diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 9498c9aa3a..d92d1a1ac7 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -7583,3 +7583,43 @@ TEST(X509Test, PublicKeyCache) { key2.reset(X509_PUBKEY_get(pub)); EXPECT_FALSE(key2); } + +TEST(X509Test, SPKIPrint) { + bssl::UniquePtr bio(BIO_new(BIO_s_mem())); + ASSERT_TRUE(bio); + bssl::UniquePtr spki(NETSCAPE_SPKI_new()); + ASSERT_TRUE(spki); + + bssl::UniquePtr key = PrivateKeyFromPEM(kP256Key); + EXPECT_TRUE(NETSCAPE_SPKI_set_pubkey(spki.get(), key.get())); + EXPECT_TRUE(NETSCAPE_SPKI_sign(spki.get(), key.get(), EVP_sha256())); + + std::string challenge = "challenge string"; + ASSERT_TRUE(ASN1_STRING_set(spki.get()->spkac->challenge, challenge.data(), + challenge.size())); + + EXPECT_TRUE(NETSCAPE_SPKI_print(bio.get(), spki.get())); + + // The contents of the signature is printed last but it's randomized, + // so we only check the expected output before that. + static const char expected_certificate_string[] = R"(Netscape SPKI: + Public Key Algorithm: id-ecPublicKey + Public-Key: (P-256) + pub: + 04:e6:2b:69:e2:bf:65:9f:97:be:2f:1e:0d:94:8a: + 4c:d5:97:6b:b7:a9:1e:0d:46:fb:dd:a9:a9:1e:9d: + dc:ba:5a:01:e7:d6:97:a8:0a:18:f9:c3:c4:a3:1e: + 56:e2:7c:83:48:db:16:1a:1c:f5:1d:7e:f1:94:2d: + 4b:cf:72:22:c1 + Challenge String: challenge string + Signature Algorithm: ecdsa-with-SHA256 + )"; + + const uint8_t *data; + size_t data_len; + ASSERT_TRUE(BIO_mem_contents(bio.get(), &data, &data_len)); + ASSERT_GT(data_len, strlen(expected_certificate_string)); + std::string print(reinterpret_cast(data), + strlen(expected_certificate_string)); + EXPECT_EQ(print, expected_certificate_string); +} diff --git a/crypto/x509/x509spki.c b/crypto/x509/x509spki.c index 611a05f443..65021712e5 100644 --- a/crypto/x509/x509spki.c +++ b/crypto/x509/x509spki.c @@ -60,6 +60,7 @@ #include #include #include +#include "internal.h" int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey) { if ((x == NULL) || (x->spkac == NULL)) { @@ -131,3 +132,47 @@ char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki) { OPENSSL_free(der_spki); return b64_str; } + +int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki) { + if (out == NULL || spki == NULL || spki->spkac == NULL || + spki->spkac->pubkey == NULL || spki->sig_algor == NULL || + spki->sig_algor->algorithm == NULL || spki->signature == NULL || + spki->signature->data == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + BIO_printf(out, "Netscape SPKI:\n"); + + // Print out public key algorithm and contents. + ASN1_OBJECT *spkioid; + X509_PUBKEY_get0_param(&spkioid, NULL, NULL, NULL, spki->spkac->pubkey); + int spkioid_nid = OBJ_obj2nid(spkioid); + BIO_printf(out, " Public Key Algorithm: %s\n", + (spkioid_nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(spkioid_nid)); + EVP_PKEY *pkey = X509_PUBKEY_get0(spki->spkac->pubkey); + if (pkey == NULL) { + BIO_printf(out, " Unable to load public key\n"); + } else { + EVP_PKEY_print_public(out, pkey, 4, NULL); + } + + ASN1_IA5STRING *chal = spki->spkac->challenge; + if (chal != NULL && chal->length != 0) { + BIO_printf(out, " Challenge String: %.*s\n", chal->length, chal->data); + } + + // Print out signature algorithm and contents. + BIO_printf(out, " Signature Algorithm: %s", + (OBJ_obj2nid(spki->sig_algor->algorithm) == NID_undef) + ? "UNKNOWN" + : OBJ_nid2ln(OBJ_obj2nid(spki->sig_algor->algorithm))); + for (int i = 0; i < spki->signature->length; i++) { + if ((i % 18) == 0) { + BIO_printf(out, "\n "); + } + BIO_printf(out, "%02x%s", (unsigned char)spki->signature->data[i], + ((i + 1) == spki->signature->length) ? "" : ":"); + } + BIO_write(out, "\n", 1); + return 1; +} diff --git a/include/openssl/x509.h b/include/openssl/x509.h index accb45c8b3..a27c6bc39d 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -2345,6 +2345,9 @@ OPENSSL_EXPORT NETSCAPE_SPKAC *d2i_NETSCAPE_SPKAC(NETSCAPE_SPKAC **out, OPENSSL_EXPORT int i2d_NETSCAPE_SPKAC(const NETSCAPE_SPKAC *spkac, uint8_t **outp); +// NETSCAPE_SPKI_print prints out the contents of |spki| to |out|. +OPENSSL_EXPORT int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki); + // RSASSA-PSS Parameters. //