Skip to content

Commit 71ca579

Browse files
authored
Merge pull request #10317 from Roy-Carter/feature/pem_write_enhancement
Implementation for PEM_write_PrivateKey & PEM_write_PUBKEY
2 parents 6852a0a + b20c1db commit 71ca579

4 files changed

Lines changed: 300 additions & 7 deletions

File tree

src/pk.c

Lines changed: 167 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,10 @@ static int der_write_to_bio_as_pem(const unsigned char* der, int derSz,
292292
#endif
293293
#endif
294294

295-
#if defined(OPENSSL_EXTRA) && \
296-
((!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || \
297-
(!defined(NO_DH) && defined(WOLFSSL_DH_EXTRA)) || \
298-
(defined(HAVE_ECC) && defined(WOLFSSL_KEY_GEN)))
299-
#if !defined(NO_FILESYSTEM)
295+
#if !defined(NO_FILESYSTEM) && \
296+
((defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_ASN) && \
297+
!defined(NO_PWDBASED)) || \
298+
defined(WOLFSSL_DH_EXTRA))
300299
/* Write the DER data as PEM into file pointer.
301300
*
302301
* @param [in] der Buffer containing DER data.
@@ -326,8 +325,9 @@ static int der_write_to_file_as_pem(const unsigned char* der, int derSz,
326325
XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
327326
return ret;
328327
}
329-
#endif
330-
#endif
328+
#endif /* !NO_FILESYSTEM &&
329+
* ((OPENSSL_EXTRA && !NO_CERTS && !NO_ASN && !NO_PWDBASED) ||
330+
* WOLFSSL_DH_EXTRA) */
331331

332332
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_KEY_GEN) && \
333333
defined(WOLFSSL_PEM_TO_DER)
@@ -6282,6 +6282,166 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key,
62826282
}
62836283
#endif /* !NO_BIO */
62846284

