From 921eb03a01e77bff24d3398e9eaa13b7e1f1c777 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Thu, 12 Jan 2017 18:06:31 -0700 Subject: [PATCH] add PEM read bio private key function and update reading a memory bio --- src/bio.c | 17 +++- src/ssl.c | 229 ++++++++++++++++++++++++++++++++++++++---- tests/api.c | 36 ++++++- wolfssl/openssl/ssl.h | 1 + 4 files changed, 257 insertions(+), 26 deletions(-) diff --git a/src/bio.c b/src/bio.c index b7bdf51f6..5b83a8a5e 100644 --- a/src/bio.c +++ b/src/bio.c @@ -173,7 +173,7 @@ size_t wolfSSL_BIO_ctrl_pending(WOLFSSL_BIO *bio) } if (bio->type == WOLFSSL_BIO_MEMORY) { - return bio->memLen; + return bio->wrSz; } /* type BIO_BIO then check paired buffer */ @@ -223,7 +223,7 @@ int wolfSSL_BIO_set_write_buf_size(WOLFSSL_BIO *bio, long size) WOLFSSL_ENTER("wolfSSL_BIO_set_write_buf_size"); if (bio == NULL || bio->type != WOLFSSL_BIO_BIO || size < 0) { - return SSL_FAILURE; + return WOLFSSL_FAILURE; } /* if already in pair then do not change size */ @@ -247,6 +247,7 @@ int wolfSSL_BIO_set_write_buf_size(WOLFSSL_BIO *bio, long size) WOLFSSL_MSG("Memory allocation error"); return WOLFSSL_FAILURE; } + bio->memLen = bio->wrSz; bio->wrIdx = 0; bio->rdIdx = 0; @@ -296,8 +297,8 @@ int wolfSSL_BIO_ctrl_reset_read_request(WOLFSSL_BIO *b) { WOLFSSL_ENTER("wolfSSL_BIO_ctrl_reset_read_request"); - if (b == NULL) { - return WOLFSSL_FAILURE; + if (b == NULL || b->type == WOLFSSL_BIO_MEMORY) { + return SSL_FAILURE; } b->readRq = 0; @@ -346,6 +347,10 @@ int wolfSSL_BIO_nread(WOLFSSL_BIO *bio, char **buf, int num) return WOLFSSL_FAILURE; } + if (bio->type == WOLFSSL_BIO_MEMORY) { + return SSL_FAILURE; + } + if (bio->pair != NULL) { /* special case if asking to read 0 bytes */ if (num == 0) { @@ -394,6 +399,10 @@ int wolfSSL_BIO_nwrite(WOLFSSL_BIO *bio, char **buf, int num) return 0; } + if (bio->type != WOLFSSL_BIO_BIO) { + return SSL_FAILURE; + } + if (bio->pair != NULL) { if (num == 0) { *buf = (char*)bio->mem + bio->wrIdx; diff --git a/src/ssl.c b/src/ssl.c index 89e8a55ce..030379f46 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -6847,7 +6847,18 @@ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, return NULL; } - local = wolfSSL_PKEY_new(); + if (out != NULL && *out != NULL) { + /* reuse structure */ + WOLFSSL_MSG("Reusing WOLFSSL_EVP_PKEY structure"); + if ((*out)->pkey.ptr != NULL) { + XFREE((*out)->pkey.ptr, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + } + local = *out; + } + else { + local = wolfSSL_PKEY_new(); + } + if (local == NULL) { return NULL; } @@ -11761,7 +11772,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl) if (bio == NULL) return bio; - bio->memLen = len; + bio->memLen = bio->wrSz = len; bio->mem = (byte*)XMALLOC(len, 0, DYNAMIC_TYPE_OPENSSL); if (bio->mem == NULL) { XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL); @@ -11909,6 +11920,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return wolfSSL_BIO_BIO_read(bio, buf, len); } + if (bio && bio->type == WOLFSSL_BIO_MEMORY) { + return wolfSSL_BIO_MEMORY_read(bio, buf, len); + } + #ifndef NO_FILESYSTEM if (bio && bio->type == WOLFSSL_BIO_FILE) { return (int)XFREAD(buf, 1, len, bio->file); @@ -11960,6 +11975,56 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } + /* for complete compatibility a bio memory write allocs its own memory + * untill the application runs out .... + */ + static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data, + int len) + { + /* internal function where arguments have already been sanity checked */ + int sz; + int ret; + const unsigned char* buf; + + sz = wolfSSL_BIO_pending(bio); + if (sz < 0) { + WOLFSSL_MSG("Error getting memory data"); + return sz; + } + + if (bio->mem == NULL) { + bio->mem = (byte*)XMALLOC(len, bio->heap, + DYNAMIC_TYPE_OPENSSL); + if (bio->mem == NULL) { + WOLFSSL_MSG("Error on malloc"); + return SSL_FAILURE; + } + bio->memLen = len; + } + + /* check if will fit in current buffer size */ + if ((ret = wolfSSL_BIO_get_mem_data(bio, &buf)) < sz + len) { + if (ret <= 0) { + return WOLFSSL_BIO_ERROR; + } + else { + bio->mem = (byte*)XREALLOC(bio->mem, sz + len, bio->heap, + DYNAMIC_TYPE_OPENSSL); + if (bio->mem == NULL) { + WOLFSSL_MSG("Error on realloc"); + return SSL_FAILURE; + } + bio->memLen = sz + len; + } + } + + XMEMCPY(bio->mem + sz, data, len); + bio->wrSz += len; + + return len; + } + + int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len) { int ret; @@ -11973,6 +12038,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return wolfSSL_BIO_BIO_write(bio, data, len); } + if (bio && bio->type == WOLFSSL_BIO_MEMORY) { + return wolfSSL_BIO_MEMORY_write(bio, data, len); + } + #ifndef NO_FILESYSTEM if (bio && bio->type == WOLFSSL_BIO_FILE) { return (int)XFWRITE(data, 1, len, bio->file); @@ -14637,6 +14706,12 @@ static void ExternalFreeX509(WOLFSSL_X509* x509) return SSL_FAILURE; } + /* free any existing data before copying */ + if (asn1->data != NULL) { + XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); + } + + /* create new data buffer and copy over */ asn1->data = (char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL); if (asn1->data == NULL) { return SSL_FAILURE; @@ -15966,9 +16041,7 @@ WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO* top) int wolfSSL_BIO_pending(WOLFSSL_BIO* bio) { - if (bio && bio->type == WOLFSSL_BIO_MEMORY) - return bio->memLen; - return 0; + return (int)wolfSSL_BIO_ctrl_pending(bio); } @@ -21819,6 +21892,7 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, int pemSz; int type; int ret; + byte* tmp; (void)cipher; (void)passwd; @@ -21859,20 +21933,27 @@ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", pemSz); return WOLFSSL_FAILURE; } - if (bio->mem != NULL) { - XFREE(bio->mem, NULL, DYNAMIC_TYPE_OPENSSL); + tmp = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (tmp == NULL) { + return MEMORY_E; } - bio->mem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_OPENSSL); - bio->memLen = pemSz; - ret = wc_DerToPemEx(keyDer, key->pkey_sz, bio->mem, bio->memLen, + ret = wc_DerToPemEx(keyDer, key->pkey_sz, tmp, pemSz, NULL, type); if (ret < 0) { WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", ret); - return WOLFSSL_FAILURE; + XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); + return SSL_FAILURE; } - return WOLFSSL_SUCCESS; + ret = wolfSSL_BIO_write(bio, tmp, pemSz); + XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (ret != pemSz) { + WOLFSSL_MSG("Unable to write full PEM to BIO"); + return SSL_FAILURE; + } + + return SSL_SUCCESS; } #endif /* defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) */ @@ -23631,17 +23712,127 @@ int wolfSSL_PEM_write_DSA_PUBKEY(FILE *fp, WOLFSSL_DSA *x) #endif /* #ifndef NO_DSA */ + WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** key, pem_password_cb* cb, void* arg) + WOLFSSL_EVP_PKEY** key, pem_password_cb* cb, void* pass) { - (void)bio; - (void)key; - (void)cb; - (void)arg; + WOLFSSL_EVP_PKEY* pkey = NULL; +#ifdef WOLFSSL_SMALL_STACK + Encryptedinfo* info; +#else + EncryptedInfo info[1]; +#endif /* WOLFSSL_SMALL_STACK */ + pem_password_cb* localCb = cb; + DerBuffer* der = NULL; - WOLFSSL_MSG("wolfSSL_PEM_read_bio_PrivateKey not implemented"); + char* mem = NULL; + int memSz; + int ret; + int eccFlag = 0; - return NULL; + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PrivateKey"); + + if ((ret = wolfSSL_BIO_pending(bio)) > 0) { + memSz = ret; + mem = (char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (mem == NULL) { + WOLFSSL_MSG("Memory error"); + return NULL; + } + + if ((ret = wolfSSL_BIO_read(bio, mem, memSz)) <= 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", ret); + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + } + else { + WOLFSSL_MSG("No data to read from bio"); + return NULL; + } + +#ifdef WOLFSSL_SMALL_STACK + info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (info == NULL) { + WOLFSSL_MSG("Error getting memory for EncryptedInfo structure"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } +#endif + + XMEMSET(info, 0, sizeof(EncryptedInfo)); + + if (pass != NULL) { + info->ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + if (info->ctx == NULL) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + WOLFSSL_MSG("Error creating ctx for password"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + if (cb == NULL) { + localCb = &OurPasswordCb; + } + wolfSSL_CTX_set_default_passwd_cb(info->ctx, localCb); + wolfSSL_CTX_set_default_passwd_cb_userdata(info->ctx, pass); + } + + ret = PemToDer((const unsigned char*)mem, memSz, PRIVATEKEY_TYPE, &der, + NULL, info, &eccFlag); + + if (info->ctx) { + wolfSSL_CTX_free(info->ctx); + } + + if (ret < 0) { + WOLFSSL_MSG("Bad Pem To Der"); + } + else { + int type; + + /* write left over data back to bio */ + if ((memSz - (int)info->consumed) > 0) { + if (wolfSSL_BIO_write(bio, mem + (int)info->consumed, + memSz - (int)info->consumed) <= 0) { + WOLFSSL_MSG("Unable to advance bio read pointer"); + } + } + + if (eccFlag) { + type = ECDSAk; + } + else { + type = RSAk; + } + + /* handle case where reuse is attempted */ + if (key != NULL && *key != NULL) { + pkey = *key; + } + + wolfSSL_d2i_PrivateKey(type, &pkey, + (const unsigned char**)&der->buffer, der->length); + if (pkey == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + FreeDer(&der); + + if (key != NULL) { + *key = pkey; + } + + return pkey; } diff --git a/tests/api.c b/tests/api.c index 7939f508c..606377cf9 100644 --- a/tests/api.c +++ b/tests/api.c @@ -13383,6 +13383,12 @@ static void test_wolfSSL_private_keys(void) AssertNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &server_key, (long)sizeof_server_key_der_2048)); AssertIntEQ(SSL_use_PrivateKey(ssl, pkey), WOLFSSL_SUCCESS); + + /* reuse PKEY structure and test + * this should be checked with a memory management sanity checker */ + AssertNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, + &server_key, (long)sizeof_server_key_der_2048)); + AssertIntEQ(SSL_use_PrivateKey(ssl, pkey), WOLFSSL_SUCCESS); } #endif @@ -13408,21 +13414,45 @@ static void test_wolfSSL_PEM_PrivateKey(void) (defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN)) && \ defined(USE_CERT_BUFFERS_2048) const unsigned char* server_key = (const unsigned char*)server_key_der_2048; - EVP_PKEY* pkey = NULL; + EVP_PKEY* pkey = NULL; + EVP_PKEY* pkey2 = NULL; BIO* bio; + unsigned char extra[10]; + int i; printf(testingFmt, "wolfSSL_PEM_PrivateKey()"); - bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); - AssertNotNull(bio); + XMEMSET(extra, 0, sizeof(extra)); + AssertNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())); + AssertIntEQ(BIO_set_write_buf_size(bio, 4096), SSL_FAILURE); AssertNotNull(wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &server_key, (long)sizeof_server_key_der_2048)); AssertIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), WOLFSSL_SUCCESS); + /* test of creating new EVP_PKEY */ + AssertNotNull((pkey2 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))); + AssertIntEQ((int)XMEMCMP(pkey->pkey.ptr, pkey2->pkey.ptr, pkey->pkey_sz),0); + + /* test of reuse of EVP_PKEY */ + AssertNull(PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)); + AssertIntEQ(BIO_pending(bio), 0); + AssertIntEQ(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL), + SSL_SUCCESS); + AssertIntEQ(BIO_write(bio, extra, 10), 10); /*add 10 extra bytes after PEM*/ + AssertNotNull(PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)); + AssertNotNull(pkey); + AssertIntEQ((int)XMEMCMP(pkey->pkey.ptr, pkey2->pkey.ptr, pkey->pkey_sz),0); + AssertIntEQ(BIO_pending(bio), 10); /* check 10 extra bytes still there */ + AssertIntEQ(BIO_read(bio, extra, 10), 10); + for (i = 0; i < 10; i++) { + AssertIntEQ(extra[i], 0); + } + BIO_free(bio); EVP_PKEY_free(pkey); + EVP_PKEY_free(pkey2); printf(resultFmt, passed); #endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) */ diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 68eb8ae7c..5462c68f4 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -124,6 +124,7 @@ typedef WOLFSSL_X509_STORE_CTX X509_STORE_CTX; #define SSL_use_certificate wolfSSL_use_certificate #define SSL_use_certificate_ASN1 wolfSSL_use_certificate_ASN1 +#define d2i_PrivateKey wolfSSL_d2i_PrivateKey #define SSL_use_PrivateKey wolfSSL_use_PrivateKey #define SSL_use_PrivateKey_ASN1 wolfSSL_use_PrivateKey_ASN1 #define SSL_use_RSAPrivateKey_ASN1 wolfSSL_use_RSAPrivateKey_ASN1