Test requireAnyPolicy being a SkipCerts value

And specifically that it also counts at the leaf, which was a bug I'd
nearly introduced. (RFC 5280 is written somewhat confusingly. The
wrap-up and prepare procedures have some duplicate processing.)

Change-Id: Iea901b96f64e12199fec426dc936bfbde16f88a4
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/56035
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/x509/test/make_policy_certs.go b/crypto/x509/test/make_policy_certs.go
index bec2ace..8d3a11d 100644
--- a/crypto/x509/test/make_policy_certs.go
+++ b/crypto/x509/test/make_policy_certs.go
@@ -22,6 +22,7 @@
 	"crypto/x509/pkix"
 	"encoding/asn1"
 	"encoding/pem"
+	"flag"
 	"math/big"
 	"os"
 	"time"
@@ -30,6 +31,8 @@
 	cbasn1 "golang.org/x/crypto/cryptobyte/asn1"
 )
 
+var resetFlag = flag.Bool("reset", false, "if set, regenerates certificates that already exist")
+
 var (
 	// https://davidben.net/oid
 	testOID1 = asn1.ObjectIdentifier([]int{1, 2, 840, 113554, 4, 1, 72585, 2, 1})
@@ -62,7 +65,17 @@
 	key      *ecdsa.PrivateKey
 }
 
