Add some tests to exercise v2i_AUTHORITY_KEYID This is a separate list of tests just because we don't have C++20 designated initializers yet and it's a pain to have /*issuer_cert=*/nullptr in every test. Change-Id: Ic4397fa0cce6f1eed13ca6bfea051c4d652eaff3 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/96707 Reviewed-by: Adam Langley <agl@google.com> Auto-Submit: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 7948a45..5a8e8c9 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc
@@ -8062,6 +8062,111 @@ EXPECT_EQ(Bytes(t.expected), Bytes(der, len)); } } + + UniquePtr<EVP_PKEY> issuer_key = PrivateKeyFromPEM(kP256Key); + ASSERT_TRUE(issuer_key); + + // Issuer cert without SKID. + UniquePtr<X509> issuer_no_skid = + MakeTestCert("Issuer", "Issuer", issuer_key.get(), /*is_ca=*/true); + ASSERT_TRUE(issuer_no_skid); + ASSERT_TRUE(X509_sign(issuer_no_skid.get(), issuer_key.get(), EVP_sha256())); + + // Issuer cert with SKID. + UniquePtr<X509> issuer_with_skid = + MakeTestCert("Issuer", "Issuer", issuer_key.get(), /*is_ca=*/true); + ASSERT_TRUE(issuer_with_skid); + static const uint8_t kSKID[] = {1, 2, 3, 4, 5, 6, 7, 8}; + ASSERT_TRUE(AddSubjectKeyIdentifier(issuer_with_skid.get(), kSKID)); + ASSERT_TRUE( + X509_sign(issuer_with_skid.get(), issuer_key.get(), EVP_sha256())); + + const struct { + const char *name; + const char *value; + // issuer_cert is the issuer certificate that must be used with the + // extension. + const X509 *issuer_cert; + // expected is the resulting extension, encoded in DER, or the empty string + // if an error is expected. + std::vector<uint8_t> expected; + } kTestsWithIssuer[] = { + // The AKID extension is a series of options. The "keyid" option picks up + // the issuer's SKID, but only if it is present. + {"authorityKeyIdentifier", + "keyid", + issuer_no_skid.get(), + {0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x02, 0x30, 0x00}}, + {"authorityKeyIdentifier", + "keyid", + issuer_with_skid.get(), + {0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x0c, 0x30, 0x0a, + 0x80, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, + + // keyid:always makes it an error when there is no issuer SKID. + {"authorityKeyIdentifier", "keyid:always", issuer_no_skid.get(), {}}, + {"authorityKeyIdentifier", + "keyid:always", + issuer_with_skid.get(), + {0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x0c, 0x30, 0x0a, + 0x80, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, + + // The issuer option picks up the issuer's issuer and serial. + {"authorityKeyIdentifier", + "issuer", + issuer_no_skid.get(), + {0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x1c, 0x30, + 0x1a, 0xa1, 0x15, 0xa4, 0x13, 0x30, 0x11, 0x31, 0x0f, 0x30, + 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x82, 0x01, 0x2a}}, + + // If both options are enabled, the issuer option only applies if the + // keyid option missed. + {"authorityKeyIdentifier", + "keyid,issuer", + issuer_no_skid.get(), + {0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x1c, 0x30, + 0x1a, 0xa1, 0x15, 0xa4, 0x13, 0x30, 0x11, 0x31, 0x0f, 0x30, + 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x82, 0x01, 0x2a}}, + {"authorityKeyIdentifier", + "keyid,issuer", + issuer_with_skid.get(), + {0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x0c, 0x30, 0x0a, + 0x80, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, + + // Unless issuer:always is set, in which case both are included. + {"authorityKeyIdentifier", + "keyid,issuer:always", + issuer_with_skid.get(), + {0x30, 0x2d, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x26, 0x30, 0x24, 0x80, + 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xa1, 0x15, 0xa4, + 0x13, 0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x06, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x82, 0x01, 0x2a}}, + + // Invalid options are rejected. + {"authorityKeyIdentifier", "keyid,badopt", issuer_with_skid.get(), {}}, + }; + for (const auto &t : kTestsWithIssuer) { + SCOPED_TRACE(t.name); + SCOPED_TRACE(t.value); + + X509V3_CTX ctx; + X509V3_set_ctx(&ctx, t.issuer_cert, nullptr, nullptr, nullptr, 0); + UniquePtr<X509_EXTENSION> ext( + X509V3_EXT_nconf(nullptr, &ctx, t.name, t.value)); + if (t.expected.empty()) { + EXPECT_FALSE(ext); + ERR_clear_error(); + } else { + ASSERT_TRUE(ext); + uint8_t *der = nullptr; + int len = i2d_X509_EXTENSION(ext.get(), &der); + ASSERT_GE(len, 0); + UniquePtr<uint8_t> free_der(der); + EXPECT_EQ(Bytes(t.expected), Bytes(der, len)); + } + } } TEST(X509Test, AddUnserializableExtension) {