From c8233177c3f4386cdae63842574ddd3a0fa1a3fd Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 8 Feb 2017 09:16:48 -0700 Subject: [PATCH] fix bio gets and enhance x509 get public key --- src/bio.c | 24 +++++++-- src/ssl.c | 123 ++++++++++++++++++++++++++++++++---------- tests/api.c | 104 ++++++++++++++++++++++++++++++++++- wolfcrypt/src/evp.c | 10 +++- wolfssl/openssl/ssl.h | 6 --- wolfssl/ssl.h | 4 ++ 6 files changed, 227 insertions(+), 44 deletions(-) diff --git a/src/bio.c b/src/bio.c index e4bfe475b..84382a2c8 100644 --- a/src/bio.c +++ b/src/bio.c @@ -38,7 +38,7 @@ WOLFSSL_API long wolfSSL_BIO_ctrl(WOLFSSL_BIO *bio, int cmd, long larg, void *pa /* helper function for wolfSSL_BIO_gets * size till a newline is hit - * returns the number of bytes + * returns the number of bytes including the new line character */ static int wolfSSL_getLineLength(char* in, int inSz) { @@ -46,11 +46,11 @@ static int wolfSSL_getLineLength(char* in, int inSz) for (i = 0; i < inSz; i++) { if (in[i] == '\n') { - break; + return i + 1; /* includes new line character */ } } - return i + 1; /* +1 to return number of bytes not index */ + return inSz; /* rest of buffer is all one line */ } @@ -72,6 +72,10 @@ int wolfSSL_BIO_gets(WOLFSSL_BIO* bio, char* buf, int sz) switch (bio->type) { #ifndef NO_FILESYSTEM case WOLFSSL_BIO_FILE: + if (bio->file == NULL) { + return WOLFSSL_BIO_ERROR; + } + #if defined(MICRIUM) || defined(LSR_FS) || defined(EBSNET) WOLFSSL_MSG("XFGETS not ported for this system yet"); ret = XFGETS(buf, sz, bio->file); @@ -103,10 +107,15 @@ int wolfSSL_BIO_gets(WOLFSSL_BIO* bio, char* buf, int sz) cSz = wolfSSL_getLineLength((char*)c, cSz); /* check case where line was bigger then buffer and buffer * needs end terminator */ - if (cSz > sz) { + if (cSz >= sz) { cSz = sz - 1; buf[cSz] = '\0'; } + else { + /* not minus 1 here because placing terminator after + msg and have checked that sz is large enough */ + buf[cSz] = '\0'; + } ret = wolfSSL_BIO_read(bio, (void*)buf, cSz); /* ret is read after the switch statment */ @@ -125,10 +134,15 @@ int wolfSSL_BIO_gets(WOLFSSL_BIO* bio, char* buf, int sz) cSz = wolfSSL_getLineLength(c, cSz); /* check case where line was bigger then buffer and buffer * needs end terminator */ - if (cSz > sz) { + if (cSz >= sz) { cSz = sz - 1; buf[cSz] = '\0'; } + else { + /* not minus 1 here because placing terminator after + msg and have checked that sz is large enough */ + buf[cSz] = '\0'; + } ret = wolfSSL_BIO_nread(bio, &c, cSz); if (ret > 0 && ret < sz) { diff --git a/src/ssl.c b/src/ssl.c index 91c1d982e..273b8dbd3 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17220,34 +17220,6 @@ WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl) -WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) -{ - WOLFSSL_EVP_PKEY* key = NULL; - if (x509 != NULL) { - key = (WOLFSSL_EVP_PKEY*)XMALLOC( - sizeof(WOLFSSL_EVP_PKEY), x509->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (key != NULL) { - key->type = EVP_PKEY_RSA; /*x509->pubKeyOID;*/ - key->save_type = 0; - key->pkey.ptr = (char*)XMALLOC( - x509->pubKey.length, x509->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (key->pkey.ptr == NULL) { - XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); - return NULL; - } - XMEMCPY(key->pkey.ptr, - x509->pubKey.buffer, x509->pubKey.length); - key->pkey_sz = x509->pubKey.length; - #ifdef HAVE_ECC - key->pkey_curve = (int)x509->pkCurveOID; - #endif /* HAVE_ECC */ - } - } - return key; -} - int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* key) { @@ -17334,6 +17306,14 @@ void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key) break; #endif /* NO_RSA */ + #ifdef HAVE_ECC + case EVP_PKEY_EC: + if (key->ecc != NULL && key->ownEcc == 1) { + wolfSSL_EC_KEY_free(key->ecc); + } + break; + #endif /* HAVE_ECC */ + default: break; } @@ -24478,6 +24458,91 @@ int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, } #endif /* HAVE_ECC */ + +WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) +{ + WOLFSSL_EVP_PKEY* key = NULL; + if (x509 != NULL) { + key = (WOLFSSL_EVP_PKEY*)XMALLOC( + sizeof(WOLFSSL_EVP_PKEY), x509->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (key != NULL) { + XMEMSET(key, 0, sizeof(WOLFSSL_EVP_PKEY)); + if (x509->pubKeyOID == RSAk) { + key->type = EVP_PKEY_RSA; + } + else { + key->type = EVP_PKEY_EC; + } + key->save_type = 0; + key->pkey.ptr = (char*)XMALLOC( + x509->pubKey.length, x509->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (key->pkey.ptr == NULL) { + XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + return NULL; + } + XMEMCPY(key->pkey.ptr, x509->pubKey.buffer, x509->pubKey.length); + key->pkey_sz = x509->pubKey.length; + + #ifdef HAVE_ECC + key->pkey_curve = (int)x509->pkCurveOID; + #endif /* HAVE_ECC */ + + /* decode RSA key */ + #ifndef NO_RSA + if (key->type == EVP_PKEY_RSA) { + key->ownRsa = 1; + key->rsa = wolfSSL_RSA_new(); + if (key->rsa == NULL) { + XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + return NULL; + } + + if (wolfSSL_RSA_LoadDer_ex(key->rsa, + (const unsigned char*)key->pkey.ptr, key->pkey_sz, + WOLFSSL_RSA_LOAD_PUBLIC) != SSL_SUCCESS) { + XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + wolfSSL_RSA_free(key->rsa); + return NULL; + } + } + #endif /* NO_RSA */ + + /* decode ECC key */ + #ifdef HAVE_ECC + if (key->type == EVP_PKEY_EC) { + key->ownEcc = 1; + key->ecc = wolfSSL_EC_KEY_new(); + if (key->ecc == NULL || key->ecc->internal == NULL) { + XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + return NULL; + } + + /* not using wolfSSL_EC_KEY_LoadDer because public key in x509 + * is in the format of x963 (no sequence at start of buffer) */ + if (wc_ecc_import_x963((const unsigned char*)key->pkey.ptr, + key->pkey_sz, (ecc_key*)key->ecc->internal) < 0) { + WOLFSSL_MSG("wc_ecc_import_x963 failed"); + XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + wolfSSL_EC_KEY_free(key->ecc); + return NULL; + } + + if (SetECKeyExternal(key->ecc) != SSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyExternal failed"); + XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + wolfSSL_EC_KEY_free(key->ecc); + return NULL; + } + + key->ecc->inSet = 1; + } + #endif /* HAVE_ECC */ + } + } + return key; +} #endif /* OPENSSL_EXTRA */ @@ -26292,7 +26357,7 @@ WOLFSSL_BIO *wolfSSL_BIO_new_file(const char *filename, const char *mode) (void)filename; (void)mode; return NULL; -#endif +#endif /* NO_FILESYSTEM */ } diff --git a/tests/api.c b/tests/api.c index ffb0db4b2..659dd220d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -13716,7 +13716,34 @@ static void test_wolfSSL_CTX_add_extra_chain_cert(void) x509 = wolfSSL_X509_load_certificate_file(clientFile, WOLFSSL_FILETYPE_PEM); AssertNotNull(x509); - AssertIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, x509), WOLFSSL_SUCCESS); + + /* additional test of getting EVP_PKEY key size from X509 */ + { + EVP_PKEY* pkey; + #if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) + X509* ecX509; + #endif /* HAVE_ECC */ + + AssertNotNull(pkey = X509_get_pubkey(x509)); + /* current RSA key is 2048 bit (256 bytes) */ + AssertIntEQ(EVP_PKEY_size(pkey), 256); + + EVP_PKEY_free(pkey); + + #if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) + AssertNotNull(ecX509 = wolfSSL_X509_load_certificate_buffer( + cliecc_cert_der_256, sizeof_cliecc_cert_der_256, + SSL_FILETYPE_ASN1)); + AssertNotNull(pkey = X509_get_pubkey(ecX509)); + /* current ECC key is 256 bit (32 bytes) */ + AssertIntEQ(EVP_PKEY_size(pkey), 32); + + X509_free(ecX509); + EVP_PKEY_free(pkey); + #endif /* HAVE_ECC */ + } + + AssertIntEQ((int)SSL_CTX_add_extra_chain_cert(ctx, x509), SSL_SUCCESS); AssertNull(SSL_CTX_get_default_passwd_cb(ctx)); AssertNull(SSL_CTX_get_default_passwd_cb_userdata(ctx)); @@ -14551,7 +14578,7 @@ static void test_wolfSSL_BIO(void) BIO_free(f_bio1); BIO_free(f_bio2); - AssertNotNull(f_bio1 = BIO_new_file(svrCert, "rwb")); + AssertNotNull(f_bio1 = BIO_new_file(svrCertFile, "rwb")); AssertIntEQ((int)BIO_set_mem_eof_return(f_bio1, -1), 0); AssertIntEQ(BIO_read(f_bio1, cert, sizeof(cert)), sizeof(cert)); BIO_free(f_bio1); @@ -14977,6 +15004,7 @@ static void test_wolfSSL_BIO_gets(void) BIO* bio; BIO* bio2; char msg[] = "\nhello wolfSSL\n security plus\t---...**adf\na...b.c"; + char emp[] = ""; char buffer[20]; int bufferSz = 20; @@ -14989,6 +15017,9 @@ static void test_wolfSSL_BIO_gets(void) AssertNotNull(bio2 = BIO_find_type(bio, BIO_TYPE_BIO)); AssertFalse(bio2 != BIO_next(bio)); + /* make buffer filled with no terminating characters */ + XMEMSET(buffer, 1, bufferSz); + /* BIO_gets reads a line of data */ AssertIntEQ(BIO_gets(bio, buffer, -3), 0); AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 1); @@ -14998,6 +15029,75 @@ static void test_wolfSSL_BIO_gets(void) AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 8); AssertIntEQ(BIO_gets(bio, buffer, -1), 0); + /* check not null terminated string */ + BIO_free(bio); + msg[0] = 0x33; + msg[1] = 0x33; + msg[2] = 0x33; + AssertNotNull(bio = BIO_new_mem_buf((void*)msg, 3)); + AssertIntEQ(BIO_gets(bio, buffer, 3), 2); + AssertIntEQ(buffer[0], msg[0]); + AssertIntEQ(buffer[1], msg[1]); + AssertIntNE(buffer[2], msg[2]); + + BIO_free(bio); + msg[3] = 0x33; + buffer[3] = 0x33; + AssertNotNull(bio = BIO_new_mem_buf((void*)msg, 3)); + AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 3); + AssertIntEQ(buffer[0], msg[0]); + AssertIntEQ(buffer[1], msg[1]); + AssertIntEQ(buffer[2], msg[2]); + AssertIntNE(buffer[3], 0x33); /* make sure null terminator was set */ + + /* check reading an empty string */ + BIO_free(bio); + AssertNotNull(bio = BIO_new_mem_buf((void*)emp, sizeof(emp))); + AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 1); /* just terminator */ + AssertStrEQ(emp, buffer); + + /* check error cases */ + BIO_free(bio); + AssertIntEQ(BIO_gets(NULL, NULL, 0), SSL_FAILURE); + AssertNotNull(bio = BIO_new(BIO_s_mem())); + AssertIntEQ(BIO_gets(bio, buffer, 2), -1); /* nothing to read */ + +#if !defined(NO_FILESYSTEM) + { + BIO* f_bio; + XFILE f; + AssertNotNull(f_bio = BIO_new(BIO_s_file())); + AssertIntLE(BIO_gets(f_bio, buffer, bufferSz), 0); + + f = XFOPEN(svrCertFile, "rb"); + AssertIntEQ((int)BIO_set_fp(f_bio, f, BIO_CLOSE), SSL_SUCCESS); + AssertIntGT(BIO_gets(f_bio, buffer, bufferSz), 0); + + BIO_free(f_bio); + } +#endif /* NO_FILESYSTEM */ + + BIO_free(bio); + BIO_free(bio2); + + /* try with type BIO */ + XMEMCPY(msg, "\nhello wolfSSL\n security plus\t---...**adf\na...b.c", + sizeof(msg)); + AssertNotNull(bio = BIO_new(BIO_s_bio())); + AssertNotNull(bio2 = BIO_new(BIO_s_bio())); + + AssertIntEQ(BIO_set_write_buf_size(bio, 10), SSL_SUCCESS); + AssertIntEQ(BIO_set_write_buf_size(bio2, sizeof(msg)), SSL_SUCCESS); + AssertIntEQ(BIO_make_bio_pair(bio, bio2), SSL_SUCCESS); + + AssertIntEQ(BIO_write(bio2, msg, sizeof(msg)), sizeof(msg)); + AssertIntEQ(BIO_gets(bio, buffer, -3), 0); + AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 1); + AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 14); + AssertStrEQ(buffer, "hello wolfSSL\n"); + AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 19); + AssertIntEQ(BIO_gets(bio, buffer, bufferSz), 8); + AssertIntEQ(BIO_gets(bio, buffer, -1), 0); BIO_free(bio); BIO_free(bio2); diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 3dce7e93b..f964f39e4 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -756,8 +756,14 @@ WOLFSSL_API int wolfSSL_EVP_PKEY_size(WOLFSSL_EVP_PKEY *pkey) #endif /* NO_RSA */ case EVP_PKEY_EC: - WOLFSSL_MSG("not implemented"); - /* not implemented */ +#ifdef HAVE_ECC + if (pkey->ecc == NULL || pkey->ecc->internal == NULL) { + WOLFSSL_MSG("No ECC key has been set"); + return 0; + } + return wc_ecc_size((ecc_key*)(pkey->ecc->internal)); +#endif /* HAVE_ECC */ + default: return 0; } diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index d12aa7d3f..def44c15d 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -531,11 +531,6 @@ typedef WOLFSSL_X509_STORE_CTX X509_STORE_CTX; /* yassl had set the default to be 500 */ #define SSL_get_default_timeout(ctx) 500 -/* Lighthttp compatibility */ - -#if defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \ - defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ - defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY) typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY; #define X509_NAME_free wolfSSL_X509_NAME_free @@ -604,7 +599,6 @@ enum { #define sk_SSL_COMP_zero wolfSSL_sk_SSL_COMP_zero #define sk_SSL_CIPHER_value wolfSSL_sk_SSL_CIPHER_value #endif /* WOLFSSL_HAPROXY */ -#endif /* HAVE_STUNNEL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ #define SSL_CTX_set_tmp_dh wolfSSL_CTX_set_tmp_dh diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 0edd5cb81..aaef2dcf4 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -207,6 +207,10 @@ typedef struct WOLFSSL_EVP_PKEY { WOLFSSL_RSA* rsa; byte ownRsa; /* if struct owns RSA and should free it */ #endif + #ifdef HAVE_ECC + WOLFSSL_EC_KEY* ecc; + byte ownEcc; /* if struct owns ECC and should free it */ + #endif WC_RNG rng; #endif #ifdef HAVE_ECC