-func mustGenerateCertificate(path string, subject, issuer *templateAndKey) []byte {
+func mustGenerateCertificate(path string, subject, issuer *templateAndKey) {
+	if !*resetFlag {
+		// Skip if the file already exists.
+		_, err := os.Stat(path)
+		if err == nil {
+			return
+		}
+		if !os.IsNotExist(err) {
+			panic(err)
+		}
+	}
 	cert, err := x509.CreateCertificate(rand.Reader, &subject.template, &issuer.template, &subject.key.PublicKey, issuer.key)
 	if err != nil {
 		panic(err)
@@ -76,10 +89,11 @@
 	if err != nil {
 		panic(err)
 	}
-	return cert
 }
 
 func main() {
+	flag.Parse()
+
 	notBefore, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z")
 	if err != nil {
 		panic(err)
@@ -160,14 +174,29 @@
 	intermediateDuplicate.template.PolicyIdentifiers = []asn1.ObjectIdentifier{testOID1, testOID2, testOID2}
 	mustGenerateCertificate("policy_intermediate_duplicate.pem", &intermediateDuplicate, &root)
 
-	// A version of the intermediate that sets requireExplicitPolicy without
-	// skipping certificates.
+	// Various policy constraints with requireExplicitPolicy values.
 	b := cryptobyte.NewBuilder(nil)
 	b.AddASN1(cbasn1.SEQUENCE, func(seq *cryptobyte.Builder) {
 		seq.AddASN1Int64WithTag(0, cbasn1.Tag(0).ContextSpecific())
 	})
+	requireExplicitPolicy0 := b.BytesOrPanic()
+
+	b = cryptobyte.NewBuilder(nil)
+	b.AddASN1(cbasn1.SEQUENCE, func(seq *cryptobyte.Builder) {
+		seq.AddASN1Int64WithTag(1, cbasn1.Tag(0).ContextSpecific())
+	})
+	requireExplicitPolicy1 := b.BytesOrPanic()
+
+	b = cryptobyte.NewBuilder(nil)
+	b.AddASN1(cbasn1.SEQUENCE, func(seq *cryptobyte.Builder) {
+		seq.AddASN1Int64WithTag(2, cbasn1.Tag(0).ContextSpecific())
+	})
+	requireExplicitPolicy2 := b.BytesOrPanic()
+
+	// A version of the intermediate that sets requireExplicitPolicy, skipping
+	// zero certificates.
 	intermediateRequire := intermediate
-	intermediateRequire.template.ExtraExtensions = []pkix.Extension{{Id: policyConstraintsOID, Value: b.BytesOrPanic()}}
+	intermediateRequire.template.ExtraExtensions = []pkix.Extension{{Id: policyConstraintsOID, Value: requireExplicitPolicy0}}
 	mustGenerateCertificate("policy_intermediate_require.pem", &intermediateRequire, &root)
 
 	// Same as above, but there are no policies on the intermediate.
@@ -183,6 +212,18 @@
 	intermediateAny.template.PolicyIdentifiers = []asn1.ObjectIdentifier{anyPolicyOID}
 	mustGenerateCertificate("policy_intermediate_any.pem", &intermediateAny, &root)
 
+	// Other requireExplicitPolicy values, on the leaf and intermediate.
+	intermediateRequire = intermediate
+	intermediateRequire.template.ExtraExtensions = []pkix.Extension{{Id: policyConstraintsOID, Value: requireExplicitPolicy1}}
+	mustGenerateCertificate("policy_intermediate_require1.pem", &intermediateRequire, &root)
+	intermediateRequire.template.ExtraExtensions = []pkix.Extension{{Id: policyConstraintsOID, Value: requireExplicitPolicy2}}
+	mustGenerateCertificate("policy_intermediate_require2.pem", &intermediateRequire, &root)
+	leafRequire := leaf
+	leafRequire.template.ExtraExtensions = []pkix.Extension{{Id: policyConstraintsOID, Value: requireExplicitPolicy0}}
+	mustGenerateCertificate("policy_leaf_require.pem", &leafRequire, &intermediate)
+	leafRequire.template.ExtraExtensions = []pkix.Extension{{Id: policyConstraintsOID, Value: requireExplicitPolicy1}}
+	mustGenerateCertificate("policy_leaf_require1.pem", &leafRequire, &intermediate)
+
 	leafAny := leaf
 	leafAny.template.PolicyIdentifiers = []asn1.ObjectIdentifier{anyPolicyOID}
 	mustGenerateCertificate("policy_leaf_any.pem", &leafAny, &intermediate)
diff --git a/crypto/x509/test/policy_intermediate_require1.pem b/crypto/x509/test/policy_intermediate_require1.pem
new file mode 100644
index 0000000..7087404
--- /dev/null
+++ b/crypto/x509/test/policy_intermediate_require1.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBujCCAV+gAwIBAgIBAjAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg
+Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowHjEcMBoGA1UE
+AxMTUG9saWN5IEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
+BOI6fKiM3jFLkLyAn88cvlw4SwxuygRjopP3FFBKHyUQvh3VVvfqSpSCSmp50Qia
+jQ6Dg7CTpVZVVH+bguT7JTCjgZMwgZAwDgYDVR0PAQH/BAQDAgIEMBMGA1UdJQQM
+MAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJDS9/4O7qhr
+CIRhwsXrPVBagG2uMCsGA1UdIAQkMCIwDwYNKoZIhvcSBAGEtwkCATAPBg0qhkiG
+9xIEAYS3CQICMAwGA1UdJAQFMAOAAQEwCgYIKoZIzj0EAwIDSQAwRgIhAIAwvhHB
+GQDN5YXlidd+n3OT/SqoeXfp7RiEonBnCkW4AiEA+iFc47EOBchHb+Gy0gg8F9Po
+RnlpoulWDfbDwx9r4lc=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/policy_intermediate_require2.pem b/crypto/x509/test/policy_intermediate_require2.pem
new file mode 100644
index 0000000..350f419
--- /dev/null
+++ b/crypto/x509/test/policy_intermediate_require2.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBuTCCAV+gAwIBAgIBAjAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg
+Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowHjEcMBoGA1UE
+AxMTUG9saWN5IEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
+BOI6fKiM3jFLkLyAn88cvlw4SwxuygRjopP3FFBKHyUQvh3VVvfqSpSCSmp50Qia
+jQ6Dg7CTpVZVVH+bguT7JTCjgZMwgZAwDgYDVR0PAQH/BAQDAgIEMBMGA1UdJQQM
+MAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJDS9/4O7qhr
+CIRhwsXrPVBagG2uMCsGA1UdIAQkMCIwDwYNKoZIhvcSBAGEtwkCATAPBg0qhkiG
+9xIEAYS3CQICMAwGA1UdJAQFMAOAAQIwCgYIKoZIzj0EAwIDSAAwRQIgOpliSKKA
++wy/auQnKKl+wwtn/hGw6eZXgIOtFgDmyMYCIQC84zoJL87AE64gsrdX4XSHq6lb
+WhZQp9ZnDaNu88SQLQ==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/policy_leaf_require.pem b/crypto/x509/test/policy_leaf_require.pem
new file mode 100644
index 0000000..169b844
--- /dev/null
+++ b/crypto/x509/test/policy_leaf_require.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBuDCCAV2gAwIBAgIBAzAKBggqhkjOPQQDAjAeMRwwGgYDVQQDExNQb2xpY3kg
+SW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjAa
+MRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZREvmcBCJBjVIREacR
+qI0umhzR2V5NLzBBP9yPD/A+Ch5Xo4GNMIGKMA4GA1UdDwEB/wQEAwICBDATBgNV
+HSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGCD3d3dy5l
+eGFtcGxlLmNvbTArBgNVHSAEJDAiMA8GDSqGSIb3EgQBhLcJAgEwDwYNKoZIhvcS
+BAGEtwkCAjAMBgNVHSQEBTADgAEAMAoGCCqGSM49BAMCA0kAMEYCIQDrNQPi/mdK
+l7Nd/YmMXWYTHJBWWin1zA64Ohkd7z4jGgIhAJpw/umk5MxS1MwSi+YTkkcSQKpl
+YROQH6+T53DauoW6
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/policy_leaf_require1.pem b/crypto/x509/test/policy_leaf_require1.pem
new file mode 100644
index 0000000..261ef95
--- /dev/null
+++ b/crypto/x509/test/policy_leaf_require1.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBuDCCAV2gAwIBAgIBAzAKBggqhkjOPQQDAjAeMRwwGgYDVQQDExNQb2xpY3kg
+SW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjAa
+MRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZREvmcBCJBjVIREacR
+qI0umhzR2V5NLzBBP9yPD/A+Ch5Xo4GNMIGKMA4GA1UdDwEB/wQEAwICBDATBgNV
+HSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGCD3d3dy5l
+eGFtcGxlLmNvbTArBgNVHSAEJDAiMA8GDSqGSIb3EgQBhLcJAgEwDwYNKoZIhvcS
+BAGEtwkCAjAMBgNVHSQEBTADgAEBMAoGCCqGSM49BAMCA0kAMEYCIQCtXENGJrKv
+IOeLHO/3Nu/SMRXc69Vb3q+4b/uHBFbuqwIhAK22Wfh/ZIHKu3FwbjL+sN0Z39pf
+Dsak6fp1y4tqNuvK
+-----END CERTIFICATE-----
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index a1005d7..eb26611 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -5143,6 +5143,14 @@
   bssl::UniquePtr<X509> intermediate_require(CertFromPEM(
       GetTestData("crypto/x509/test/policy_intermediate_require.pem").c_str()));
   ASSERT_TRUE(intermediate_require);
+  bssl::UniquePtr<X509> intermediate_require1(CertFromPEM(
+      GetTestData("crypto/x509/test/policy_intermediate_require1.pem")
+          .c_str()));
+  ASSERT_TRUE(intermediate_require1);
+  bssl::UniquePtr<X509> intermediate_require2(CertFromPEM(
+      GetTestData("crypto/x509/test/policy_intermediate_require2.pem")
+          .c_str()));
+  ASSERT_TRUE(intermediate_require2);
   bssl::UniquePtr<X509> intermediate_require_duplicate(CertFromPEM(
       GetTestData("crypto/x509/test/policy_intermediate_require_duplicate.pem")
           .c_str()));
@@ -5179,6 +5187,12 @@
   bssl::UniquePtr<X509> leaf_oid5(CertFromPEM(
       GetTestData("crypto/x509/test/policy_leaf_oid5.pem").c_str()));
   ASSERT_TRUE(leaf_oid5);
+  bssl::UniquePtr<X509> leaf_require(CertFromPEM(
+      GetTestData("crypto/x509/test/policy_leaf_require.pem").c_str()));
+  ASSERT_TRUE(leaf_require);
+  bssl::UniquePtr<X509> leaf_require1(CertFromPEM(
+      GetTestData("crypto/x509/test/policy_leaf_require1.pem").c_str()));
+  ASSERT_TRUE(leaf_require1);
 
   // By default, OpenSSL does not check policies, so even syntax errors in the
   // certificatePolicies extension go unnoticed. (This is probably not
@@ -5286,6 +5300,57 @@
                      set_policies(param, {oid3.get()});
                    }));
 
+  // A leaf can also set requireExplicitPolicy.
+  EXPECT_EQ(X509_V_OK, Verify(leaf_require.get(), {root.get()},
+                              {intermediate.get()}, /*crls=*/{},
+                              /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+                                set_policies(param, {oid1.get()});
+                              }));
+  EXPECT_EQ(X509_V_ERR_NO_EXPLICIT_POLICY,
+            Verify(leaf_require.get(), {root.get()}, {intermediate.get()},
+                   /*crls=*/{},
+                   /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+                     set_policies(param, {oid3.get()});
+                   }));
+
+  // requireExplicitPolicy is a count of certificates to skip. If the value is
+  // not zero by the end of the chain, it doesn't count.
+  EXPECT_EQ(X509_V_ERR_NO_EXPLICIT_POLICY,
+            Verify(leaf.get(), {root.get()}, {intermediate_require1.get()},
+                   /*crls=*/{},
+                   /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+                     set_policies(param, {oid3.get()});
+                   }));
+  EXPECT_EQ(X509_V_OK,
+            Verify(leaf.get(), {root.get()}, {intermediate_require2.get()},
+                   /*crls=*/{},
+                   /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+                     set_policies(param, {oid3.get()});
+                   }));
+  EXPECT_EQ(X509_V_OK,
+            Verify(leaf_require1.get(), {root.get()}, {intermediate.get()},
+                   /*crls=*/{},
+                   /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+                     set_policies(param, {oid3.get()});
+                   }));
+
+  // If multiple certificates specify the constraint, the more constrained value
+  // wins.
+  EXPECT_EQ(
+      X509_V_ERR_NO_EXPLICIT_POLICY,
+      Verify(leaf_require1.get(), {root.get()}, {intermediate_require1.get()},
+             /*crls=*/{},
+             /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+               set_policies(param, {oid3.get()});
+             }));
+  EXPECT_EQ(
+      X509_V_ERR_NO_EXPLICIT_POLICY,
+      Verify(leaf_require.get(), {root.get()}, {intermediate_require2.get()},
+             /*crls=*/{},
+             /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
+               set_policies(param, {oid3.get()});
+             }));
+
   // An intermediate that requires an explicit policy, but then specifies no
   // policies should fail verification as a result.
   EXPECT_EQ(X509_V_ERR_NO_EXPLICIT_POLICY,
@@ -5306,16 +5371,18 @@
 
   // The leaf asserts anyPolicy, but the intermediate does not. The resulting
   // valid policies are the intersection.
-  EXPECT_EQ(X509_V_OK,
-            Verify(leaf_any.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
-                   X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
-                     set_policies(param, {oid1.get()});
-                   }));
-  EXPECT_EQ(X509_V_ERR_NO_EXPLICIT_POLICY,
-            Verify(leaf_any.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
-                   X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
-                     set_policies(param, {oid3.get()});
-                   }));
+  EXPECT_EQ(
+      X509_V_OK,
+      Verify(leaf_any.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+             X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+               set_policies(param, {oid1.get()});
+             }));
+  EXPECT_EQ(
+      X509_V_ERR_NO_EXPLICIT_POLICY,
+      Verify(leaf_any.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+             X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+               set_policies(param, {oid3.get()});
+             }));
 
   // The intermediate asserts anyPolicy, but the leaf does not. The resulting
   // valid policies are the intersection.
