From c0a3b64fe2e70c11bf6c6b62ded22ae99cb34109 Mon Sep 17 00:00:00 2001 From: samuel40791765 Date: Wed, 11 Sep 2024 00:12:10 +0000 Subject: [PATCH 1/3] add support for PEM_write_bio_PrivateKey_traditional --- crypto/pem/pem_pkey.c | 15 ++++++ crypto/pem/pem_test.cc | 102 ++++++++++++++++++++++++++++++++++++++++- include/openssl/pem.h | 7 +++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c index 9fadfbc694..59ce84d916 100644 --- a/crypto/pem/pem_pkey.c +++ b/crypto/pem/pem_pkey.c @@ -157,6 +157,7 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (char *)kstr, klen, cb, u); } +<<<<<<< HEAD EVP_PKEY *PEM_read_bio_Parameters(BIO *bio, EVP_PKEY **pkey) { if (bio == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_PASSED_NULL_PARAMETER); @@ -260,6 +261,20 @@ int PEM_write_bio_Parameters(BIO *bio, EVP_PKEY *pkey) { } } +static int i2d_PrivateKey_void(const void *key, uint8_t **out) { + return i2d_PrivateKey((const EVP_PKEY *)key, out); +} + +int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x, + const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) { + char pem_str[80]; + BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); + return PEM_ASN1_write_bio(i2d_PrivateKey_void, pem_str, bp, x, enc, kstr, + klen, cb, u); +} + EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) { BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); diff --git a/crypto/pem/pem_test.cc b/crypto/pem/pem_test.cc index 5039a494e1..f4413cf277 100644 --- a/crypto/pem/pem_test.cc +++ b/crypto/pem/pem_test.cc @@ -21,11 +21,11 @@ #include #include #include +#include #include #include "../test/test_util.h" -#include "openssl/rand.h" const char* SECRET = "test"; @@ -366,3 +366,103 @@ TEST(ParametersTest, RubyDHFile) { EXPECT_TRUE(dh); EXPECT_EQ(DH_num_bits(dh.get()), 2048u); } + +TEST(PEMTest, WriteReadTraditionalPem) { + // Test |PEM_write_bio_PrivateKey_traditional| with |EC_KEY|. + bssl::UniquePtr ec_key(EC_KEY_new()); + ASSERT_TRUE(ec_key); + bssl::UniquePtr ec_group(EC_GROUP_new_by_curve_name(NID_secp256k1)); + ASSERT_TRUE(ec_group); + ASSERT_TRUE(EC_KEY_set_group(ec_key.get(), ec_group.get())); + ASSERT_TRUE(EC_KEY_generate_key(ec_key.get())); + + bssl::UniquePtr write_bio(BIO_new(BIO_s_mem())); + bssl::UniquePtr pkey(EVP_PKEY_new()); + ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())); + EXPECT_TRUE(PEM_write_bio_PrivateKey_traditional( + write_bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr)); + + const uint8_t *content; + size_t content_len; + BIO_mem_contents(write_bio.get(), &content, &content_len); + + bssl::UniquePtr read_bio(BIO_new_mem_buf(content, content_len)); + ASSERT_TRUE(read_bio); + bssl::UniquePtr pkey_read( + PEM_read_bio_PrivateKey(read_bio.get(), nullptr, nullptr, nullptr)); + ASSERT_TRUE(pkey_read); + + EC_KEY *pkey_eckey = EVP_PKEY_get0_EC_KEY(pkey.get()); + const BIGNUM *orig_priv_key = EC_KEY_get0_private_key(ec_key.get()); + const BIGNUM *read_priv_key = EC_KEY_get0_private_key(pkey_eckey); + ASSERT_EQ(0, BN_cmp(orig_priv_key, read_priv_key)); + + // Test |PEM_write_bio_PrivateKey_traditional| with |RSA|. + bssl::UniquePtr e(BN_new()); + ASSERT_TRUE(e); + ASSERT_TRUE(BN_set_word(e.get(), RSA_F4)); + bssl::UniquePtr rsa(RSA_new()); + ASSERT_TRUE(rsa); + ASSERT_TRUE(RSA_generate_key_ex(rsa.get(), 1024, e.get(), nullptr)); + + write_bio.reset(BIO_new(BIO_s_mem())); + pkey.reset(EVP_PKEY_new()); + ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa.get())); + EXPECT_TRUE(PEM_write_bio_PrivateKey_traditional( + write_bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr)); + + BIO_mem_contents(write_bio.get(), &content, &content_len); + read_bio.reset(BIO_new_mem_buf(content, content_len)); + ASSERT_TRUE(read_bio); + pkey_read.reset( + PEM_read_bio_PrivateKey(read_bio.get(), nullptr, nullptr, nullptr)); + ASSERT_TRUE(pkey_read); + + RSA *pkey_rsa = EVP_PKEY_get0_RSA(pkey.get()); + EXPECT_EQ(0, BN_cmp(RSA_get0_d(pkey_rsa), RSA_get0_d(rsa.get()))); + EXPECT_EQ(0, BN_cmp(RSA_get0_d(pkey_rsa), RSA_get0_d(rsa.get()))); + + // Test |PEM_write_bio_PrivateKey_traditional| with |DSA|. + bssl::UniquePtr dsa(DSA_new()); + ASSERT_TRUE(dsa); + uint8_t seed[20]; + ASSERT_TRUE(RAND_bytes(seed, sizeof(seed))); + ASSERT_TRUE(DSA_generate_parameters_ex(dsa.get(), 512, seed, sizeof(seed), + nullptr, nullptr, nullptr)); + ASSERT_TRUE(DSA_generate_key(dsa.get())); + + write_bio.reset(BIO_new(BIO_s_mem())); + pkey.reset(EVP_PKEY_new()); + ASSERT_TRUE(EVP_PKEY_set1_DSA(pkey.get(), dsa.get())); + EXPECT_TRUE(PEM_write_bio_PrivateKey_traditional( + write_bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr)); + + BIO_mem_contents(write_bio.get(), &content, &content_len); + read_bio.reset(BIO_new_mem_buf(content, content_len)); + ASSERT_TRUE(read_bio); + pkey_read.reset( + PEM_read_bio_PrivateKey(read_bio.get(), nullptr, nullptr, nullptr)); + ASSERT_TRUE(pkey_read); + + DSA *pkey_dsa = EVP_PKEY_get0_DSA(pkey.get()); + EXPECT_EQ(0, + BN_cmp(DSA_get0_priv_key(pkey_dsa), DSA_get0_priv_key(dsa.get()))); + EXPECT_EQ(0, + BN_cmp(DSA_get0_priv_key(pkey_dsa), DSA_get0_priv_key(dsa.get()))); + + // Test |PEM_write_bio_PrivateKey_traditional| with |DH|. This should fail, + // since it's not supported by the API. + bssl::UniquePtr p(BN_get_rfc3526_prime_1536(nullptr)); + ASSERT_TRUE(p); + bssl::UniquePtr g(BN_new()); + ASSERT_TRUE(g); + ASSERT_TRUE(BN_set_u64(g.get(), 2)); + bssl::UniquePtr dh(DH_new()); + ASSERT_TRUE(dh); + ASSERT_TRUE(DH_set0_pqg(dh.get(), p.release(), nullptr, g.release())); + write_bio.reset(BIO_new(BIO_s_mem())); + pkey.reset(EVP_PKEY_new()); + ASSERT_TRUE(EVP_PKEY_set1_DH(pkey.get(), dh.get())); + EXPECT_FALSE(PEM_write_bio_PrivateKey_traditional( + write_bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr)); +} diff --git a/include/openssl/pem.h b/include/openssl/pem.h index e8d3363e50..922955454c 100644 --- a/include/openssl/pem.h +++ b/include/openssl/pem.h @@ -518,6 +518,13 @@ OPENSSL_EXPORT EC_GROUP *PEM_read_bio_ECPKParameters(BIO *bio, OPENSSL_EXPORT int PEM_write_bio_ECPKParameters(BIO *out, const EC_GROUP *group); +// PEM_write_bio_PrivateKey_traditional calls |PEM_ASN1_write_bio| to write +// out |x|'s private key in the "traditional" ASN1 format. Use +// |PEM_write_bio_PrivateKey| instead. +OPENSSL_EXPORT int PEM_write_bio_PrivateKey_traditional( + BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, + pem_password_cb *cb, void *u); + #ifdef __cplusplus } // extern "C" #endif From 5e7b7f751033300472cf865c5eb006c921cec196 Mon Sep 17 00:00:00 2001 From: samuel40791765 Date: Fri, 13 Sep 2024 20:36:20 +0000 Subject: [PATCH 2/3] add null check --- crypto/pem/pem_pkey.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c index 59ce84d916..366337b595 100644 --- a/crypto/pem/pem_pkey.c +++ b/crypto/pem/pem_pkey.c @@ -157,7 +157,6 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (char *)kstr, klen, cb, u); } -<<<<<<< HEAD EVP_PKEY *PEM_read_bio_Parameters(BIO *bio, EVP_PKEY **pkey) { if (bio == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_PASSED_NULL_PARAMETER); @@ -269,6 +268,11 @@ int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { + if (bp == NULL || x == NULL || x->ameth == NULL || + x->ameth->pem_str == NULL) { + OPENSSL_PUT_ERROR(PEM, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } char pem_str[80]; BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); return PEM_ASN1_write_bio(i2d_PrivateKey_void, pem_str, bp, x, enc, kstr, From ba048f14b194170c8163b24993f486d573a48703 Mon Sep 17 00:00:00 2001 From: Samuel Chiang Date: Tue, 17 Sep 2024 13:10:38 -0700 Subject: [PATCH 3/3] Update crypto/pem/pem_pkey.c Co-authored-by: Will Childs-Klein --- crypto/pem/pem_pkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c index 366337b595..796bf693c6 100644 --- a/crypto/pem/pem_pkey.c +++ b/crypto/pem/pem_pkey.c @@ -274,7 +274,7 @@ int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x, return 0; } char pem_str[80]; - BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); + BIO_snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", x->ameth->pem_str); return PEM_ASN1_write_bio(i2d_PrivateKey_void, pem_str, bp, x, enc, kstr, klen, cb, u); }