Skip to content

Commit

Permalink
add support for PEM_write_bio_PrivateKey_traditional
Browse files Browse the repository at this point in the history
  • Loading branch information
samuel40791765 committed Sep 11, 2024
1 parent 51d9a8d commit 98b3b46
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 0 deletions.
15 changes: 15 additions & 0 deletions crypto/pem/pem_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#include <openssl/pkcs8.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include "../fipsmodule/evp/internal.h"

EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
void *u) {
Expand Down Expand Up @@ -156,6 +157,20 @@ 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);
}

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);
Expand Down
101 changes: 101 additions & 0 deletions crypto/pem/pem_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@


#include "../test/test_util.h"
#include "openssl/rand.h"

const char* SECRET = "test";

Expand Down Expand Up @@ -265,3 +266,103 @@ TEST(PEMTest, WriteReadECPKPem) {
ASSERT_TRUE(read_group);
ASSERT_EQ(EC_GROUP_cmp(EC_group_p256(), read_group.get(), nullptr), 0);
}

TEST(PEMTest, WriteReadTraditionalPem) {
// Test |PEM_write_bio_PrivateKey_traditional| with |EC_KEY|.
bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new());
ASSERT_TRUE(ec_key);
bssl::UniquePtr<EC_GROUP> 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<BIO> write_bio(BIO_new(BIO_s_mem()));
bssl::UniquePtr<EVP_PKEY> 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<BIO> read_bio(BIO_new_mem_buf(content, content_len));
ASSERT_TRUE(read_bio);
bssl::UniquePtr<EVP_PKEY> 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<BIGNUM> e(BN_new());
ASSERT_TRUE(e);
ASSERT_TRUE(BN_set_word(e.get(), RSA_F4));
bssl::UniquePtr<RSA> 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(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_traditionalrs| with |DH|. This should fail,
// since it's not supported by the API.
bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_1536(nullptr));
ASSERT_TRUE(p);
bssl::UniquePtr<BIGNUM> g(BN_new());
ASSERT_TRUE(g);
ASSERT_TRUE(BN_set_u64(g.get(), 2));
bssl::UniquePtr<DH> 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));
}
7 changes: 7 additions & 0 deletions include/openssl/pem.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,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
Expand Down

0 comments on commit 98b3b46

Please sign in to comment.