diff --git a/sources.cmake b/sources.cmake
index c35299e..881cb15 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -111,16 +111,17 @@
   crypto/x509/test/many_names1.pem
   crypto/x509/test/many_names2.pem
   crypto/x509/test/many_names3.pem
-  crypto/x509/test/policy_root.pem
   crypto/x509/test/policy_intermediate_any.pem
   crypto/x509/test/policy_intermediate_duplicate.pem
   crypto/x509/test/policy_intermediate_invalid.pem
-  crypto/x509/test/policy_intermediate_mapped.pem
   crypto/x509/test/policy_intermediate_mapped_any.pem
   crypto/x509/test/policy_intermediate_mapped_oid3.pem
-  crypto/x509/test/policy_intermediate_require.pem
+  crypto/x509/test/policy_intermediate_mapped.pem
   crypto/x509/test/policy_intermediate_require_duplicate.pem
   crypto/x509/test/policy_intermediate_require_no_policies.pem
+  crypto/x509/test/policy_intermediate_require.pem
+  crypto/x509/test/policy_intermediate_require1.pem
+  crypto/x509/test/policy_intermediate_require2.pem
   crypto/x509/test/policy_intermediate.pem
   crypto/x509/test/policy_leaf_any.pem
   crypto/x509/test/policy_leaf_duplicate.pem
@@ -130,7 +131,10 @@
   crypto/x509/test/policy_leaf_oid3.pem
   crypto/x509/test/policy_leaf_oid4.pem
   crypto/x509/test/policy_leaf_oid5.pem
+  crypto/x509/test/policy_leaf_require.pem
+  crypto/x509/test/policy_leaf_require1.pem
   crypto/x509/test/policy_leaf.pem
+  crypto/x509/test/policy_root.pem
   crypto/x509/test/pss_sha1_explicit.pem
   crypto/x509/test/pss_sha1_mgf1_syntax_error.pem
   crypto/x509/test/pss_sha1.pem