6285+
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) && \
6286+
!defined(NO_ASN) && !defined(NO_PWDBASED)
6287+
/* Writes a public key to a file pointer encoded in PEM format.
6288+
*
6289+
* @param [in] fp File pointer to write to.
6290+
* @param [in] key Public key to write in PEM format.
6291+
* @return 1 on success.
6292+
* @return 0 on failure.
6293+
*/
6294+
int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key)
6295+
{
6296+
int err = 0;
6297+
unsigned char* derBuf = NULL;
6298+
int derSz = 0;
6299+
6300+
WOLFSSL_ENTER("wolfSSL_PEM_write_PUBKEY");
6301+
6302+
if ((fp == XBADFILE) || (key == NULL)) {
6303+
WOLFSSL_MSG("Bad Function Arguments");
6304+
err = 1;
6305+
}
6306+
6307+
if (!err) {
6308+
derSz = wolfSSL_i2d_PUBKEY(key, NULL);
6309+
if (derSz <= 0) {
6310+
WOLFSSL_MSG("Failed to get DER size for key");
6311+
err = 1;
6312+
}
6313+
}
6314+
6315+
if (!err) {
6316+
unsigned char* tmp;
6317+
derBuf = (unsigned char*)XMALLOC((size_t)derSz, NULL,
6318+
DYNAMIC_TYPE_TMP_BUFFER);
6319+
if (derBuf == NULL) {
6320+
WOLFSSL_MSG("Failed to allocate DER buffer");
6321+
err = 1;
6322+
}
6323+
else {
6324+
tmp = derBuf;
6325+
if (wolfSSL_i2d_PUBKEY(key, &tmp) <= 0) {
6326+
WOLFSSL_MSG("Failed to convert key to DER");
6327+
err = 1;
6328+
}
6329+
}
6330+
}
6331+
6332+
/* Write DER buffer to file as PEM. */
6333+
if ((!err) && (der_write_to_file_as_pem(derBuf, derSz, fp,
6334+
PUBLICKEY_TYPE, NULL) != 1)) {
6335+
WOLFSSL_MSG("Failed to write DER to file as PEM");
6336+
err = 1;
6337+
}
6338+
6339+
/* Dispose of the DER encoding. */
6340+
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
6341+
6342+
WOLFSSL_LEAVE("wolfSSL_PEM_write_PUBKEY", err);
6343+
return !err;
6344+
}
6345+
6346+
/* Writes a private key to a file pointer encoded in PEM format.
6347+
*
6348+
* @param [in] fp File pointer to write to.
6349+
* @param [in] key Private key to write in PEM format.
6350+
* @param [in] cipher Encryption cipher to use. May be NULL.
6351+
* @param [in] passwd Password to use when encrypting. May be NULL.
6352+
* @param [in] len Length of password.
6353+
* @param [in] cb Password callback.
6354+
* @param [in] arg Password callback argument.
6355+
* @return 1 on success.
6356+
* @return 0 on failure.
6357+
*/
6358+
int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key,
6359+
const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len,
6360+
wc_pem_password_cb* cb, void* arg)
6361+
{
6362+
int err = 0;
6363+
int type = 0;
6364+
unsigned char* derBuf = NULL;
6365+
int derSz = 0;
6366+
6367+
(void)cipher;
6368+
(void)passwd;
6369+
(void)len;
6370+
(void)cb;
6371+
(void)arg;
6372+
6373+
WOLFSSL_ENTER("wolfSSL_PEM_write_PrivateKey");
6374+
6375+
/* Validate parameters. */
6376+
if ((fp == XBADFILE) || (key == NULL)) {
6377+
WOLFSSL_MSG("Bad Function Arguments");
6378+
err = 1;
6379+
}
6380+
6381+
/* Determine PEM type from key type, mirroring wolfSSL_PEM_read_PrivateKey's
6382+
* keyFormat switch. */
6383+
if (!err) {
6384+
switch (key->type) {
6385+
case WC_EVP_PKEY_RSA:
6386+
type = PRIVATEKEY_TYPE;
6387+
break;
6388+
case WC_EVP_PKEY_DSA:
6389+
type = DSA_PRIVATEKEY_TYPE;
6390+
break;
6391+
case WC_EVP_PKEY_EC:
6392+
type = ECC_PRIVATEKEY_TYPE;
6393+
break;
6394+
case WC_EVP_PKEY_DH:
6395+
type = DH_PRIVATEKEY_TYPE;
6396+
break;
6397+
default:
6398+
WOLFSSL_MSG("Unknown key type");
6399+
err = 1;
6400+
break;
6401+
}
6402+
}
6403+
6404+
if (!err) {
6405+
derSz = wolfSSL_i2d_PrivateKey(key, NULL);
6406+
if (derSz <= 0) {
6407+
WOLFSSL_MSG("Failed to get DER size for private key");
6408+
err = 1;
6409+
}
6410+
}
6411+
6412+
if (!err) {
6413+
unsigned char* tmp;
6414+
derBuf = (unsigned char*)XMALLOC((size_t)derSz, NULL,
6415+
DYNAMIC_TYPE_TMP_BUFFER);
6416+
if (derBuf == NULL) {
6417+
WOLFSSL_MSG("Failed to allocate DER buffer");
6418+
err = 1;
6419+
}
6420+
else {
6421+
tmp = derBuf;
6422+
if (wolfSSL_i2d_PrivateKey(key, &tmp) <= 0) {
6423+
WOLFSSL_MSG("Error encoding private key as DER");
6424+
err = 1;
6425+
}
6426+
}
6427+
}
6428+
6429+
/* Write DER buffer to file as PEM. */
6430+
if ((!err) && (der_write_to_file_as_pem(derBuf, derSz, fp, type,
6431+
NULL) != 1)) {
6432+
WOLFSSL_MSG("Error writing DER to file as PEM");
6433+
err = 1;
6434+
}
6435+
6436+
/* Dispose of the DER encoding. */
6437+
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
6438+
6439+
WOLFSSL_LEAVE("wolfSSL_PEM_write_PrivateKey", err);
6440+
return !err;
6441+
}
6442+
#endif /* !NO_FILESYSTEM && !NO_CERTS && OPENSSL_EXTRA && !NO_ASN &&
6443+
* !NO_PWDBASED */
6444+
62856445
#ifndef NO_BIO
62866446
/* Create a private key object from the data in the BIO.
62876447
*

tests/api/test_ossl_pem.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,126 @@ int test_wolfSSL_PEM_PrivateKey(void)
755755
return EXPECT_RESULT();
756756
}
757757

758+
int test_wolfSSL_PEM_write_PrivateKey(void)
759+
{
760+
EXPECT_DECLS;
761+
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \
762+
!defined(NO_FILESYSTEM) && defined(USE_CERT_BUFFERS_2048) && \
763+
!defined(NO_ASN) && !defined(NO_PWDBASED)
764+
const char* privFile = "./test-pem-write-private-key.pem";
765+
const unsigned char* serverKey =
766+
(const unsigned char*)server_key_der_2048;
767+
EVP_PKEY* pkey = NULL;
768+
EVP_PKEY* readPriv = NULL;
769+
XFILE fp = XBADFILE;
770+
771+
remove(privFile);
772+
773+
ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &serverKey,
774+
(long)sizeof_server_key_der_2048));
775+
776+
/* Bad-argument checks. */
777+
ExpectIntEQ(PEM_write_PrivateKey(XBADFILE, pkey, NULL, NULL, 0, NULL,
778+
NULL), 0);
779+
ExpectIntEQ(PEM_write_PrivateKey(stderr, NULL, NULL, NULL, 0, NULL,
780+
NULL), 0);
781+
782+
/* Write private key to file. */
783+
ExpectTrue((fp = XFOPEN(privFile, "wb")) != XBADFILE);
784+
if (fp != XBADFILE) {
785+
ExpectIntEQ(PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL),
786+
1);
787+
XFCLOSE(fp);
788+
fp = XBADFILE;
789+
}
790+
791+
/* Read it back and verify the DER content matches. */
792+
ExpectTrue((fp = XFOPEN(privFile, "rb")) != XBADFILE);
793+
if (fp != XBADFILE) {
794+
ExpectNotNull(readPriv = PEM_read_PrivateKey(fp, NULL, NULL, NULL));
795+
XFCLOSE(fp);
796+
fp = XBADFILE;
797+
}
798+
if ((pkey != NULL) && (readPriv != NULL) && (pkey->pkey.ptr != NULL) &&
799+
(readPriv->pkey.ptr != NULL)) {
800+
ExpectIntEQ(pkey->pkey_sz, readPriv->pkey_sz);
801+
ExpectIntEQ(XMEMCMP(pkey->pkey.ptr, readPriv->pkey.ptr,
802+
pkey->pkey_sz), 0);
803+
}
804+
805+
EVP_PKEY_free(readPriv);
806+
EVP_PKEY_free(pkey);
807+
if (fp != XBADFILE) {
808+
XFCLOSE(fp);
809+
}
810+
remove(privFile);
811+
#endif
812+
return EXPECT_RESULT();
813+
}
814+
815+
int test_wolfSSL_PEM_write_PUBKEY(void)
816+
{
817+
EXPECT_DECLS;
818+
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_RSA) && \
819+
!defined(NO_FILESYSTEM) && defined(USE_CERT_BUFFERS_2048) && \
820+
!defined(NO_ASN) && !defined(NO_PWDBASED)
821+
const char* pubFile = "./test-pem-write-pubkey.pem";
822+
const unsigned char* serverKey =
823+
(const unsigned char*)server_key_der_2048;
824+
EVP_PKEY* pkey = NULL;
825+
EVP_PKEY* readPub = NULL;
826+
unsigned char* pubDer = NULL;
827+
unsigned char* readPubDer = NULL;
828+
XFILE fp = XBADFILE;
829+
int pubDerSz = 0;
830+
int readPubDerSz = 0;
831+
832+
remove(pubFile);
833+
834+
ExpectNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &serverKey,
835+
(long)sizeof_server_key_der_2048));
836+
837+
/* Bad-argument checks. */
838+
ExpectIntEQ(PEM_write_PUBKEY(XBADFILE, pkey), 0);
839+
ExpectIntEQ(PEM_write_PUBKEY(stderr, NULL), 0);
840+
841+
/* Capture the expected public-key DER for later comparison. */
842+
ExpectIntGT(pubDerSz = wolfSSL_i2d_PUBKEY(pkey, &pubDer), 0);
843+
844+
/* Write public key to file. */
845+
ExpectTrue((fp = XFOPEN(pubFile, "wb")) != XBADFILE);
846+
if (fp != XBADFILE) {
847+
ExpectIntEQ(PEM_write_PUBKEY(fp, pkey), 1);
848+
XFCLOSE(fp);
849+
fp = XBADFILE;
850+
}
851+
852+
/* Read it back and verify the DER content matches. */
853+
ExpectTrue((fp = XFOPEN(pubFile, "rb")) != XBADFILE);
854+
if (fp != XBADFILE) {
855+
ExpectNotNull(readPub = PEM_read_PUBKEY(fp, NULL, NULL, NULL));
856+
XFCLOSE(fp);
857+
fp = XBADFILE;
858+
}
859+
ExpectIntGT(readPubDerSz = wolfSSL_i2d_PUBKEY(readPub, &readPubDer), 0);
860+
ExpectIntEQ(pubDerSz, readPubDerSz);
861+
if ((pubDer != NULL) && (readPubDer != NULL) && (pubDerSz > 0) &&
862+
(pubDerSz == readPubDerSz)) {
863+
ExpectIntEQ(XMEMCMP(pubDer, readPubDer, pubDerSz), 0);
864+
}
865+
866+
XFREE(readPubDer, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
867+
XFREE(pubDer, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
868+
EVP_PKEY_free(readPub);
869+
EVP_PKEY_free(pkey);
870+
if (fp != XBADFILE) {
871+
XFCLOSE(fp);
872+
}
873+
remove(pubFile);
874+
#endif
875+
return EXPECT_RESULT();
876+
}
877+
758878
int test_wolfSSL_PEM_file_RSAKey(void)
759879
{
760880
EXPECT_DECLS;

tests/api/test_ossl_pem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ int test_wolfSSL_PEM_PrivateKey_ecc(void);
3232
int test_wolfSSL_PEM_PrivateKey_dsa(void);
3333
int test_wolfSSL_PEM_PrivateKey_dh(void);
3434
int test_wolfSSL_PEM_PrivateKey(void);
35+
int test_wolfSSL_PEM_write_PrivateKey(void);
36+
int test_wolfSSL_PEM_write_PUBKEY(void);
3537
int test_wolfSSL_PEM_file_RSAKey(void);
3638
int test_wolfSSL_PEM_file_RSAPrivateKey(void);
3739
int test_wolfSSL_PEM_read_RSA_PUBKEY(void);
@@ -52,6 +54,8 @@ int test_wolfSSL_PEM_PUBKEY(void);
5254
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey_dsa), \
5355
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey_dh), \
5456
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_PrivateKey), \
57+
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_write_PrivateKey), \
58+
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_write_PUBKEY), \
5559
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_file_RSAKey), \
5660
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_file_RSAPrivateKey), \
5761
TEST_DECL_GROUP("ossl_pem", test_wolfSSL_PEM_read_RSA_PUBKEY), \

