From 613337cf8934995778dbb6f5abd4ebad0e0eb1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 15 Sep 2014 23:41:49 -0300 Subject: [PATCH] ssl: refactoring PemToDer to reduce stack usage: --- variable header moved to the heap (80 bytes saved) --- variable footer moved to the heap (80 bytes saved) --- variable password moved to the heap (80 bytes saved) fixes memory leak in CyaSSL_RAND_bytes --- src/ssl.c | 277 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 146 insertions(+), 131 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 82bf7f9fe..0d471612f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1788,92 +1788,80 @@ int CyaSSL_Init(void) #ifndef NO_CERTS +static const char* BEGIN_CERT = "-----BEGIN CERTIFICATE-----"; +static const char* END_CERT = "-----END CERTIFICATE-----"; +static const char* BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----"; +static const char* END_CERT_REQ = "-----END CERTIFICATE REQUEST-----"; +static const char* BEGIN_DH_PARAM = "-----BEGIN DH PARAMETERS-----"; +static const char* END_DH_PARAM = "-----END DH PARAMETERS-----"; +static const char* BEGIN_X509_CRL = "-----BEGIN X509 CRL-----"; +static const char* END_X509_CRL = "-----END X509 CRL-----"; +static const char* BEGIN_RSA_PRIV = "-----BEGIN RSA PRIVATE KEY-----"; +static const char* END_RSA_PRIV = "-----END RSA PRIVATE KEY-----"; +static const char* BEGIN_PRIV_KEY = "-----BEGIN PRIVATE KEY-----"; +static const char* END_PRIV_KEY = "-----END PRIVATE KEY-----"; +static const char* BEGIN_ENC_PRIV_KEY = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; +static const char* END_ENC_PRIV_KEY = "-----END ENCRYPTED PRIVATE KEY-----"; +static const char* BEGIN_EC_PRIV = "-----BEGIN EC PRIVATE KEY-----"; +static const char* END_EC_PRIV = "-----END EC PRIVATE KEY-----"; +static const char* BEGIN_DSA_PRIV = "-----BEGIN DSA PRIVATE KEY-----"; +static const char* END_DSA_PRIV = "-----END DSA PRIVATE KEY-----"; + /* Remove PEM header/footer, convert to ASN1, store any encrypted data info->consumed tracks of PEM bytes consumed in case multiple parts */ int PemToDer(const unsigned char* buff, long longSz, int type, buffer* der, void* heap, EncryptedInfo* info, int* eccKey) { - char header[PEM_LINE_LEN]; - char footer[PEM_LINE_LEN]; - char* headerEnd; - char* footerEnd; - char* consumedEnd; - char* bufferEnd = (char*)(buff + longSz); - long neededSz; - int ret = 0; - int pkcs8 = 0; - int pkcs8Enc = 0; - int dynamicType = 0; - int sz = (int)longSz; + const char* header = NULL; + const char* footer = NULL; + char* headerEnd; + char* footerEnd; + char* consumedEnd; + char* bufferEnd = (char*)(buff + longSz); + long neededSz; + int ret = 0; + int dynamicType = 0; + int sz = (int)longSz; - (void)heap; - (void)dynamicType; - - if (type == CERT_TYPE || type == CA_TYPE) { - XSTRNCPY(header, "-----BEGIN CERTIFICATE-----", sizeof(header)); - XSTRNCPY(footer, "-----END CERTIFICATE-----", sizeof(footer)); - dynamicType = (type == CA_TYPE) ? DYNAMIC_TYPE_CA - : DYNAMIC_TYPE_CERT; - } else if (type == CERTREQ_TYPE) { - XSTRNCPY(header, "-----BEGIN CERTIFICATE REQUEST-----", - sizeof(header)); - XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----", - sizeof(footer)); - dynamicType = DYNAMIC_TYPE_KEY; - } else if (type == DH_PARAM_TYPE) { - XSTRNCPY(header, "-----BEGIN DH PARAMETERS-----", sizeof(header)); - XSTRNCPY(footer, "-----END DH PARAMETERS-----", sizeof(footer)); - dynamicType = DYNAMIC_TYPE_KEY; - } else if (type == CRL_TYPE) { - XSTRNCPY(header, "-----BEGIN X509 CRL-----", sizeof(header)); - XSTRNCPY(footer, "-----END X509 CRL-----", sizeof(footer)); - dynamicType = DYNAMIC_TYPE_CRL; - } else { - XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header)); - XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----", sizeof(footer)); - dynamicType = DYNAMIC_TYPE_KEY; - } + switch (type) { + case CA_TYPE: /* same as below */ + case CERT_TYPE: header= BEGIN_CERT; footer= END_CERT; break; + case CRL_TYPE: header= BEGIN_X509_CRL; footer= END_X509_CRL; break; + case DH_PARAM_TYPE: header= BEGIN_DH_PARAM; footer= END_DH_PARAM; break; + case CERTREQ_TYPE: header= BEGIN_CERT_REQ; footer= END_CERT_REQ; break; + default: header= BEGIN_RSA_PRIV; footer= END_RSA_PRIV; break; + } + + switch (type) { + case CA_TYPE: dynamicType = DYNAMIC_TYPE_CA; break; + case CERT_TYPE: dynamicType = DYNAMIC_TYPE_CERT; break; + case CRL_TYPE: dynamicType = DYNAMIC_TYPE_CRL; break; + default: dynamicType = DYNAMIC_TYPE_KEY; break; + } /* find header */ - headerEnd = XSTRNSTR((char*)buff, header, sz); - if (!headerEnd && type == PRIVATEKEY_TYPE) { /* may be pkcs8 */ - XSTRNCPY(header, "-----BEGIN PRIVATE KEY-----", sizeof(header)); - XSTRNCPY(footer, "-----END PRIVATE KEY-----", sizeof(footer)); + for (;;) { + headerEnd = XSTRNSTR((char*)buff, header, sz); + + if (headerEnd || type != PRIVATEKEY_TYPE) { + break; + } else if (header == BEGIN_RSA_PRIV) { + header = BEGIN_PRIV_KEY; footer = END_PRIV_KEY; + } else if (header == BEGIN_PRIV_KEY) { + header = BEGIN_ENC_PRIV_KEY; footer = END_ENC_PRIV_KEY; + } else if (header == BEGIN_ENC_PRIV_KEY) { + header = BEGIN_EC_PRIV; footer = END_EC_PRIV; + } else if (header == BEGIN_ENC_PRIV_KEY) { + header = BEGIN_DSA_PRIV; footer = END_DSA_PRIV; + } else + break; + } - headerEnd = XSTRNSTR((char*)buff, header, sz); - if (headerEnd) - pkcs8 = 1; - else { - XSTRNCPY(header, "-----BEGIN ENCRYPTED PRIVATE KEY-----", - sizeof(header)); - XSTRNCPY(footer, "-----END ENCRYPTED PRIVATE KEY-----", - sizeof(footer)); - - headerEnd = XSTRNSTR((char*)buff, header, sz); - if (headerEnd) { - pkcs8Enc = 1; - (void)pkcs8Enc; /* only opensslextra will read */ - } - } - } - if (!headerEnd && type == PRIVATEKEY_TYPE) { /* may be ecc */ - XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----", sizeof(header)); - XSTRNCPY(footer, "-----END EC PRIVATE KEY-----", sizeof(footer)); - - headerEnd = XSTRNSTR((char*)buff, header, sz); - if (headerEnd) - *eccKey = 1; - } - if (!headerEnd && type == PRIVATEKEY_TYPE) { /* may be dsa */ - XSTRNCPY(header, "-----BEGIN DSA PRIVATE KEY-----", sizeof(header)); - XSTRNCPY(footer, "-----END DSA PRIVATE KEY-----", sizeof(footer)); - - headerEnd = XSTRNSTR((char*)buff, header, sz); - } if (!headerEnd) { CYASSL_MSG("Couldn't find PEM header"); return SSL_NO_PEM_HEADER; } + headerEnd += XSTRLEN(header); /* eat end of line */ @@ -1884,53 +1872,59 @@ int PemToDer(const unsigned char* buff, long longSz, int type, else return SSL_BAD_FILE; + if (type == PRIVATEKEY_TYPE) { + if (eccKey) + *eccKey = header == BEGIN_EC_PRIV; + } + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) -{ - /* remove encrypted header if there */ - char encHeader[] = "Proc-Type"; - char* line = XSTRNSTR(headerEnd, encHeader, PEM_LINE_LEN); - if (line) { - char* newline; - char* finish; - char* start = XSTRNSTR(line, "DES", PEM_LINE_LEN); + { + /* remove encrypted header if there */ + char encHeader[] = "Proc-Type"; + char* line = XSTRNSTR(headerEnd, encHeader, PEM_LINE_LEN); + if (line) { + char* newline; + char* finish; + char* start = XSTRNSTR(line, "DES", PEM_LINE_LEN); - if (!start) - start = XSTRNSTR(line, "AES", PEM_LINE_LEN); + if (!start) + start = XSTRNSTR(line, "AES", PEM_LINE_LEN); - if (!start) return SSL_BAD_FILE; - if (!info) return SSL_BAD_FILE; + if (!start) return SSL_BAD_FILE; + if (!info) return SSL_BAD_FILE; - finish = XSTRNSTR(start, ",", PEM_LINE_LEN); + finish = XSTRNSTR(start, ",", PEM_LINE_LEN); - if (start && finish && (start < finish)) { - newline = XSTRNSTR(finish, "\r", PEM_LINE_LEN); + if (start && finish && (start < finish)) { + newline = XSTRNSTR(finish, "\r", PEM_LINE_LEN); - XMEMCPY(info->name, start, finish - start); - info->name[finish - start] = 0; - XMEMCPY(info->iv, finish + 1, sizeof(info->iv)); + XMEMCPY(info->name, start, finish - start); + info->name[finish - start] = 0; + XMEMCPY(info->iv, finish + 1, sizeof(info->iv)); - if (!newline) newline = XSTRNSTR(finish, "\n", PEM_LINE_LEN); - if (newline && (newline > finish)) { - info->ivSz = (word32)(newline - (finish + 1)); - info->set = 1; - } - else - return SSL_BAD_FILE; - } - else - return SSL_BAD_FILE; + if (!newline) newline = XSTRNSTR(finish, "\n", PEM_LINE_LEN); + if (newline && (newline > finish)) { + info->ivSz = (word32)(newline - (finish + 1)); + info->set = 1; + } + else + return SSL_BAD_FILE; + } + else + return SSL_BAD_FILE; - /* eat blank line */ - while (*newline == '\r' || *newline == '\n') - newline++; - headerEnd = newline; - } -} + /* eat blank line */ + while (*newline == '\r' || *newline == '\n') + newline++; + headerEnd = newline; + } + } #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ /* find footer */ footerEnd = XSTRNSTR((char*)buff, footer, sz); - if (!footerEnd) return SSL_BAD_FILE; + if (!footerEnd) + return SSL_BAD_FILE; consumedEnd = footerEnd + XSTRLEN(footer); @@ -1949,43 +1943,60 @@ int PemToDer(const unsigned char* buff, long longSz, int type, /* set up der buffer */ neededSz = (long)(footerEnd - headerEnd); - if (neededSz > sz || neededSz < 0) return SSL_BAD_FILE; - der->buffer = (byte*) XMALLOC(neededSz, heap, dynamicType); - if (!der->buffer) return MEMORY_ERROR; + if (neededSz > sz || neededSz < 0) + return SSL_BAD_FILE; + + der->buffer = (byte*)XMALLOC(neededSz, heap, dynamicType); + if (!der->buffer) + return MEMORY_ERROR; + der->length = (word32)neededSz; if (Base64_Decode((byte*)headerEnd, (word32)neededSz, der->buffer, &der->length) < 0) return SSL_BAD_FILE; - if (pkcs8) { - /* convert and adjust length */ - if ( (ret = ToTraditional(der->buffer, der->length)) < 0 ) { + if (header == BEGIN_PRIV_KEY) { + /* pkcs8 key, convert and adjust length */ + if ((ret = ToTraditional(der->buffer, der->length)) < 0) return ret; - } else { - der->length = ret; - return 0; - } + + der->length = ret; + return 0; } #if (defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)) && !defined(NO_PWDBASED) - if (pkcs8Enc) { - int passwordSz; - char password[80]; + if (header == BEGIN_ENC_PRIV_KEY) { + int passwordSz; + #ifdef CYASSL_SMALL_STACK + char* password = NULL; + #else + char password[80]; + #endif if (!info || !info->ctx || !info->ctx->passwd_cb) return SSL_BAD_FILE; /* no callback error */ - passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0, + + #ifdef CYASSL_SMALL_STACK + password = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (password == NULL) + return MEMORY_E; + #endif + passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0, info->ctx->userdata); /* convert and adjust length */ - if ( (ret = ToTraditionalEnc(der->buffer, der->length, password, - passwordSz)) < 0 ) { + ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz); + + #ifdef CYASSL_SMALL_STACK + XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + + if (ret < 0) return ret; - } else { - der->length = ret; - return 0; - } - } + + der->length = ret; + return 0; + } #endif return 0; @@ -10013,11 +10024,11 @@ int CyaSSL_RAND_bytes(unsigned char* buf, int num) CYASSL_ENTER("RAND_bytes"); - #ifdef CYASSL_SMALL_STACK +#ifdef CYASSL_SMALL_STACK tmpRNG = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (tmpRNG == NULL) return ret; - #endif +#endif if (InitRng(tmpRNG) == 0) rng = tmpRNG; @@ -10031,6 +10042,10 @@ int CyaSSL_RAND_bytes(unsigned char* buf, int num) ret = SSL_SUCCESS; } +#ifdef CYASSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; }