From 96e966e779a4aca1f28f759e25587181b03c869a Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Sun, 26 Apr 2026 16:52:02 +0300 Subject: [PATCH 1/7] Feat: Allow for a wrapper for pem write privatekey & PUBKEY --- src/pk.c | 119 ++++++++++++++++++++++++++++++++++++++ tests/api/test_ossl_pem.c | 98 +++++++++++++++++++++++++++++++ tests/api/test_ossl_pem.h | 2 + wolfssl/openssl/pem.h | 9 +++ 4 files changed, 228 insertions(+) diff --git a/src/pk.c b/src/pk.c index 410cce3a95..c86f54501d 100644 --- a/src/pk.c +++ b/src/pk.c @@ -6282,6 +6282,125 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, } #endif /* !NO_BIO */ +#ifndef NO_FILESYSTEM +/* Writes a public key to a file pointer encoded in PEM format. + * + * Mirrors wolfSSL_PEM_read_PUBKEY: convert the EVP_PKEY to public-key DER and + * write it with the generic PUBLIC KEY PEM type. + * + * @param [in] fp File pointer to write to. + * @param [in] key Public key to write in PEM format. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key) +{ + int ret = 0; +#if !defined(NO_ASN) && !defined(NO_PWDBASED) + unsigned char* der = NULL; + int derSz; +#endif + + WOLFSSL_ENTER("wolfSSL_PEM_write_PUBKEY"); + + if ((fp == XBADFILE) || (key == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + return 0; + } + +#if !defined(NO_ASN) && !defined(NO_PWDBASED) + derSz = wolfSSL_i2d_PUBKEY(key, &der); + if (derSz > 0) { + ret = der_write_to_file_as_pem(der, derSz, fp, PUBLICKEY_TYPE, NULL); + } + XFREE(der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); +#else + WOLFSSL_MSG("i2d_PUBKEY not supported in this build"); +#endif + + return ret; +} + +/* Writes a private key to a file pointer encoded in PEM format. + * + * Mirrors wolfSSL_PEM_read_PrivateKey's key-type switch and writes the stored + * DER as the matching PEM private key type. + * + * @param [in] fp File pointer to write to. + * @param [in] key Private key to write in PEM format. + * @param [in] cipher Encryption cipher to use. May be NULL. + * @param [in] passwd Password to use when encrypting. May be NULL. + * @param [in] len Length of password. + * @param [in] cb Password callback. + * @param [in] arg Password callback argument. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, + wc_pem_password_cb* cb, void* arg) +{ + int err = 0; + int type = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_PrivateKey"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (key == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + err = 1; + } + + if ((!err) && ((cipher != NULL) || (passwd != NULL) || (len != 0) || + (cb != NULL) || (arg != NULL))) { + WOLFSSL_MSG("PEM private key encryption not supported here"); + } + + if (!err) { + /* Set PEM type based on key type, inverse of PEM_read_PrivateKey. */ + switch (key->type) { + #ifndef NO_RSA + case WC_EVP_PKEY_RSA: + type = PRIVATEKEY_TYPE; + break; + #endif + #ifndef NO_DSA + case WC_EVP_PKEY_DSA: + type = DSA_PRIVATEKEY_TYPE; + break; + #endif + #ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + type = ECC_PRIVATEKEY_TYPE; + break; + #endif + #ifndef NO_DH + case WC_EVP_PKEY_DH: + type = DH_PRIVATEKEY_TYPE; + break; + #endif + default: + type = WOLFSSL_FATAL_ERROR; + break; + } + } + + if ((!err) && (type == WOLFSSL_FATAL_ERROR)) { + err = 1; + } + + /* Write DER data as the selected PEM private key type. */ + if ((!err) && (der_write_to_file_as_pem((byte*)key->pkey.ptr, key->pkey_sz, + fp, type, NULL) != 1)) { + err = 1; + } + + WOLFSSL_LEAVE("wolfSSL_PEM_write_PrivateKey", err); + + return !err; +} +#endif /* !NO_FILESYSTEM */ + #ifndef NO_BIO /* Create a private key object from the data in the BIO. * diff --git a/tests/api/test_ossl_pem.c b/tests/api/test_ossl_pem.c index 547768854e..f772fa35d2 100644 --- a/tests/api/test_ossl_pem.c +++ b/tests/api/test_ossl_pem.c @@ -755,6 +755,104 @@ int test_wolfSSL_PEM_PrivateKey(void) return EXPECT_RESULT(); } +int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \ + !defined(NO_FILESYSTEM) && defined(USE_CERT_BUFFERS_2048) && \ + !defined(NO_ASN) && !defined(NO_PWDBASED) + const char* privFile = "./test-pem-write-private-key.pem"; + const char* pubFile = "./test-pem-write-pubkey.pem"; + const unsigned char* serverKey = + (const unsigned char*)server_key_der_2048; + EVP_PKEY* pkey = NULL; + EVP_PKEY* readPriv = NULL; + EVP_PKEY* readPub = NULL; + unsigned char* pubDer = NULL; + unsigned char* readPubDer = NULL; + XFILE fp = XBADFILE; + long privSz = 0; + long pubSz = 0; + int pubDerSz = 0; + int readPubDerSz = 0; + + remove(privFile); + remove(pubFile); + + ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &serverKey, + (long)sizeof_server_key_der_2048)); + + ExpectIntEQ(PEM_write_PrivateKey(XBADFILE, pkey, NULL, NULL, 0, NULL, + NULL), 0); + ExpectIntEQ(PEM_write_PrivateKey(stderr, NULL, NULL, NULL, 0, NULL, + NULL), 0); + ExpectIntEQ(PEM_write_PUBKEY(XBADFILE, pkey), 0); + ExpectIntEQ(PEM_write_PUBKEY(stderr, NULL), 0); + + ExpectTrue((fp = XFOPEN(privFile, "wb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectIntEQ(PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL), + 1); + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectTrue((fp = XFOPEN(privFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectTrue(XFSEEK(fp, 0, XSEEK_END) == 0); + ExpectIntGT(privSz = XFTELL(fp), 0); + ExpectTrue(XFSEEK(fp, 0, XSEEK_SET) == 0); + ExpectNotNull(readPriv = PEM_read_PrivateKey(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + if ((pkey != NULL) && (readPriv != NULL) && (pkey->pkey.ptr != NULL) && + (readPriv->pkey.ptr != NULL)) { + ExpectIntEQ(pkey->pkey_sz, readPriv->pkey_sz); + ExpectIntEQ(XMEMCMP(pkey->pkey.ptr, readPriv->pkey.ptr, + pkey->pkey_sz), 0); + } + + ExpectIntGT(pubDerSz = wolfSSL_i2d_PUBKEY(pkey, &pubDer), 0); + ExpectTrue((fp = XFOPEN(pubFile, "wb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectIntEQ(PEM_write_PUBKEY(fp, pkey), 1); + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectTrue((fp = XFOPEN(pubFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectTrue(XFSEEK(fp, 0, XSEEK_END) == 0); + ExpectIntGT(pubSz = XFTELL(fp), 0); + ExpectTrue(XFSEEK(fp, 0, XSEEK_SET) == 0); + ExpectNotNull(readPub = PEM_read_PUBKEY(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + ExpectIntGT(readPubDerSz = wolfSSL_i2d_PUBKEY(readPub, &readPubDer), 0); + ExpectIntEQ(pubDerSz, readPubDerSz); + if ((pubDer != NULL) && (readPubDer != NULL) && (pubDerSz > 0) && + (pubDerSz == readPubDerSz)) { + ExpectIntEQ(XMEMCMP(pubDer, readPubDer, pubDerSz), 0); + } + + ExpectIntGT(privSz, pubSz); + + XFREE(readPubDer, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(pubDer, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + EVP_PKEY_free(readPub); + EVP_PKEY_free(readPriv); + EVP_PKEY_free(pkey); + if (fp != XBADFILE) { + XFCLOSE(fp); + } + remove(privFile); + remove(pubFile); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_PEM_file_RSAKey(void) { EXPECT_DECLS; diff --git a/tests/api/test_ossl_pem.h b/tests/api/test_ossl_pem.h index 55480d218e..f84a0bb459 100644 --- a/tests/api/test_ossl_pem.h +++ b/tests/api/test_ossl_pem.h @@ -32,6 +32,7 @@ int test_wolfSSL_PEM_PrivateKey_ecc(void); int test_wolfSSL_PEM_PrivateKey_dsa(void); int test_wolfSSL_PEM_PrivateKey_dh(void); int test_wolfSSL_PEM_PrivateKey(void); +int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void); int test_wolfSSL_PEM_file_RSAKey(void); int test_wolfSSL_PEM_file_RSAPrivateKey(void); int test_wolfSSL_PEM_read_RSA_PUBKEY(void); @@ -52,6 +53,7 @@ int test_wolfSSL_PEM_PUBKEY(void); TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey_dsa), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey_dh), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey), \ + TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_write_PrivateKey_PUBKEY), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_file_RSAKey), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_file_RSAPrivateKey), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_read_RSA_PUBKEY), \ diff --git a/wolfssl/openssl/pem.h b/wolfssl/openssl/pem.h index 9ccc4731de..6ad42052b2 100644 --- a/wolfssl/openssl/pem.h +++ b/wolfssl/openssl/pem.h @@ -231,6 +231,13 @@ WOLFSSL_API int wolfSSL_PEM_write_X509(XFILE fp, WOLFSSL_X509 *x); WOLFSSL_API int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh); +WOLFSSL_API +int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, + const WOLFSSL_EVP_CIPHER* cipher, + unsigned char* passwd, int len, + wc_pem_password_cb* cb, void* arg); +WOLFSSL_API +int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key); #endif /* NO_FILESYSTEM */ #ifndef OPENSSL_COEXIST @@ -244,6 +251,7 @@ int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh); #define PEM_read_X509 wolfSSL_PEM_read_X509 #define PEM_read_PrivateKey wolfSSL_PEM_read_PrivateKey +#define PEM_write_PrivateKey wolfSSL_PEM_write_PrivateKey #define PEM_write_X509 wolfSSL_PEM_write_X509 #define PEM_write_bio_PrivateKey wolfSSL_PEM_write_bio_PrivateKey #define PEM_write_bio_PKCS8PrivateKey wolfSSL_PEM_write_bio_PKCS8PrivateKey @@ -287,6 +295,7 @@ int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh); #define PEM_read_PUBKEY wolfSSL_PEM_read_PUBKEY #define PEM_read_bio_PUBKEY wolfSSL_PEM_read_bio_PUBKEY #define PEM_write_bio_PUBKEY wolfSSL_PEM_write_bio_PUBKEY +#define PEM_write_PUBKEY wolfSSL_PEM_write_PUBKEY #define PEM_write_bio_PKCS8_PRIV_KEY_INFO wolfSSL_PEM_write_bio_PKCS8_PRIV_KEY_INFO #define PEM_read_bio_PKCS8_PRIV_KEY_INFO wolfSSL_PEM_read_bio_PKCS8_PRIV_KEY_INFO From e638f8ec6147ebaae4362e047f55ac5ca0dca54a Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Sun, 26 Apr 2026 17:37:34 +0300 Subject: [PATCH 2/7] Refactor: remove incorrect check against NULL , passwd and cipher can be NULL --- src/pk.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/pk.c b/src/pk.c index c86f54501d..4d722ad70f 100644 --- a/src/pk.c +++ b/src/pk.c @@ -6351,11 +6351,6 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, err = 1; } - if ((!err) && ((cipher != NULL) || (passwd != NULL) || (len != 0) || - (cb != NULL) || (arg != NULL))) { - WOLFSSL_MSG("PEM private key encryption not supported here"); - } - if (!err) { /* Set PEM type based on key type, inverse of PEM_read_PrivateKey. */ switch (key->type) { @@ -6394,6 +6389,7 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, fp, type, NULL) != 1)) { err = 1; } + WOLFSSL_LEAVE("wolfSSL_PEM_write_PrivateKey", err); From 5403298327ad5470400363b2e624dbbed1aa9993 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Mon, 27 Apr 2026 11:26:24 +0300 Subject: [PATCH 3/7] Refactor - Split test to two different functions --- tests/api/test_ossl_pem.c | 66 ++++++++++++++++++++++++++------------- tests/api/test_ossl_pem.h | 6 ++-- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/tests/api/test_ossl_pem.c b/tests/api/test_ossl_pem.c index f772fa35d2..9715319ae6 100644 --- a/tests/api/test_ossl_pem.c +++ b/tests/api/test_ossl_pem.c @@ -755,40 +755,31 @@ int test_wolfSSL_PEM_PrivateKey(void) return EXPECT_RESULT(); } -int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void) +int test_wolfSSL_PEM_write_PrivateKey(void) { EXPECT_DECLS; #if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \ !defined(NO_FILESYSTEM) && defined(USE_CERT_BUFFERS_2048) && \ !defined(NO_ASN) && !defined(NO_PWDBASED) const char* privFile = "./test-pem-write-private-key.pem"; - const char* pubFile = "./test-pem-write-pubkey.pem"; const unsigned char* serverKey = (const unsigned char*)server_key_der_2048; EVP_PKEY* pkey = NULL; EVP_PKEY* readPriv = NULL; - EVP_PKEY* readPub = NULL; - unsigned char* pubDer = NULL; - unsigned char* readPubDer = NULL; XFILE fp = XBADFILE; - long privSz = 0; - long pubSz = 0; - int pubDerSz = 0; - int readPubDerSz = 0; remove(privFile); - remove(pubFile); ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &serverKey, (long)sizeof_server_key_der_2048)); + /* Bad-argument checks. */ ExpectIntEQ(PEM_write_PrivateKey(XBADFILE, pkey, NULL, NULL, 0, NULL, NULL), 0); ExpectIntEQ(PEM_write_PrivateKey(stderr, NULL, NULL, NULL, 0, NULL, NULL), 0); - ExpectIntEQ(PEM_write_PUBKEY(XBADFILE, pkey), 0); - ExpectIntEQ(PEM_write_PUBKEY(stderr, NULL), 0); + /* Write private key to file. */ ExpectTrue((fp = XFOPEN(privFile, "wb")) != XBADFILE); if (fp != XBADFILE) { ExpectIntEQ(PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL), @@ -797,11 +788,9 @@ int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void) fp = XBADFILE; } + /* Read it back and verify the DER content matches. */ ExpectTrue((fp = XFOPEN(privFile, "rb")) != XBADFILE); if (fp != XBADFILE) { - ExpectTrue(XFSEEK(fp, 0, XSEEK_END) == 0); - ExpectIntGT(privSz = XFTELL(fp), 0); - ExpectTrue(XFSEEK(fp, 0, XSEEK_SET) == 0); ExpectNotNull(readPriv = PEM_read_PrivateKey(fp, NULL, NULL, NULL)); XFCLOSE(fp); fp = XBADFILE; @@ -813,7 +802,46 @@ int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void) pkey->pkey_sz), 0); } + EVP_PKEY_free(readPriv); + EVP_PKEY_free(pkey); + if (fp != XBADFILE) { + XFCLOSE(fp); + } + remove(privFile); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_PEM_write_PUBKEY(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \ + !defined(NO_FILESYSTEM) && defined(USE_CERT_BUFFERS_2048) && \ + !defined(NO_ASN) && !defined(NO_PWDBASED) + const char* pubFile = "./test-pem-write-pubkey.pem"; + const unsigned char* serverKey = + (const unsigned char*)server_key_der_2048; + EVP_PKEY* pkey = NULL; + EVP_PKEY* readPub = NULL; + unsigned char* pubDer = NULL; + unsigned char* readPubDer = NULL; + XFILE fp = XBADFILE; + int pubDerSz = 0; + int readPubDerSz = 0; + + remove(pubFile); + + ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &serverKey, + (long)sizeof_server_key_der_2048)); + + /* Bad-argument checks. */ + ExpectIntEQ(PEM_write_PUBKEY(XBADFILE, pkey), 0); + ExpectIntEQ(PEM_write_PUBKEY(stderr, NULL), 0); + + /* Capture the expected public-key DER for later comparison. */ ExpectIntGT(pubDerSz = wolfSSL_i2d_PUBKEY(pkey, &pubDer), 0); + + /* Write public key to file. */ ExpectTrue((fp = XFOPEN(pubFile, "wb")) != XBADFILE); if (fp != XBADFILE) { ExpectIntEQ(PEM_write_PUBKEY(fp, pkey), 1); @@ -821,11 +849,9 @@ int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void) fp = XBADFILE; } + /* Read it back and verify the DER content matches. */ ExpectTrue((fp = XFOPEN(pubFile, "rb")) != XBADFILE); if (fp != XBADFILE) { - ExpectTrue(XFSEEK(fp, 0, XSEEK_END) == 0); - ExpectIntGT(pubSz = XFTELL(fp), 0); - ExpectTrue(XFSEEK(fp, 0, XSEEK_SET) == 0); ExpectNotNull(readPub = PEM_read_PUBKEY(fp, NULL, NULL, NULL)); XFCLOSE(fp); fp = XBADFILE; @@ -837,17 +863,13 @@ int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void) ExpectIntEQ(XMEMCMP(pubDer, readPubDer, pubDerSz), 0); } - ExpectIntGT(privSz, pubSz); - XFREE(readPubDer, NULL, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(pubDer, NULL, DYNAMIC_TYPE_PUBLIC_KEY); EVP_PKEY_free(readPub); - EVP_PKEY_free(readPriv); EVP_PKEY_free(pkey); if (fp != XBADFILE) { XFCLOSE(fp); } - remove(privFile); remove(pubFile); #endif return EXPECT_RESULT(); diff --git a/tests/api/test_ossl_pem.h b/tests/api/test_ossl_pem.h index f84a0bb459..3de900a6fa 100644 --- a/tests/api/test_ossl_pem.h +++ b/tests/api/test_ossl_pem.h @@ -32,7 +32,8 @@ int test_wolfSSL_PEM_PrivateKey_ecc(void); int test_wolfSSL_PEM_PrivateKey_dsa(void); int test_wolfSSL_PEM_PrivateKey_dh(void); int test_wolfSSL_PEM_PrivateKey(void); -int test_wolfSSL_PEM_write_PrivateKey_PUBKEY(void); +int test_wolfSSL_PEM_write_PrivateKey(void); +int test_wolfSSL_PEM_write_PUBKEY(void); int test_wolfSSL_PEM_file_RSAKey(void); int test_wolfSSL_PEM_file_RSAPrivateKey(void); int test_wolfSSL_PEM_read_RSA_PUBKEY(void); @@ -53,7 +54,8 @@ int test_wolfSSL_PEM_PUBKEY(void); TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey_dsa), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey_dh), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey), \ - TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_write_PrivateKey_PUBKEY), \ + TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_write_PrivateKey), \ + TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_write_PUBKEY), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_file_RSAKey), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_file_RSAPrivateKey), \ TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_read_RSA_PUBKEY), \ From 210c2e45f668ac72f55cdd834d57929bd9d870fc Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Mon, 27 Apr 2026 11:27:31 +0300 Subject: [PATCH 4/7] Fix: Implement with const char and not der like in read --- src/pk.c | 98 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/pk.c b/src/pk.c index 4d722ad70f..37efe591e3 100644 --- a/src/pk.c +++ b/src/pk.c @@ -292,11 +292,7 @@ static int der_write_to_bio_as_pem(const unsigned char* der, int derSz, #endif #endif -#if defined(OPENSSL_EXTRA) && \ - ((!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || \ - (!defined(NO_DH) && defined(WOLFSSL_DH_EXTRA)) || \ - (defined(HAVE_ECC) && defined(WOLFSSL_KEY_GEN))) -#if !defined(NO_FILESYSTEM) +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) /* Write the DER data as PEM into file pointer. * * @param [in] der Buffer containing DER data. @@ -326,8 +322,7 @@ static int der_write_to_file_as_pem(const unsigned char* der, int derSz, XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } -#endif -#endif +#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM */ #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_KEY_GEN) && \ defined(WOLFSSL_PEM_TO_DER) @@ -6283,10 +6278,8 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, #endif /* !NO_BIO */ #ifndef NO_FILESYSTEM +#ifndef NO_CERTS /* Writes a public key to a file pointer encoded in PEM format. - * - * Mirrors wolfSSL_PEM_read_PUBKEY: convert the EVP_PKEY to public-key DER and - * write it with the generic PUBLIC KEY PEM type. * * @param [in] fp File pointer to write to. * @param [in] key Public key to write in PEM format. @@ -6295,30 +6288,39 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, */ int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key) { - int ret = 0; -#if !defined(NO_ASN) && !defined(NO_PWDBASED) - unsigned char* der = NULL; - int derSz; -#endif + int err = 0; + unsigned char* derBuf = NULL; + int derSz = 0; WOLFSSL_ENTER("wolfSSL_PEM_write_PUBKEY"); + /* Validate parameters. */ if ((fp == XBADFILE) || (key == NULL)) { WOLFSSL_MSG("Bad Function Arguments"); - return 0; + err = 1; } -#if !defined(NO_ASN) && !defined(NO_PWDBASED) - derSz = wolfSSL_i2d_PUBKEY(key, &der); - if (derSz > 0) { - ret = der_write_to_file_as_pem(der, derSz, fp, PUBLICKEY_TYPE, NULL); + /* Encode the public key as DER. */ + if (!err) { + derSz = wolfSSL_i2d_PUBKEY(key, &derBuf); + if (derSz <= 0) { + WOLFSSL_MSG("Failed to convert key to DER"); + err = 1; + } } - XFREE(der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); -#else - WOLFSSL_MSG("i2d_PUBKEY not supported in this build"); -#endif - return ret; + /* Write DER buffer to file as PEM. */ + if ((!err) && (der_write_to_file_as_pem(derBuf, derSz, fp, + PUBLICKEY_TYPE, NULL) != 1)) { + WOLFSSL_MSG("Failed to write DER to file as PEM"); + err = 1; + } + + /* Dispose of the DER encoding. */ + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("wolfSSL_PEM_write_PUBKEY", err); + return !err; } /* Writes a private key to a file pointer encoded in PEM format. @@ -6342,6 +6344,14 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, { int err = 0; int type = 0; + unsigned char* derBuf = NULL; + int derSz = 0; + + (void)cipher; + (void)passwd; + (void)len; + (void)cb; + (void)arg; WOLFSSL_ENTER("wolfSSL_PEM_write_PrivateKey"); @@ -6351,50 +6361,52 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, err = 1; } + /* Determine PEM type from key type, mirroring wolfSSL_PEM_read_PrivateKey's + * keyFormat switch. */ if (!err) { - /* Set PEM type based on key type, inverse of PEM_read_PrivateKey. */ switch (key->type) { - #ifndef NO_RSA case WC_EVP_PKEY_RSA: type = PRIVATEKEY_TYPE; break; - #endif - #ifndef NO_DSA case WC_EVP_PKEY_DSA: type = DSA_PRIVATEKEY_TYPE; break; - #endif - #ifdef HAVE_ECC case WC_EVP_PKEY_EC: type = ECC_PRIVATEKEY_TYPE; break; - #endif - #ifndef NO_DH case WC_EVP_PKEY_DH: type = DH_PRIVATEKEY_TYPE; break; - #endif default: - type = WOLFSSL_FATAL_ERROR; + WOLFSSL_MSG("Unknown key type"); + err = 1; break; } } - if ((!err) && (type == WOLFSSL_FATAL_ERROR)) { + /* Encode the private key as DER. */ + if (!err) { + derSz = wolfSSL_i2d_PrivateKey(key, &derBuf); + if (derSz <= 0) { + WOLFSSL_MSG("Error encoding private key as DER"); + err = 1; + } + } + + /* Write DER buffer to file as PEM. */ + if ((!err) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, + NULL) != 1)) { + WOLFSSL_MSG("Error writing DER to file as PEM"); err = 1; } - /* Write DER data as the selected PEM private key type. */ - if ((!err) && (der_write_to_file_as_pem((byte*)key->pkey.ptr, key->pkey_sz, - fp, type, NULL) != 1)) { - err = 1; - } - + /* Dispose of the DER encoding. */ + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); WOLFSSL_LEAVE("wolfSSL_PEM_write_PrivateKey", err); - return !err; } +#endif /* !NO_CERTS */ #endif /* !NO_FILESYSTEM */ #ifndef NO_BIO From 07d71a3b87aff934fa6b83a1a5ccc9a35638c0e4 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Mon, 27 Apr 2026 11:28:05 +0300 Subject: [PATCH 5/7] Cosmetic - remove mirrored irrelevant note --- src/pk.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pk.c b/src/pk.c index 37efe591e3..d02384fefc 100644 --- a/src/pk.c +++ b/src/pk.c @@ -6324,9 +6324,6 @@ int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key) } /* Writes a private key to a file pointer encoded in PEM format. - * - * Mirrors wolfSSL_PEM_read_PrivateKey's key-type switch and writes the stored - * DER as the matching PEM private key type. * * @param [in] fp File pointer to write to. * @param [in] key Private key to write in PEM format. From 3aa3201ed0ca52f0777726d0d7446eaae7386f8c Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Fri, 8 May 2026 21:16:10 +0300 Subject: [PATCH 6/7] Fix - leantls defines NO_PWDBASED , also add !NO_ASN guard for clarity . --- src/pk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pk.c b/src/pk.c index d02384fefc..fa5af22bb9 100644 --- a/src/pk.c +++ b/src/pk.c @@ -6279,6 +6279,7 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, #ifndef NO_FILESYSTEM #ifndef NO_CERTS +#if defined(OPENSSL_EXTRA) && !defined(NO_ASN) && !defined(NO_PWDBASED) /* Writes a public key to a file pointer encoded in PEM format. * * @param [in] fp File pointer to write to. @@ -6403,6 +6404,7 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, WOLFSSL_LEAVE("wolfSSL_PEM_write_PrivateKey", err); return !err; } +#endif /* OPENSSL_EXTRA && !NO_ASN && !NO_PWDBASED */ #endif /* !NO_CERTS */ #endif /* !NO_FILESYSTEM */ From b20c1db02e734ebf11212b3a414357efed9e7e65 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Fri, 22 May 2026 19:24:43 +0300 Subject: [PATCH 7/7] Refactor - Fix pr notes + compilation error for a test --- src/pk.c | 64 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/src/pk.c b/src/pk.c index fa5af22bb9..131e1367e0 100644 --- a/src/pk.c +++ b/src/pk.c @@ -292,7 +292,10 @@ static int der_write_to_bio_as_pem(const unsigned char* der, int derSz, #endif #endif -#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) +#if !defined(NO_FILESYSTEM) && \ + ((defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_ASN) && \ + !defined(NO_PWDBASED)) || \ + defined(WOLFSSL_DH_EXTRA)) /* Write the DER data as PEM into file pointer. * * @param [in] der Buffer containing DER data. @@ -322,7 +325,9 @@ static int der_write_to_file_as_pem(const unsigned char* der, int derSz, XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } -#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM */ +#endif /* !NO_FILESYSTEM && + * ((OPENSSL_EXTRA && !NO_CERTS && !NO_ASN && !NO_PWDBASED) || + * WOLFSSL_DH_EXTRA) */ #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_KEY_GEN) && \ defined(WOLFSSL_PEM_TO_DER) @@ -6277,9 +6282,8 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, } #endif /* !NO_BIO */ -#ifndef NO_FILESYSTEM -#ifndef NO_CERTS -#if defined(OPENSSL_EXTRA) && !defined(NO_ASN) && !defined(NO_PWDBASED) +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) && \ + !defined(NO_ASN) && !defined(NO_PWDBASED) /* Writes a public key to a file pointer encoded in PEM format. * * @param [in] fp File pointer to write to. @@ -6295,21 +6299,36 @@ int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key) WOLFSSL_ENTER("wolfSSL_PEM_write_PUBKEY"); - /* Validate parameters. */ if ((fp == XBADFILE) || (key == NULL)) { WOLFSSL_MSG("Bad Function Arguments"); err = 1; } - /* Encode the public key as DER. */ if (!err) { - derSz = wolfSSL_i2d_PUBKEY(key, &derBuf); + derSz = wolfSSL_i2d_PUBKEY(key, NULL); if (derSz <= 0) { - WOLFSSL_MSG("Failed to convert key to DER"); + WOLFSSL_MSG("Failed to get DER size for key"); err = 1; } } + if (!err) { + unsigned char* tmp; + derBuf = (unsigned char*)XMALLOC((size_t)derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("Failed to allocate DER buffer"); + err = 1; + } + else { + tmp = derBuf; + if (wolfSSL_i2d_PUBKEY(key, &tmp) <= 0) { + WOLFSSL_MSG("Failed to convert key to DER"); + err = 1; + } + } + } + /* Write DER buffer to file as PEM. */ if ((!err) && (der_write_to_file_as_pem(derBuf, derSz, fp, PUBLICKEY_TYPE, NULL) != 1)) { @@ -6382,15 +6401,31 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, } } - /* Encode the private key as DER. */ if (!err) { - derSz = wolfSSL_i2d_PrivateKey(key, &derBuf); + derSz = wolfSSL_i2d_PrivateKey(key, NULL); if (derSz <= 0) { - WOLFSSL_MSG("Error encoding private key as DER"); + WOLFSSL_MSG("Failed to get DER size for private key"); err = 1; } } + if (!err) { + unsigned char* tmp; + derBuf = (unsigned char*)XMALLOC((size_t)derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("Failed to allocate DER buffer"); + err = 1; + } + else { + tmp = derBuf; + if (wolfSSL_i2d_PrivateKey(key, &tmp) <= 0) { + WOLFSSL_MSG("Error encoding private key as DER"); + err = 1; + } + } + } + /* Write DER buffer to file as PEM. */ if ((!err) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, NULL) != 1)) { @@ -6404,9 +6439,8 @@ int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key, WOLFSSL_LEAVE("wolfSSL_PEM_write_PrivateKey", err); return !err; } -#endif /* OPENSSL_EXTRA && !NO_ASN && !NO_PWDBASED */ -#endif /* !NO_CERTS */ -#endif /* !NO_FILESYSTEM */ +#endif /* !NO_FILESYSTEM && !NO_CERTS && OPENSSL_EXTRA && !NO_ASN && + * !NO_PWDBASED */ #ifndef NO_BIO /* Create a private key object from the data in the BIO.