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