wolfssl/openssl/pem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,13 @@ WOLFSSL_API
231231
int wolfSSL_PEM_write_X509(XFILE fp, WOLFSSL_X509 *x);
232232
WOLFSSL_API
233233
int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh);
234+
WOLFSSL_API
235+
int wolfSSL_PEM_write_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY* key,
236+
const WOLFSSL_EVP_CIPHER* cipher,
237+
unsigned char* passwd, int len,
238+
wc_pem_password_cb* cb, void* arg);
239+
WOLFSSL_API
240+
int wolfSSL_PEM_write_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY* key);
234241
#endif /* NO_FILESYSTEM */
235242

236243
#ifndef OPENSSL_COEXIST
@@ -244,6 +251,7 @@ int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh);
244251

245252
#define PEM_read_X509 wolfSSL_PEM_read_X509
246253
#define PEM_read_PrivateKey wolfSSL_PEM_read_PrivateKey
254+
#define PEM_write_PrivateKey wolfSSL_PEM_write_PrivateKey
247255
#define PEM_write_X509 wolfSSL_PEM_write_X509
248256
#define PEM_write_bio_PrivateKey wolfSSL_PEM_write_bio_PrivateKey
249257
#define PEM_write_bio_PKCS8PrivateKey wolfSSL_PEM_write_bio_PKCS8PrivateKey
@@ -287,6 +295,7 @@ int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh);
287295
#define PEM_read_PUBKEY wolfSSL_PEM_read_PUBKEY
288296
#define PEM_read_bio_PUBKEY wolfSSL_PEM_read_bio_PUBKEY
289297
#define PEM_write_bio_PUBKEY wolfSSL_PEM_write_bio_PUBKEY
298+
#define PEM_write_PUBKEY wolfSSL_PEM_write_PUBKEY
290299

291300
#define PEM_write_bio_PKCS8_PRIV_KEY_INFO wolfSSL_PEM_write_bio_PKCS8_PRIV_KEY_INFO
292301
#define PEM_read_bio_PKCS8_PRIV_KEY_INFO wolfSSL_PEM_read_bio_PKCS8_PRIV_KEY_INFO

0 commit comments

Comments
 (0)