diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c index a230801de3..77a24072c1 100644 --- a/crypto/dsa/dsa.c +++ b/crypto/dsa/dsa.c @@ -61,11 +61,13 @@ #include +#include #include #include #include #include #include +#include #include #include #include @@ -125,6 +127,28 @@ void DSA_free(DSA *dsa) { OPENSSL_free(dsa); } +int DSA_print(BIO *bio, const DSA *dsa, int indent) { + EVP_PKEY *pkey = EVP_PKEY_new(); + int ret = pkey != NULL && + EVP_PKEY_set1_DSA(pkey, (DSA *)dsa) && + EVP_PKEY_print_private(bio, pkey, indent, NULL); + EVP_PKEY_free(pkey); + return ret; +} + + +int DSA_print_fp(FILE *fp, const DSA *dsa, int indent) { + BIO *bio = BIO_new(BIO_s_file()); + if (bio == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BUF_LIB); + return 0; + } + BIO_set_fp(bio, fp, BIO_NOCLOSE); + int ret = DSA_print(bio, dsa, indent); + BIO_free(bio); + return ret; +} + int DSA_up_ref(DSA *dsa) { CRYPTO_refcount_inc(&dsa->references); return 1; diff --git a/crypto/dsa/dsa_test.cc b/crypto/dsa/dsa_test.cc index 22e9e13bbf..5d0847670f 100644 --- a/crypto/dsa/dsa_test.cc +++ b/crypto/dsa/dsa_test.cc @@ -416,3 +416,56 @@ s2lmkAIcLIFUDFrbC2nViaB5ATM9ARKk6F2QwnCfGCyZ6A== EXPECT_EQ(1, DSA_verify(0, fips_digest, sizeof(fips_digest), sig.data(), sig.size(), dsa.get())); } + +TEST(DSATest, DSAPrint) { + bssl::UniquePtr dsa = GetFIPSDSA(); + ASSERT_TRUE(dsa); + bssl::UniquePtr bio(BIO_new(BIO_s_mem())); + + DSA_print(bio.get(), dsa.get(), 4); + const uint8_t *data; + size_t len; + BIO_mem_contents(bio.get(), &data, &len); + + const char *expected = "" + " Private-Key: (512 bit)\n" + " priv:\n" + " 20:70:b3:22:3d:ba:37:2f:de:1c:0f:fc:7b:2e:3b:\n" + " 49:8b:26:06:14\n" + " pub:\n" + " 19:13:18:71:d7:5b:16:12:a8:19:f2:9d:78:d1:b0:\n" + " d7:34:6f:7a:a7:7b:b6:2a:85:9b:fd:6c:56:75:da:\n" + " 9d:21:2d:3a:36:ef:16:72:ef:66:0b:8c:7c:25:5c:\n" + " c0:ec:74:85:8f:ba:33:f4:4c:06:69:96:30:a7:6b:\n" + " 03:0e:e3:33\n" + " P:\n" + " 00:8d:f2:a4:94:49:22:76:aa:3d:25:75:9b:b0:68:\n" + " 69:cb:ea:c0:d8:3a:fb:8d:0c:f7:cb:b8:32:4f:0d:\n" + " 78:82:e5:d0:76:2f:c5:b7:21:0e:af:c2:e9:ad:ac:\n" + " 32:ab:7a:ac:49:69:3d:fb:f8:37:24:c2:ec:07:36:\n" + " ee:31:c8:02:91\n" + " Q:\n" + " 00:c7:73:21:8c:73:7e:c8:ee:99:3b:4f:2d:ed:30:\n" + " f4:8e:da:ce:91:5f\n" + " G:\n" + " 62:6d:02:78:39:ea:0a:13:41:31:63:a5:5b:4c:b5:\n" + " 00:29:9d:55:22:95:6c:ef:cb:3b:ff:10:f3:99:ce:\n" + " 2c:2e:71:cb:9d:e5:fa:24:ba:bf:58:e5:b7:95:21:\n" + " 92:5c:9c:c4:2e:9f:6f:46:4b:08:8c:c5:72:af:53:\n" + " e6:d7:88:02\n"; + ASSERT_EQ(Bytes(expected), Bytes(data, len)); + +#if !defined(OPENSSL_ANDROID) + // On Android, when running from an APK, |tmpfile| does not work. See + // b/36991167#comment8. + FILE *tmp = tmpfile(); + ASSERT_TRUE(DSA_print_fp(tmp, dsa.get(), 4)); + fseek(tmp, 0, SEEK_END); + long fileSize = ftell(tmp); + rewind(tmp); + std::unique_ptr buf(new uint8_t[fileSize]); + size_t bytesRead = fread(buf.get(), 1, fileSize, tmp); + ASSERT_EQ(bytesRead, (size_t)fileSize); + ASSERT_EQ(Bytes(expected), Bytes(buf.get(), fileSize)); +#endif +} diff --git a/crypto/rsa_extra/rsa_print.c b/crypto/rsa_extra/rsa_print.c index 71970b8ea9..ee4b127871 100644 --- a/crypto/rsa_extra/rsa_print.c +++ b/crypto/rsa_extra/rsa_print.c @@ -9,6 +9,8 @@ #include +#include +#include #include @@ -20,3 +22,15 @@ int RSA_print(BIO *bio, const RSA *rsa, int indent) { EVP_PKEY_free(pkey); return ret; } + +int RSA_print_fp(FILE *fp, const RSA *rsa, int indent) { + BIO *bio = BIO_new(BIO_s_file()); + if (bio == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BUF_LIB); + return 0; + } + BIO_set_fp(bio, fp, BIO_NOCLOSE); + int ret = RSA_print(bio, rsa, indent); + BIO_free(bio); + return ret; +} diff --git a/crypto/rsa_extra/rsa_test.cc b/crypto/rsa_extra/rsa_test.cc index e0f989f1da..7bae4c3530 100644 --- a/crypto/rsa_extra/rsa_test.cc +++ b/crypto/rsa_extra/rsa_test.cc @@ -62,6 +62,7 @@ #include #include +#include #include #include #include @@ -1392,6 +1393,70 @@ TEST(RSATest, OverwriteKey) { check_rsa_compatible(/*enc=*/key2.get(), /*dec=*/key1.get())); } +TEST(RSATest, PrintBio) { + bssl::UniquePtr rsa( + RSA_private_key_from_bytes(kKey1, sizeof(kKey1) - 1)); + ASSERT_TRUE(rsa); + bssl::UniquePtr bio(BIO_new(BIO_s_mem())); + + RSA_print(bio.get(), rsa.get(), 4); + const uint8_t *data; + size_t len; + BIO_mem_contents(bio.get(), &data, &len); + + const char *expected = "" + " Private-Key: (512 bit)\n" + " modulus:\n" + " 00:aa:36:ab:ce:88:ac:fd:ff:55:52:3c:7f:c4:52:\n" + " 3f:90:ef:a0:0d:f3:77:4a:25:9f:2e:62:b4:c5:d9:\n" + " 9c:b5:ad:b3:00:a0:28:5e:53:01:93:0e:0c:70:fb:\n" + " 68:76:93:9c:e6:16:ce:62:4a:11:e0:08:6d:34:1e:\n" + " bc:ac:a0:a1:f5\n" + " publicExponent: 17 (0x11)\n" + " privateExponent:\n" + " 0a:03:37:48:62:64:87:69:5f:5f:30:bc:38:b9:8b:\n" + " 44:c2:cd:2d:ff:43:40:98:cd:20:d8:a1:38:d0:90:\n" + " bf:64:79:7c:3f:a7:a2:cd:cb:3c:d1:e0:bd:ba:26:\n" + " 54:b4:f9:df:8e:8a:e5:9d:73:3d:9f:33:b3:01:62:\n" + " 4a:fd:1d:51\n" + " prime1:\n" + " 00:d8:40:b4:16:66:b4:2e:92:ea:0d:a3:b4:32:04:\n" + " b5:cf:ce:33:52:52:4d:04:16:a5:a4:41:e7:00:af:\n" + " 46:12:0d\n" + " prime2:\n" + " 00:c9:7f:b1:f0:27:f4:53:f6:34:12:33:ea:aa:d1:\n" + " d9:35:3f:6c:42:d0:88:66:b1:d0:5a:0f:20:35:02:\n" + " 8b:9d:89\n" + " exponent1:\n" + " 59:0b:95:72:a2:c2:a9:c4:06:05:9d:c2:ab:2f:1d:\n" + " af:eb:7e:8b:4f:10:a7:54:9e:8e:ed:f5:b4:fc:e0:\n" + " 9e:05\n" + " exponent2:\n" + " 00:8e:3c:05:21:fe:15:e0:ea:06:a3:6f:f0:f1:0c:\n" + " 99:52:c3:5b:7a:75:14:fd:32:38:b8:0a:ad:52:98:\n" + " 62:8d:51\n" + " coefficient:\n" + " 36:3f:f7:18:9d:a8:e9:0b:1d:34:1f:71:d0:9b:76:\n" + " a8:a9:43:e1:1d:10:b2:4d:24:9f:2d:ea:fe:f8:0c:\n" + " 18:26\n"; + + ASSERT_EQ(Bytes(expected), Bytes(data, len)); + +#if !defined(OPENSSL_ANDROID) + // On Android, when running from an APK, |tmpfile| does not work. See + // b/36991167#comment8. + FILE *tmp = tmpfile(); + ASSERT_TRUE(RSA_print_fp(tmp, rsa.get(), 4)); + fseek(tmp, 0, SEEK_END); + long fileSize = ftell(tmp); + rewind(tmp); + std::unique_ptr buf(new uint8_t[fileSize]); + size_t bytesRead = fread(buf.get(), 1, fileSize, tmp); + ASSERT_EQ(bytesRead, (size_t)fileSize); + ASSERT_EQ(Bytes(expected), Bytes(buf.get(), fileSize)); +#endif +} + #if !defined(BORINGSSL_SHARED_LIBRARY) TEST(RSATest, SqrtTwo) { bssl::UniquePtr sqrt(BN_new()), pow2(BN_new()); diff --git a/include/openssl/dsa.h b/include/openssl/dsa.h index 0dc014e66d..ae40eafc01 100644 --- a/include/openssl/dsa.h +++ b/include/openssl/dsa.h @@ -61,8 +61,10 @@ #define OPENSSL_HEADER_DSA_H #include +#include #include +#include #if defined(__cplusplus) extern "C" { @@ -89,6 +91,13 @@ OPENSSL_EXPORT void DSA_free(DSA *dsa); // DSA_up_ref increments the reference count of |dsa| and returns one. OPENSSL_EXPORT int DSA_up_ref(DSA *dsa); +// DSA_print prints a textual representation of |dsa| to |bio|. It returns one +// on success or zero otherwise. +OPENSSL_EXPORT int DSA_print(BIO *bio, const DSA *dsa, int indent); + +// DSA_print_fp prints a textual representation of |dsa| to |fp|. It returns one +// on success or zero otherwise. +OPENSSL_EXPORT int DSA_print_fp(FILE *fp, const DSA *dsa, int indent); // Properties. diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index 56e51c89a8..9b1ffb29e2 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -58,10 +58,12 @@ #define OPENSSL_HEADER_RSA_H #include +#include #include #include #include +#include #if defined(__cplusplus) extern "C" { @@ -694,6 +696,10 @@ OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP(uint8_t *to, size_t to_len, // on success or zero otherwise. OPENSSL_EXPORT int RSA_print(BIO *bio, const RSA *rsa, int indent); +// RSA_print_fp prints a textual representation of |rsa| to |fp|. It returns one +// on success or zero otherwise. +OPENSSL_EXPORT int RSA_print_fp(FILE *fp, const RSA *rsa, int indent); + // RSA_get0_pss_params returns NULL. In OpenSSL, this function retries RSA-PSS // parameters associated with |RSA| objects, but BoringSSL does not support // the id-RSASSA-PSS key encoding.