From e2379c4956099294994e090b9bede94bbbbdcab1 Mon Sep 17 00:00:00 2001 From: auth12 Date: Thu, 16 Jul 2020 13:37:51 +0100 Subject: Added windows support on client. --- client/wolfssl/src/bio.c | 1705 ++ client/wolfssl/src/crl.c | 1093 + client/wolfssl/src/include.am | 531 + client/wolfssl/src/internal.c | 29412 +++++++++++++++++++++++++ client/wolfssl/src/keys.c | 3607 +++ client/wolfssl/src/ocsp.c | 1100 + client/wolfssl/src/sniffer.c | 4611 ++++ client/wolfssl/src/ssl.c | 47707 ++++++++++++++++++++++++++++++++++++++++ client/wolfssl/src/tls.c | 11755 ++++++++++ client/wolfssl/src/tls13.c | 9048 ++++++++ client/wolfssl/src/wolfio.c | 2375 ++ 11 files changed, 112944 insertions(+) create mode 100644 client/wolfssl/src/bio.c create mode 100644 client/wolfssl/src/crl.c create mode 100644 client/wolfssl/src/include.am create mode 100644 client/wolfssl/src/internal.c create mode 100644 client/wolfssl/src/keys.c create mode 100644 client/wolfssl/src/ocsp.c create mode 100644 client/wolfssl/src/sniffer.c create mode 100644 client/wolfssl/src/ssl.c create mode 100644 client/wolfssl/src/tls.c create mode 100644 client/wolfssl/src/tls13.c create mode 100644 client/wolfssl/src/wolfio.c (limited to 'client/wolfssl/src') diff --git a/client/wolfssl/src/bio.c b/client/wolfssl/src/bio.c new file mode 100644 index 0000000..c134798 --- /dev/null +++ b/client/wolfssl/src/bio.c @@ -0,0 +1,1705 @@ +/* bio.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include + +#if !defined(WOLFSSL_BIO_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning bio.c does not need to be compiled separately from ssl.c + #endif +#else + + +/* Helper function to decode a base64 input + * + * returns size of resulting buffer on success + */ +static int wolfSSL_BIO_BASE64_read(WOLFSSL_BIO* bio, void* buf, int len) +{ + word32 frmtSz = len; + + WOLFSSL_ENTER("wolfSSL_BIO_BASE64_read"); + + if (Base64_Decode((const byte*)buf, (word32)len, (byte*)buf, &frmtSz) !=0) { + WOLFSSL_MSG("Err doing base64 decode"); + return SSL_FATAL_ERROR; + } + + (void)bio; + return (int)frmtSz; +} + + +/* Helper function to read from WOLFSSL_BIO_BIO type + * + * returns amount in bytes read on success + */ +static int wolfSSL_BIO_BIO_read(WOLFSSL_BIO* bio, void* buf, int len) +{ + int sz; + char* pt; + + sz = wolfSSL_BIO_nread(bio, &pt, len); + + if (sz > 0) { + XMEMCPY(buf, pt, sz); + } + + return sz; +} + + +/* Handles reading from a memory type BIO and advancing the state. + * + * bio WOLFSSL_BIO to read from + * buf buffer to put data from bio in + * len amount of data to be read + * + * returns size read on success + */ +static int wolfSSL_BIO_MEMORY_read(WOLFSSL_BIO* bio, void* buf, int len) +{ + int sz; + WOLFSSL_ENTER("wolfSSL_BIO_MEMORY_read"); + + sz = wolfSSL_BIO_pending(bio); + if (sz > 0) { + const unsigned char* pt = NULL; + int memSz; + + if (sz > len) { + sz = len; + } + memSz = wolfSSL_BIO_get_mem_data(bio, (void*)&pt); + if (memSz >= sz && pt != NULL) { + byte* tmp; + + XMEMCPY(buf, (void*)pt, sz); + if (memSz - sz > 0) { + tmp = (byte*)XMALLOC(memSz-sz, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (tmp == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_BIO_ERROR; + } + XMEMCPY(tmp, (void*)(pt + sz), memSz - sz); + + /* reset internal bio->mem */ + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = tmp; + bio->num = memSz-sz; + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + } + bio->wrSz -= sz; + } + else { + WOLFSSL_MSG("Issue with getting bio mem pointer"); + return 0; + } + } + else { + return WOLFSSL_BIO_ERROR; + } + + return sz; +} + +#ifndef WOLFCRYPT_ONLY +/* Helper function to read from WOLFSSL_BIO_SSL type + * + * returns the number of bytes read on success + */ +static int wolfSSL_BIO_SSL_read(WOLFSSL_BIO* bio, void* buf, + int len, WOLFSSL_BIO* front) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_BIO_SSL_read"); + + /* already got eof, again is error */ + if ((front == NULL) || front->eof) + return WOLFSSL_FATAL_ERROR; + + bio->flags &= ~(WOLFSSL_BIO_FLAG_RETRY); /* default no retry */ + ret = wolfSSL_read((WOLFSSL*)bio->ptr, buf, len); + if (ret == 0) + front->eof = 1; + else if (ret < 0) { + int err = wolfSSL_get_error((WOLFSSL*)bio->ptr, 0); + if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) ) { + front->eof = 1; + } + else { + bio->flags |= WOLFSSL_BIO_FLAG_RETRY; /* should retry */ + } + } + + return ret; +} + +static int wolfSSL_BIO_MD_read(WOLFSSL_BIO* bio, void* buf, int sz) +{ + int ret = sz; + + if (wolfSSL_EVP_MD_CTX_type((WOLFSSL_EVP_MD_CTX*)bio->ptr) == NID_hmac) { + if (wolfSSL_EVP_DigestSignUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, buf, + sz) != WOLFSSL_SUCCESS) + { + ret = WOLFSSL_FATAL_ERROR; + } + } + else { + if (wolfSSL_EVP_DigestUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, buf, ret) + != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FATAL_ERROR; + } + } + return ret; +} +#endif /* WOLFCRYPT_ONLY */ + + +/* Used to read data from a WOLFSSL_BIO structure + * + * bio structure to read data from + * buf buffer to hold the result + * len length of buf buffer + * + * returns the number of bytes read on success + */ +int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len) +{ + int ret = 0; + WOLFSSL_BIO* front = bio; + int sz = 0; + + WOLFSSL_ENTER("wolfSSL_BIO_read"); + + /* info cb, abort if user returns <= 0*/ + if (front != NULL && front->infoCb != NULL) { + ret = (int)front->infoCb(front, WOLFSSL_BIO_CB_READ, (const char*)buf, + len, 0, 1); + if (ret <= 0) { + return ret; + } + } + + /* start at end of list and work backwards */ + while ((bio != NULL) && (bio->next != NULL)) { + bio = bio->next; + } + + while (bio != NULL && ret >= 0) { + /* check for custom read */ + if (bio->method && bio->method->readCb) { + ret = bio->method->readCb(bio, (char*)buf, len); + } + + /* formatting data */ + if (bio->type == WOLFSSL_BIO_BASE64 && ret > 0 && sz > 0) { + ret = wolfSSL_BIO_BASE64_read(bio, buf, sz); + } + + /* write BIOs */ + if (bio && bio->type == WOLFSSL_BIO_BIO) { + ret = wolfSSL_BIO_BIO_read(bio, buf, len); + } + + if (bio && bio->type == WOLFSSL_BIO_MEMORY) { + ret = wolfSSL_BIO_MEMORY_read(bio, buf, len); + } + + #ifndef NO_FILESYSTEM + if (bio && bio->type == WOLFSSL_BIO_FILE) { + ret = (int)XFREAD(buf, 1, len, (XFILE)bio->ptr); + } + #endif + + #ifndef WOLFCRYPT_ONLY + if (bio && bio->type == WOLFSSL_BIO_SSL) { + ret = wolfSSL_BIO_SSL_read(bio, buf, len, front); + } + + /* data passing through BIO MD wrapper */ + if (bio && bio->type == WOLFSSL_BIO_MD && ret > 0) { + ret = wolfSSL_BIO_MD_read(bio, buf, ret); + } + #endif + + /* case where front of list is done */ + if (bio == front) { + break; /* at front of list so be done */ + } + + if (ret > 0) { + sz = ret; /* adjust size for formatting */ + } + + /* previous WOLFSSL_BIO in list working towards head of list */ + bio = bio->prev; + } + + /* info cb, user can override return value */ + if (front != NULL && front->infoCb != NULL) { + ret = (int)front->infoCb(front, + WOLFSSL_BIO_CB_READ | WOLFSSL_BIO_CB_RETURN, + (const char*)buf, len, 0, ret); + } + + return ret; +} + + +/* Converts data into base64 output + * + * returns the resulting buffer size on success. + */ +static int wolfSSL_BIO_BASE64_write(WOLFSSL_BIO* bio, const void* data, + word32 inLen, byte* out, word32* outLen) +{ + byte* tmp = NULL; + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_BIO_BASE64_write"); + + if (bio == NULL || data == NULL || out == NULL || outLen == NULL) { + return BAD_FUNC_ARG; + } + +#if defined(WOLFSSL_BASE64_ENCODE) + tmp = (byte*)XMALLOC(*outLen, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + if ((bio->flags & WOLFSSL_BIO_FLAG_BASE64_NO_NL) == + WOLFSSL_BIO_FLAG_BASE64_NO_NL) { + if (Base64_Encode_NoNl((const byte*)data, inLen, + tmp, outLen) < 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } + else { + if (Base64_Encode((const byte*)data, inLen, + tmp, outLen) < 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret != WOLFSSL_FATAL_ERROR) { + ret = (int) inLen; + XMEMCPY(out, tmp, *outLen); + + } + XFREE(tmp, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); +#else + (void)bio; + (void)data; + (void)inLen; + (void)out; + (void)outLen; + (void)tmp; + WOLFSSL_MSG("BASE64 encoding not compiled in"); +#endif + return ret; +} + + +#ifndef WOLFCRYPT_ONLY +/* Helper function for writing to a WOLFSSL_BIO_SSL type + * + * returns the amount written in bytes on success + */ +static int wolfSSL_BIO_SSL_write(WOLFSSL_BIO* bio, const void* data, + int len, WOLFSSL_BIO* front) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_BIO_SSL_write"); + + if (bio->ptr == NULL) { + return BAD_FUNC_ARG; + } + + bio->flags &= ~(WOLFSSL_BIO_FLAG_RETRY); /* default no retry */ + ret = wolfSSL_write((WOLFSSL*)bio->ptr, data, len); + if (ret == 0) + front->eof = 1; + else if (ret < 0) { + int err = wolfSSL_get_error((WOLFSSL*)bio->ptr, 0); + if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) ) { + front->eof = 1; + } + else { + bio->flags |= WOLFSSL_BIO_FLAG_RETRY; /* should retry */ + } + } + return ret; +} +#endif /* WOLFCRYPT_ONLY */ + + +/* Writes to a WOLFSSL_BIO_BIO type. + * + * returns the amount written on success + */ +static int wolfSSL_BIO_BIO_write(WOLFSSL_BIO* bio, const void* data, + int len) +{ + int sz; + char* buf; + + WOLFSSL_ENTER("wolfSSL_BIO_BIO_write"); + + /* adding in sanity checks for static analysis tools */ + if (bio == NULL || data == NULL) { + return BAD_FUNC_ARG; + } + + sz = wolfSSL_BIO_nwrite(bio, &buf, len); + + /* test space for write */ + if (sz <= 0) { + WOLFSSL_MSG("No room left to write"); + return sz; + } + + XMEMCPY(buf, data, sz); + + return sz; +} + + +/* for complete compatibility a bio memory write allocs its own memory + * until the application runs out .... + * + * bio structure to hold incoming data + * data buffer holding the data to be written + * len length of data buffer + * + * returns the amount of data written on success and WOLFSSL_FAILURE or + * WOLFSSL_BIO_ERROR for failure cases. + */ +static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data, + int len) +{ + int sz; + const unsigned char* buf; + + WOLFSSL_ENTER("wolfSSL_BIO_MEMORY_write"); + + if (bio == NULL || data == NULL) { + return BAD_FUNC_ARG; + } + + sz = wolfSSL_BIO_pending(bio); + if (sz < 0) { + WOLFSSL_MSG("Error getting memory data"); + return sz; + } + + if (bio->ptr == NULL) { + bio->ptr = (byte*)XMALLOC(len, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (bio->ptr == NULL) { + WOLFSSL_MSG("Error on malloc"); + return WOLFSSL_FAILURE; + } + bio->num = len; + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + } + + /* check if will fit in current buffer size */ + if (wolfSSL_BIO_get_mem_data(bio, (void*)&buf) < 0) { + return WOLFSSL_BIO_ERROR; + } + if (bio->num < sz + len) { + bio->ptr = (byte*)XREALLOC(bio->ptr, sz + len, bio->heap, + DYNAMIC_TYPE_OPENSSL); + if (bio->ptr == NULL) { + WOLFSSL_MSG("Error on realloc"); + return WOLFSSL_FAILURE; + } + bio->num = sz + len; + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + } + + XMEMCPY((byte*)bio->ptr + sz, data, len); + bio->wrSz += len; + + return len; +} + + +#ifndef WOLFCRYPT_ONLY +/* Helper function for writing to a WOLFSSL_BIO_MD type + * + * returns the amount written in bytes on success (0) + */ +static int wolfSSL_BIO_MD_write(WOLFSSL_BIO* bio, const void* data, int len) +{ + int ret = 0; + + if (bio == NULL || data == NULL) { + return BAD_FUNC_ARG; + } + + if (wolfSSL_EVP_MD_CTX_type((WOLFSSL_EVP_MD_CTX*)bio->ptr) == NID_hmac) { + if (wolfSSL_EVP_DigestSignUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, data, + len) != WOLFSSL_SUCCESS) { + ret = WOLFSSL_BIO_ERROR; + } + } + else { + if (wolfSSL_EVP_DigestUpdate((WOLFSSL_EVP_MD_CTX*)bio->ptr, data, len) + != WOLFSSL_SUCCESS) { + ret = WOLFSSL_BIO_ERROR; + } + } + return ret; +} +#endif /* WOLFCRYPT_ONLY */ + + +/* Writes data to a WOLFSSL_BIO structure + * + * bio structure to write to + * data holds the data to be written + * len length of data buffer + * + * returns the amount written in bytes on success + */ +int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len) +{ + int ret = 0; + int retB64 = 0; + WOLFSSL_BIO* front = bio; + void* frmt = NULL; + word32 frmtSz = 0; + + WOLFSSL_ENTER("wolfSSL_BIO_write"); + + /* info cb, abort if user returns <= 0*/ + if (front != NULL && front->infoCb != NULL) { + ret = (int)front->infoCb(front, WOLFSSL_BIO_CB_WRITE, + (const char*)data, len, 0, 1); + if (ret <= 0) { + return ret; + } + } + + while (bio != NULL && ret >= 0) { + /* check for custom write */ + if (bio->method && bio->method->writeCb) { + ret = bio->method->writeCb(bio, (const char*)data, len); + } + + /* check for formatting */ + if (bio->type == WOLFSSL_BIO_BASE64) { +#if defined(WOLFSSL_BASE64_ENCODE) + word32 sz = 0; + + if (bio->flags & WOLFSSL_BIO_FLAG_BASE64_NO_NL) { + if (Base64_Encode_NoNl((const byte*)data, len, NULL, + &sz) != LENGTH_ONLY_E) { + WOLFSSL_MSG("Error with base 64 get length"); + ret = SSL_FATAL_ERROR; + } + } + else { + if (Base64_Encode((const byte*)data, len, NULL, &sz) != + LENGTH_ONLY_E) { + WOLFSSL_MSG("Error with base 64 get length"); + ret = SSL_FATAL_ERROR; + } + } + + if (frmt == NULL && sz > 0 && ret != SSL_FATAL_ERROR) { + frmt = (void*)XMALLOC(sz, front->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (frmt == NULL) { + WOLFSSL_MSG("Memory error"); + ret = SSL_FATAL_ERROR; + } + frmtSz = sz; + } + else if (sz > frmtSz) { + frmt = (void*)XREALLOC(frmt, sz, front->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (frmt == NULL) { + WOLFSSL_MSG("Memory error"); + ret = SSL_FATAL_ERROR; + } + /* since frmt already existed then data should point to knew + formatted buffer */ + data = frmt; + len = frmtSz; + frmtSz = sz; + } +#endif /* defined(WOLFSSL_BASE64_ENCODE) */ + + if (ret >= 0) { + /* change so that data is formatted buffer */ + retB64 = wolfSSL_BIO_BASE64_write(bio, data, (word32)len, + (byte*)frmt, &frmtSz); + data = frmt; + len = frmtSz; + } + } + + /* write bios */ + if (bio && bio->type == WOLFSSL_BIO_BIO) { + ret = wolfSSL_BIO_BIO_write(bio, data, len); + } + + if (bio && bio->type == WOLFSSL_BIO_MEMORY) { + ret = wolfSSL_BIO_MEMORY_write(bio, data, len); + } + + #ifndef NO_FILESYSTEM + if (bio && bio->type == WOLFSSL_BIO_FILE) { + ret = (int)XFWRITE(data, 1, len, (XFILE)bio->ptr); + } + #endif + + #ifndef WOLFCRYPT_ONLY + if (bio && bio->type == WOLFSSL_BIO_SSL) { + /* already got eof, again is error */ + if (front->eof) { + ret = SSL_FATAL_ERROR; + } + else { + ret = wolfSSL_BIO_SSL_write(bio, data, len, front); + } + } + + if (bio && bio->type == WOLFSSL_BIO_MD) { + if (bio->next != NULL) { /* data passing through MD BIO */ + ret = wolfSSL_BIO_MD_write(bio, data, len); + } + } + #endif /* WOLFCRYPT_ONLY */ + + /* advance to the next bio in list */ + bio = bio->next; + } + + if (frmt != NULL) { + XFREE(frmt, front->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* info cb, user can override return value */ + if (front != NULL && front->infoCb != NULL) { + ret = (int)front->infoCb(front, + WOLFSSL_BIO_CB_WRITE | WOLFSSL_BIO_CB_RETURN, + (const char*)data, 0, 0, ret); + } + + if (retB64 != 0) + return retB64; + else + return ret; +} + + +/* Wrapper for other BIO type functions, expected to grow as OpenSSL compatibility + * layer grows. + * + * return info. specific to the cmd that is passed in. + */ +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) +long wolfSSL_BIO_ctrl(WOLFSSL_BIO *bio, int cmd, long larg, void *parg) +{ + long ret; + + (void)larg; /* not currently used */ + + WOLFSSL_ENTER("wolfSSL_BIO_ctrl"); + + if (bio && bio->method && bio->method->ctrlCb) { + return bio->method->ctrlCb(bio, cmd, larg, parg); + } + + switch(cmd) { + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = (long)wolfSSL_BIO_ctrl_pending(bio); + break; + case BIO_CTRL_INFO: + ret = (long)wolfSSL_BIO_get_mem_data(bio, parg); + break; + case BIO_CTRL_FLUSH: + ret = (long)wolfSSL_BIO_flush(bio); + break; + case BIO_CTRL_RESET: + ret = (long)wolfSSL_BIO_reset(bio); + break; + default: + WOLFSSL_MSG("CMD not yet implemented"); + ret = WOLFSSL_FAILURE; + break; + } + return ret; +} +#endif + + +/* helper function for wolfSSL_BIO_gets + * size till a newline is hit + * returns the number of bytes including the new line character + */ +static int wolfSSL_getLineLength(char* in, int inSz) +{ + int i; + + for (i = 0; i < inSz; i++) { + if (in[i] == '\n') { + return i + 1; /* includes new line character */ + } + } + + return inSz; /* rest of buffer is all one line */ +} + + +/* Gets the next line from bio. Goes until a new line character or end of + * buffer is reached. + * + * bio the structure to read a new line from + * buf buffer to hold the result + * sz the size of "buf" buffer + * + * returns the size of the result placed in buf on success and a 0 or negative + * value in an error case. + */ +int wolfSSL_BIO_gets(WOLFSSL_BIO* bio, char* buf, int sz) +{ + int ret = WOLFSSL_BIO_UNSET; + + WOLFSSL_ENTER("wolfSSL_BIO_gets"); + + if (bio == NULL || buf == NULL) { + return WOLFSSL_FAILURE; + } + + /* not enough space for character plus terminator */ + if (sz <= 1) { + return 0; + } + + /* info cb, abort if user returns <= 0*/ + if (bio->infoCb != NULL) { + ret = (int)bio->infoCb(bio, WOLFSSL_BIO_CB_GETS, buf, sz, 0, 1); + if (ret <= 0) { + return ret; + } + } + + /* check if is custom method */ + if (bio->method && bio->method->getsCb) { + return bio->method->getsCb(bio, buf, sz); + } + + switch (bio->type) { +#ifndef NO_FILESYSTEM + case WOLFSSL_BIO_FILE: + if (((XFILE)bio->ptr) == XBADFILE) { + 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, (XFILE)bio->ptr); + #else + if (XFGETS(buf, sz, (XFILE)bio->ptr) != NULL) { + ret = (int)XSTRLEN(buf); + } + else { + ret = WOLFSSL_BIO_ERROR; + } + #endif + break; +#endif /* NO_FILESYSTEM */ + case WOLFSSL_BIO_MEMORY: + { + const byte* c; + int cSz; + cSz = wolfSSL_BIO_pending(bio); + if (cSz == 0) { + ret = 0; /* Nothing to read */ + buf[0] = '\0'; + break; + } + + if (wolfSSL_BIO_get_mem_data(bio, (void*)&c) <= 0) { + ret = WOLFSSL_BIO_ERROR; + break; + } + + cSz = wolfSSL_getLineLength((char*)c, cSz); + /* check case where line was bigger then buffer and buffer + * needs end terminator */ + 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_MEMORY_read(bio, (void*)buf, cSz); + /* ret is read after the switch statement */ + break; + } + case WOLFSSL_BIO_BIO: + { + char* c; + int cSz; + cSz = wolfSSL_BIO_nread0(bio, &c); + if (cSz == 0) { + ret = 0; /* Nothing to read */ + buf[0] = '\0'; + break; + } + + cSz = wolfSSL_getLineLength(c, cSz); + /* check case where line was bigger then buffer and buffer + * needs end terminator */ + 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) { + XMEMCPY(buf, c, ret); + } + break; + } + +#ifndef WOLFCRYPT_ONLY + /* call final on hash */ + case WOLFSSL_BIO_MD: + if (wolfSSL_EVP_MD_CTX_size((WOLFSSL_EVP_MD_CTX*)bio->ptr) > sz) { + WOLFSSL_MSG("Output buffer was too small for digest"); + ret = WOLFSSL_FAILURE; + } + else { + unsigned int szOut = 0; + ret = wolfSSL_EVP_DigestFinal((WOLFSSL_EVP_MD_CTX*)bio->ptr, + (unsigned char*)buf, &szOut); + if (ret == WOLFSSL_SUCCESS) { + ret = szOut; + } + } + break; +#endif /* WOLFCRYPT_ONLY */ + + default: + WOLFSSL_MSG("BIO type not supported yet with wolfSSL_BIO_gets"); + } + + /* info cb, user can override return value */ + if (bio->infoCb != NULL) { + ret = (int)bio->infoCb(bio, WOLFSSL_BIO_CB_GETS | WOLFSSL_BIO_CB_RETURN, + buf, sz, 0, ret); + } + + return ret; +} + + +/* Writes a null terminated string to bio. + * + * bio the structure to write to + * buf buffer to holding input string + * + * returns the size of the result placed in bio on success and a 0 or negative + * value in an error case. -2 is returned if the implementation is not + * supported for the BIO type. + */ +int wolfSSL_BIO_puts(WOLFSSL_BIO* bio, const char* buf) +{ + int sz; + + if (bio == NULL || buf == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + /* check if is custom method */ + if (bio->method && bio->method->putsCb) { + return bio->method->putsCb(bio, buf); + } + + sz = (int)XSTRLEN(buf); + if (sz <= 0) { + return WOLFSSL_FATAL_ERROR; + } + + return wolfSSL_BIO_write(bio, buf, sz); +} + + +/* searches through bio list for a BIO of type "type" + * returns NULL on failure to find a given type */ +WOLFSSL_BIO* wolfSSL_BIO_find_type(WOLFSSL_BIO* bio, int type) +{ + WOLFSSL_BIO* local = NULL; + WOLFSSL_BIO* current; + + WOLFSSL_ENTER("wolfSSL_BIO_find_type"); + + if (bio == NULL) { + return local; + } + + current = bio; + while (current != NULL) { + if (current->type == type) { + WOLFSSL_MSG("Found matching WOLFSSL_BIO type"); + local = current; + break; + } + current = current->next; + } + + return local; +} + + +/* returns a pointer to the next WOLFSSL_BIO in the chain on success. + * If a failure case then NULL is returned */ +WOLFSSL_BIO* wolfSSL_BIO_next(WOLFSSL_BIO* bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_next"); + + if (bio == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return NULL; + } + + return bio->next; +} + +/* BIO_wpending returns the number of bytes pending to be written. */ +size_t wolfSSL_BIO_wpending(const WOLFSSL_BIO *bio) +{ + WOLFSSL_ENTER("BIO_wpending"); + + if (bio == NULL) + return 0; + + if (bio->type == WOLFSSL_BIO_MEMORY) { + return bio->wrSz; + } + + /* type BIO_BIO then check paired buffer */ + if (bio->type == WOLFSSL_BIO_BIO && bio->pair != NULL) { + WOLFSSL_BIO* pair = bio->pair; + return pair->wrIdx; + } + + return 0; +} + +/* Return the number of pending bytes in read and write buffers */ +size_t wolfSSL_BIO_ctrl_pending(WOLFSSL_BIO *bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_ctrl_pending"); + if (bio == NULL) { + return 0; + } + + if (bio->type == WOLFSSL_BIO_MD) { + /* MD is a wrapper only get next bio */ + while (bio->next != NULL) { + bio = bio->next; + if (bio->type != WOLFSSL_BIO_MD) { + break; + } + } + } + +#ifndef WOLFCRYPT_ONLY + if (bio->type == WOLFSSL_BIO_SSL && bio->ptr != NULL) { + return (long)wolfSSL_pending((WOLFSSL*)bio->ptr); + } +#endif + + if (bio->type == WOLFSSL_BIO_MEMORY) { + return bio->wrSz; + } + + /* type BIO_BIO then check paired buffer */ + if (bio->type == WOLFSSL_BIO_BIO && bio->pair != NULL) { + WOLFSSL_BIO* pair = bio->pair; + if (pair->wrIdx > 0 && pair->wrIdx <= pair->rdIdx) { + /* in wrap around state where beginning of buffer is being + * overwritten */ + return pair->wrSz - pair->rdIdx + pair->wrIdx; + } + else { + /* simple case where has not wrapped around */ + return pair->wrIdx - pair->rdIdx; + } + } + return 0; +} + + +long wolfSSL_BIO_get_mem_ptr(WOLFSSL_BIO *bio, WOLFSSL_BUF_MEM **ptr) +{ + WOLFSSL_BIO* front = bio; + long ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_BIO_get_mem_ptr"); + + if (bio == NULL || ptr == NULL) { + return WOLFSSL_FAILURE; + } + + /* start at end and work backwards to find a memory BIO in the BIO chain */ + while ((bio != NULL) && (bio->next != NULL)) { + bio = bio->next; + } + + while (bio != NULL) { + + if (bio->type == WOLFSSL_BIO_MEMORY) { + *ptr = bio->mem_buf; + ret = WOLFSSL_SUCCESS; + } + + if (bio == front) { + break; + } + bio = bio->prev; + } + + return ret; +} + +WOLFSSL_API long wolfSSL_BIO_int_ctrl(WOLFSSL_BIO *bp, int cmd, long larg, int iarg) +{ + (void) bp; + (void) cmd; + (void) larg; + (void) iarg; + WOLFSSL_STUB("BIO_int_ctrl"); + return 0; +} + + +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 WOLFSSL_FAILURE; + } + + /* if already in pair then do not change size */ + if (bio->pair != NULL) { + WOLFSSL_MSG("WOLFSSL_BIO is paired, free from pair before changing"); + return WOLFSSL_FAILURE; + } + + bio->wrSz = (int)size; + if (bio->wrSz < 0) { + WOLFSSL_MSG("Unexpected negative size value"); + return WOLFSSL_FAILURE; + } + + if (bio->ptr != NULL) { + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + } + + bio->ptr = (byte*)XMALLOC(bio->wrSz, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (bio->ptr == NULL) { + WOLFSSL_MSG("Memory allocation error"); + return WOLFSSL_FAILURE; + } + bio->num = bio->wrSz; + bio->wrIdx = 0; + bio->rdIdx = 0; + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + + return WOLFSSL_SUCCESS; +} + + +/* Joins two BIO_BIO types. The write of b1 goes to the read of b2 and vice + * versa. Creating something similar to a two way pipe. + * Reading and writing between the two BIOs is not thread safe, they are + * expected to be used by the same thread. */ +int wolfSSL_BIO_make_bio_pair(WOLFSSL_BIO *b1, WOLFSSL_BIO *b2) +{ + WOLFSSL_ENTER("wolfSSL_BIO_make_bio_pair"); + + if (b1 == NULL || b2 == NULL) { + WOLFSSL_LEAVE("wolfSSL_BIO_make_bio_pair", BAD_FUNC_ARG); + return WOLFSSL_FAILURE; + } + + /* both are expected to be of type BIO and not already paired */ + if (b1->type != WOLFSSL_BIO_BIO || b2->type != WOLFSSL_BIO_BIO || + b1->pair != NULL || b2->pair != NULL) { + WOLFSSL_MSG("Expected type BIO and not already paired"); + return WOLFSSL_FAILURE; + } + + /* set default write size if not already set */ + if (b1->ptr == NULL && wolfSSL_BIO_set_write_buf_size(b1, + WOLFSSL_BIO_SIZE) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + if (b2->ptr == NULL && wolfSSL_BIO_set_write_buf_size(b2, + WOLFSSL_BIO_SIZE) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + b1->pair = b2; + b2->pair = b1; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_BIO_ctrl_reset_read_request(WOLFSSL_BIO *b) +{ + WOLFSSL_ENTER("wolfSSL_BIO_ctrl_reset_read_request"); + + if (b == NULL || b->type == WOLFSSL_BIO_MEMORY) { + return SSL_FAILURE; + } + + b->readRq = 0; + + return WOLFSSL_SUCCESS; +} + + +/* Does not advance read index pointer */ +int wolfSSL_BIO_nread0(WOLFSSL_BIO *bio, char **buf) +{ + WOLFSSL_ENTER("wolfSSL_BIO_nread0"); + + if (bio == NULL || buf == NULL) { + WOLFSSL_MSG("NULL argument passed in"); + return 0; + } + + /* if paired read from pair */ + if (bio->pair != NULL) { + WOLFSSL_BIO* pair = bio->pair; + + /* case where have wrapped around write buffer */ + *buf = (char*)pair->ptr + pair->rdIdx; + if (pair->wrIdx > 0 && pair->rdIdx >= pair->wrIdx) { + return pair->wrSz - pair->rdIdx; + } + else { + return pair->wrIdx - pair->rdIdx; + } + } + + return 0; +} + + +/* similar to wolfSSL_BIO_nread0 but advances the read index */ +int wolfSSL_BIO_nread(WOLFSSL_BIO *bio, char **buf, int num) +{ + int sz = WOLFSSL_BIO_UNSET; + + WOLFSSL_ENTER("wolfSSL_BIO_nread"); + + if (bio == NULL || buf == NULL) { + WOLFSSL_MSG("NULL argument passed in"); + 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) { + *buf = (char*)bio->pair->ptr + bio->pair->rdIdx; + return 0; + } + + /* get amount able to read and set buffer pointer */ + sz = wolfSSL_BIO_nread0(bio, buf); + if (sz == 0) { + return WOLFSSL_BIO_ERROR; + } + + if (num < sz) { + sz = num; + } + bio->pair->rdIdx += sz; + + /* check if have read to the end of the buffer and need to reset */ + if (bio->pair->rdIdx == bio->pair->wrSz) { + bio->pair->rdIdx = 0; + if (bio->pair->wrIdx == bio->pair->wrSz) { + bio->pair->wrIdx = 0; + } + } + + /* check if read up to write index, if so then reset index */ + if (bio->pair->rdIdx == bio->pair->wrIdx) { + bio->pair->rdIdx = 0; + bio->pair->wrIdx = 0; + } + } + + return sz; +} + + +int wolfSSL_BIO_nwrite(WOLFSSL_BIO *bio, char **buf, int num) +{ + int sz = WOLFSSL_BIO_UNSET; + + WOLFSSL_ENTER("wolfSSL_BIO_nwrite"); + + if (bio == NULL || buf == NULL) { + WOLFSSL_MSG("NULL argument passed in"); + return 0; + } + + if (bio->type != WOLFSSL_BIO_BIO) { + return SSL_FAILURE; + } + + if (bio->pair != NULL) { + if (num == 0) { + *buf = (char*)bio->ptr + bio->wrIdx; + return 0; + } + + if (bio->wrIdx < bio->rdIdx) { + /* if wrapped around only write up to read index. In this case + * rdIdx is always greater then wrIdx so sz will not be negative. */ + sz = bio->rdIdx - bio->wrIdx; + } + else if (bio->rdIdx > 0 && bio->wrIdx == bio->rdIdx) { + return WOLFSSL_BIO_ERROR; /* no more room to write */ + } + else { + /* write index is past read index so write to end of buffer */ + sz = bio->wrSz - bio->wrIdx; + + if (sz <= 0) { + /* either an error has occurred with write index or it is at the + * end of the write buffer. */ + if (bio->rdIdx == 0) { + /* no more room, nothing has been read */ + return WOLFSSL_BIO_ERROR; + } + + bio->wrIdx = 0; + + /* check case where read index is not at 0 */ + if (bio->rdIdx > 0) { + sz = bio->rdIdx; /* can write up to the read index */ + } + else { + sz = bio->wrSz; /* no restriction other then buffer size */ + } + } + } + + if (num < sz) { + sz = num; + } + *buf = (char*)bio->ptr + bio->wrIdx; + bio->wrIdx += sz; + + /* if at the end of the buffer and space for wrap around then set + * write index back to 0 */ + if (bio->wrIdx == bio->wrSz && bio->rdIdx > 0) { + bio->wrIdx = 0; + } + } + + return sz; +} + + +/* Reset BIO to initial state */ +int wolfSSL_BIO_reset(WOLFSSL_BIO *bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_reset"); + + if (bio == NULL) { + WOLFSSL_MSG("NULL argument passed in"); + /* -1 is consistent failure even for FILE type */ + return WOLFSSL_BIO_ERROR; + } + + switch (bio->type) { + #ifndef NO_FILESYSTEM + case WOLFSSL_BIO_FILE: + XREWIND((XFILE)bio->ptr); + return 0; + #endif + + case WOLFSSL_BIO_BIO: + bio->rdIdx = 0; + bio->wrIdx = 0; + return 0; + + case WOLFSSL_BIO_MEMORY: + bio->rdIdx = 0; + bio->wrIdx = 0; + bio->wrSz = 0; + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = NULL; + bio->num = 0; + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + return 0; + +#ifndef WOLFCRYPT_ONLY + case WOLFSSL_BIO_MD: + if (bio->ptr != NULL) { + const WOLFSSL_EVP_MD* md = + wolfSSL_EVP_MD_CTX_md((WOLFSSL_EVP_MD_CTX*)bio->ptr); + wolfSSL_EVP_MD_CTX_init((WOLFSSL_EVP_MD_CTX*)bio->ptr); + wolfSSL_EVP_DigestInit((WOLFSSL_EVP_MD_CTX*)bio->ptr, md); + } + return 0; +#endif /* WOLFCRYPT_ONLY */ + + default: + WOLFSSL_MSG("Unknown BIO type needs added to reset function"); + } + + return WOLFSSL_BIO_ERROR; +} + +#ifndef NO_FILESYSTEM +long wolfSSL_BIO_set_fp(WOLFSSL_BIO *bio, XFILE fp, int c) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_fp"); + + if (bio == NULL || fp == XBADFILE) { + WOLFSSL_LEAVE("wolfSSL_BIO_set_fp", BAD_FUNC_ARG); + return WOLFSSL_FAILURE; + } + + if (bio->type != WOLFSSL_BIO_FILE) { + return WOLFSSL_FAILURE; + } + + bio->shutdown = (byte)c; + bio->ptr = (XFILE)fp; + + return WOLFSSL_SUCCESS; +} + + +long wolfSSL_BIO_get_fp(WOLFSSL_BIO *bio, XFILE* fp) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_fp"); + + if (bio == NULL || fp == XBADFILE) { + return WOLFSSL_FAILURE; + } + + if (bio->type != WOLFSSL_BIO_FILE) { + return SSL_FAILURE; + } + + *fp = (XFILE)bio->ptr; + + return WOLFSSL_SUCCESS; +} + +/* overwrites file */ +int wolfSSL_BIO_write_filename(WOLFSSL_BIO *bio, char *name) +{ + WOLFSSL_ENTER("wolfSSL_BIO_write_filename"); + + if (bio == NULL || name == NULL) { + return WOLFSSL_FAILURE; + } + + if (bio->type == WOLFSSL_BIO_FILE) { + if (((XFILE)bio->ptr) != XBADFILE && bio->shutdown == BIO_CLOSE) { + XFCLOSE((XFILE)bio->ptr); + } + + bio->ptr = XFOPEN(name, "w"); + if (((XFILE)bio->ptr) == XBADFILE) { + return WOLFSSL_FAILURE; + } + bio->shutdown = BIO_CLOSE; + + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_seek(WOLFSSL_BIO *bio, int ofs) +{ + WOLFSSL_ENTER("wolfSSL_BIO_seek"); + + if (bio == NULL) { + return -1; + } + + /* offset ofs from beginning of file */ + if (bio->type == WOLFSSL_BIO_FILE && + XFSEEK((XFILE)bio->ptr, ofs, SEEK_SET) < 0) { + return -1; + } + + return 0; +} +#endif /* NO_FILESYSTEM */ + + +long wolfSSL_BIO_set_mem_eof_return(WOLFSSL_BIO *bio, int v) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_mem_eof_return"); + + if (bio != NULL) { + bio->eof = v; + } + + return 0; +} + +int wolfSSL_BIO_get_len(WOLFSSL_BIO *bio) +{ + int len; +#ifndef NO_FILESYSTEM + long memSz = 0, curr = 0; + XFILE file; +#endif + + WOLFSSL_ENTER("wolfSSL_BIO_get_len"); + + if ((len = wolfSSL_BIO_pending(bio)) > 0) { + } +#ifndef NO_FILESYSTEM + else if (bio->type == WOLFSSL_BIO_FILE) { + if (wolfSSL_BIO_get_fp(bio, &file) != WOLFSSL_SUCCESS) + len = BAD_FUNC_ARG; + if (len == 0) { + curr = XFTELL(file); + if (curr < 0) { + len = WOLFSSL_BAD_FILE; + } + if (XFSEEK(file, 0, XSEEK_END) != 0) + len = WOLFSSL_BAD_FILE; + } + if (len == 0) { + memSz = XFTELL(file); + if (memSz > MAX_WOLFSSL_FILE_SIZE || memSz < 0) + len = WOLFSSL_BAD_FILE; + } + if (len == 0) { + memSz -= curr; + len = (int)memSz; + if (XFSEEK(file, curr, SEEK_SET) != 0) + len = WOLFSSL_BAD_FILE; + } + } +#endif + return len; +} + + +void wolfSSL_BIO_set_callback(WOLFSSL_BIO *bio, wolf_bio_info_cb callback_func) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_callback"); + + if (bio != NULL) { + bio->infoCb = callback_func; + } +} + + +wolf_bio_info_cb wolfSSL_BIO_get_callback(WOLFSSL_BIO *bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_callback"); + + if (bio != NULL) { + return bio->infoCb; + } + + return NULL; +} + + +void wolfSSL_BIO_set_callback_arg(WOLFSSL_BIO *bio, char *arg) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_callback_arg"); + + if (bio != NULL) { + bio->infoArg = arg; + } +} + + +char* wolfSSL_BIO_get_callback_arg(const WOLFSSL_BIO *bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_callback_arg"); + + if (bio != NULL) { + return bio->infoArg; + } + + return NULL; +} + + +/* store a user pointer in the WOLFSSL_BIO structure */ +void wolfSSL_BIO_set_data(WOLFSSL_BIO* bio, void *ptr) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_data"); + + if (bio != NULL) { + bio->usrCtx = ptr; + } +} + + +void* wolfSSL_BIO_get_data(WOLFSSL_BIO* bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_data"); + + if (bio != NULL) + return bio->usrCtx; + + WOLFSSL_MSG("WOLFSSL_BIO was null"); + return NULL; +} + +/* If flag is 0 then blocking is set, if 1 then non blocking. + * Always returns 1 + */ +long wolfSSL_BIO_set_nbio(WOLFSSL_BIO* bio, long on) +{ + #ifndef WOLFSSL_DTLS + (void)on; + #endif + WOLFSSL_ENTER("wolfSSL_BIO_set_nbio"); + + switch (bio->type) { + case WOLFSSL_BIO_SOCKET: + #ifdef XFCNTL + { + int flag = XFCNTL(bio->num, F_GETFL, 0); + if (on) + XFCNTL(bio->num, F_SETFL, flag | O_NONBLOCK); + else + XFCNTL(bio->num, F_SETFL, flag & ~O_NONBLOCK); + } + #endif + break; + case WOLFSSL_BIO_SSL: + #ifdef WOLFSSL_DTLS + wolfSSL_dtls_set_using_nonblock((WOLFSSL*)bio->ptr, (int)on); + #endif + break; + + default: + WOLFSSL_MSG("Unsupported bio type for non blocking"); + break; + } + + return 1; +} + + + +/* creates a new custom WOLFSSL_BIO_METHOD */ +WOLFSSL_BIO_METHOD *wolfSSL_BIO_meth_new(int type, const char *name) +{ + WOLFSSL_BIO_METHOD* meth; + + WOLFSSL_ENTER("wolfSSL_BIO_meth_new"); + + meth = (WOLFSSL_BIO_METHOD*)XMALLOC(sizeof(WOLFSSL_BIO_METHOD), NULL, + DYNAMIC_TYPE_OPENSSL); + if (meth == NULL) { + WOLFSSL_MSG("Error allocating memory for WOLFSSL_BIO_METHOD"); + return NULL; + } + XMEMSET(meth, 0, sizeof(WOLFSSL_BIO_METHOD)); + meth->type = (byte)type; + XSTRNCPY(meth->name, name, MAX_BIO_METHOD_NAME - 1); + + return meth; +} + + +void wolfSSL_BIO_meth_free(WOLFSSL_BIO_METHOD *biom) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_free"); + if (biom) { + XFREE(biom, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + + +int wolfSSL_BIO_meth_set_write(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_write_cb biom_write) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_set_write"); + if (biom) { + biom->writeCb = biom_write; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_meth_set_read(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_read_cb biom_read) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_set_read"); + if (biom) { + biom->readCb = biom_read; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_meth_set_puts(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_puts_cb biom_puts) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_set_puts"); + if (biom) { + biom->putsCb = biom_puts; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_meth_set_gets(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_gets_cb biom_gets) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_set_gets"); + if (biom) { + biom->getsCb = biom_gets; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_meth_set_ctrl(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_ctrl_get_cb biom_ctrl) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_set_ctrl"); + if (biom) { + biom->ctrlCb = biom_ctrl; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_meth_set_create(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_create_cb biom_create) +{ + WOLFSSL_ENTER("wolfSSL_BIO_meth_set_create"); + if (biom) { + biom->createCb = biom_create; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_BIO_meth_set_destroy(WOLFSSL_BIO_METHOD *biom, + wolfSSL_BIO_meth_destroy_cb biom_destroy) +{ + WOLFSSL_STUB("wolfSSL_BIO_meth_set_destroy"); + if (biom) { + biom->freeCb = biom_destroy; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + + +/* this compatibility function can be used for multiple BIO types */ +int wolfSSL_BIO_get_mem_data(WOLFSSL_BIO* bio, void* p) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_mem_data"); + + if (bio == NULL) + return WOLFSSL_FATAL_ERROR; + + if (p) { + *(byte**)p = (byte*)bio->ptr; + } + + return bio->num; +} + +int wolfSSL_BIO_pending(WOLFSSL_BIO* bio) +{ + return (int)wolfSSL_BIO_ctrl_pending(bio); +} + + +int wolfSSL_BIO_flush(WOLFSSL_BIO* bio) +{ + /* for wolfSSL no flushing needed */ + WOLFSSL_ENTER("BIO_flush"); + (void)bio; + return 1; +} +#endif /* WOLFSSL_BIO_INCLUDED */ diff --git a/client/wolfssl/src/crl.c b/client/wolfssl/src/crl.c new file mode 100644 index 0000000..a48cf9d --- /dev/null +++ b/client/wolfssl/src/crl.c @@ -0,0 +1,1093 @@ +/* crl.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + /* Name change compatibility layer no longer needs included here */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY +#ifdef HAVE_CRL + +#include +#include + +#include + +#ifdef HAVE_CRL_MONITOR + #if (defined(__MACH__) || defined(__FreeBSD__) || defined(__linux__)) + static int StopMonitor(int mfd); + #else + #error "CRL monitor only currently supported on linux or mach" + #endif +#endif /* HAVE_CRL_MONITOR */ + + +/* Initialize CRL members */ +int InitCRL(WOLFSSL_CRL* crl, WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("InitCRL"); + if(cm != NULL) + crl->heap = cm->heap; + else + crl->heap = NULL; + crl->cm = cm; + crl->crlList = NULL; + crl->monitors[0].path = NULL; + crl->monitors[1].path = NULL; +#ifdef HAVE_CRL_MONITOR + crl->tid = 0; + crl->mfd = -1; /* mfd for bsd is kqueue fd, eventfd for linux */ + crl->setup = 0; /* thread setup done predicate */ + if (pthread_cond_init(&crl->cond, 0) != 0) { + WOLFSSL_MSG("Pthread condition init failed"); + return BAD_COND_E; + } +#endif + if (wc_InitMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("Init Mutex failed"); + return BAD_MUTEX_E; + } + + return 0; +} + + +/* Initialize CRL Entry */ +static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl, const byte* buff, + int verified, void* heap) +{ + WOLFSSL_ENTER("InitCRL_Entry"); + + XMEMCPY(crle->issuerHash, dcrl->issuerHash, CRL_DIGEST_SIZE); + /* XMEMCPY(crle->crlHash, dcrl->crlHash, CRL_DIGEST_SIZE); + * copy the hash here if needed for optimized comparisons */ + XMEMCPY(crle->lastDate, dcrl->lastDate, MAX_DATE_SIZE); + XMEMCPY(crle->nextDate, dcrl->nextDate, MAX_DATE_SIZE); + crle->lastDateFormat = dcrl->lastDateFormat; + crle->nextDateFormat = dcrl->nextDateFormat; + + crle->certs = dcrl->certs; /* take ownsership */ + dcrl->certs = NULL; + crle->totalCerts = dcrl->totalCerts; + crle->verified = verified; + if (!verified) { + crle->tbsSz = dcrl->sigIndex - dcrl->certBegin; + crle->signatureSz = dcrl->sigLength; + crle->signatureOID = dcrl->signatureOID; + crle->toBeSigned = (byte*)XMALLOC(crle->tbsSz, heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (crle->toBeSigned == NULL) + return -1; + crle->signature = (byte*)XMALLOC(crle->signatureSz, heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (crle->signature == NULL) { + XFREE(crle->toBeSigned, heap, DYNAMIC_TYPE_CRL_ENTRY); + return -1; + } + XMEMCPY(crle->toBeSigned, buff + dcrl->certBegin, crle->tbsSz); + XMEMCPY(crle->signature, dcrl->signature, crle->signatureSz); + #ifndef NO_SKID + crle->extAuthKeyIdSet = dcrl->extAuthKeyIdSet; + if (crle->extAuthKeyIdSet) + XMEMCPY(crle->extAuthKeyId, dcrl->extAuthKeyId, KEYID_SIZE); + #endif + } + else { + crle->toBeSigned = NULL; + crle->signature = NULL; + } + + (void)verified; + (void)heap; + + return 0; +} + + +/* Free all CRL Entry resources */ +static void FreeCRL_Entry(CRL_Entry* crle, void* heap) +{ + RevokedCert* tmp = crle->certs; + RevokedCert* next; + + WOLFSSL_ENTER("FreeCRL_Entry"); + + while (tmp) { + next = tmp->next; + XFREE(tmp, heap, DYNAMIC_TYPE_REVOKED); + tmp = next; + } + if (crle->signature != NULL) + XFREE(crle->signature, heap, DYNAMIC_TYPE_REVOKED); + if (crle->toBeSigned != NULL) + XFREE(crle->toBeSigned, heap, DYNAMIC_TYPE_REVOKED); + + (void)heap; +} + + + +/* Free all CRL resources */ +void FreeCRL(WOLFSSL_CRL* crl, int dynamic) +{ + CRL_Entry* tmp = crl->crlList; + + WOLFSSL_ENTER("FreeCRL"); + if (crl->monitors[0].path) + XFREE(crl->monitors[0].path, crl->heap, DYNAMIC_TYPE_CRL_MONITOR); + + if (crl->monitors[1].path) + XFREE(crl->monitors[1].path, crl->heap, DYNAMIC_TYPE_CRL_MONITOR); + + while(tmp) { + CRL_Entry* next = tmp->next; + FreeCRL_Entry(tmp, crl->heap); + XFREE(tmp, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + tmp = next; + } + +#ifdef HAVE_CRL_MONITOR + if (crl->tid != 0) { + WOLFSSL_MSG("stopping monitor thread"); + if (StopMonitor(crl->mfd) == 0) + pthread_join(crl->tid, NULL); + else { + WOLFSSL_MSG("stop monitor failed"); + } + } + pthread_cond_destroy(&crl->cond); +#endif + wc_FreeMutex(&crl->crlLock); + if (dynamic) /* free self */ + XFREE(crl, crl->heap, DYNAMIC_TYPE_CRL); +} + + +static int CheckCertCRLList(WOLFSSL_CRL* crl, DecodedCert* cert, int *pFoundEntry) +{ + CRL_Entry* crle; + int foundEntry = 0; + int ret = 0; + + if (wc_LockMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockMutex failed"); + return BAD_MUTEX_E; + } + + crle = crl->crlList; + + while (crle) { + if (XMEMCMP(crle->issuerHash, cert->issuerHash, CRL_DIGEST_SIZE) == 0) { + WOLFSSL_MSG("Found CRL Entry on list"); + + if (crle->verified == 0) { + Signer* ca = NULL; + #ifndef NO_SKID + byte extAuthKeyId[KEYID_SIZE]; + #endif + byte issuerHash[CRL_DIGEST_SIZE]; + byte* tbs; + word32 tbsSz = crle->tbsSz; + byte* sig = NULL; + word32 sigSz = crle->signatureSz; + word32 sigOID = crle->signatureOID; + SignatureCtx sigCtx; + + tbs = (byte*)XMALLOC(tbsSz, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + if (tbs == NULL) { + wc_UnLockMutex(&crl->crlLock); + return MEMORY_E; + } + sig = (byte*)XMALLOC(sigSz, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + if (sig == NULL) { + XFREE(tbs, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + wc_UnLockMutex(&crl->crlLock); + return MEMORY_E; + } + + XMEMCPY(tbs, crle->toBeSigned, tbsSz); + XMEMCPY(sig, crle->signature, sigSz); + #ifndef NO_SKID + XMEMCPY(extAuthKeyId, crle->extAuthKeyId, + sizeof(extAuthKeyId)); + #endif + XMEMCPY(issuerHash, crle->issuerHash, sizeof(issuerHash)); + + wc_UnLockMutex(&crl->crlLock); + + #ifndef NO_SKID + if (crle->extAuthKeyIdSet) + ca = GetCA(crl->cm, extAuthKeyId); + if (ca == NULL) + ca = GetCAByName(crl->cm, issuerHash); + #else /* NO_SKID */ + ca = GetCA(crl->cm, issuerHash); + #endif /* NO_SKID */ + if (ca == NULL) { + XFREE(sig, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + XFREE(tbs, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + WOLFSSL_MSG("Did NOT find CRL issuer CA"); + return ASN_CRL_NO_SIGNER_E; + } + + ret = VerifyCRL_Signature(&sigCtx, tbs, tbsSz, sig, sigSz, + sigOID, ca, crl->heap); + + XFREE(sig, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + XFREE(tbs, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + + if (wc_LockMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockMutex failed"); + return BAD_MUTEX_E; + } + + crle = crl->crlList; + while (crle) { + if (XMEMCMP(crle->issuerHash, cert->issuerHash, + CRL_DIGEST_SIZE) == 0) { + + if (ret == 0) + crle->verified = 1; + else + crle->verified = ret; + + XFREE(crle->toBeSigned, crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + crle->toBeSigned = NULL; + XFREE(crle->signature, crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + crle->signature = NULL; + break; + } + crle = crle->next; + } + if (crle == NULL || crle->verified < 0) + break; + } + else if (crle->verified < 0) { + WOLFSSL_MSG("Cannot use CRL as it didn't verify"); + ret = crle->verified; + break; + } + + WOLFSSL_MSG("Checking next date validity"); + + #ifdef WOLFSSL_NO_CRL_NEXT_DATE + if (crle->nextDateFormat != ASN_OTHER_TYPE) + #endif + { + #ifndef NO_ASN_TIME + if (!XVALIDATE_DATE(crle->nextDate,crle->nextDateFormat, AFTER)) { + WOLFSSL_MSG("CRL next date is no longer valid"); + ret = ASN_AFTER_DATE_E; + } + #endif + } + if (ret == 0) { + foundEntry = 1; + } + break; + } + crle = crle->next; + } + + if (foundEntry) { + RevokedCert* rc = crle->certs; + + while (rc) { + if (rc->serialSz == cert->serialSz && + XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) { + WOLFSSL_MSG("Cert revoked"); + ret = CRL_CERT_REVOKED; + break; + } + rc = rc->next; + } + } + + wc_UnLockMutex(&crl->crlLock); + + *pFoundEntry = foundEntry; + + return ret; +} + +/* Is the cert ok with CRL, return 0 on success */ +int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert) +{ + int foundEntry = 0; + int ret = 0; + + WOLFSSL_ENTER("CheckCertCRL"); + + ret = CheckCertCRLList(crl, cert, &foundEntry); + +#ifdef HAVE_CRL_IO + if (foundEntry == 0) { + /* perform embedded lookup */ + if (crl->crlIOCb) { + ret = crl->crlIOCb(crl, (const char*)cert->extCrlInfo, + cert->extCrlInfoSz); + if (ret == WOLFSSL_CBIO_ERR_WANT_READ) { + ret = WANT_READ; + } + else if (ret >= 0) { + /* try again */ + ret = CheckCertCRLList(crl, cert, &foundEntry); + } + } + } +#endif + + if (foundEntry == 0) { + WOLFSSL_MSG("Couldn't find CRL for status check"); + ret = CRL_MISSING; + + if (crl->cm->cbMissingCRL) { + char url[256]; + + WOLFSSL_MSG("Issuing missing CRL callback"); + url[0] = '\0'; + if (cert->extCrlInfo) { + if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) { + XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz); + url[cert->extCrlInfoSz] = '\0'; + } + else { + WOLFSSL_MSG("CRL url too long"); + } + } + + crl->cm->cbMissingCRL(url); + } + } + + return ret; +} + + +/* Add Decoded CRL, 0 on success */ +static int AddCRL(WOLFSSL_CRL* crl, DecodedCRL* dcrl, const byte* buff, + int verified) +{ + CRL_Entry* crle; + + WOLFSSL_ENTER("AddCRL"); + + crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + if (crle == NULL) { + WOLFSSL_MSG("alloc CRL Entry failed"); + return -1; + } + + if (InitCRL_Entry(crle, dcrl, buff, verified, crl->heap) < 0) { + WOLFSSL_MSG("Init CRL Entry failed"); + XFREE(crle, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + return -1; + } + + if (wc_LockMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockMutex failed"); + FreeCRL_Entry(crle, crl->heap); + XFREE(crle, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + return BAD_MUTEX_E; + } + crle->next = crl->crlList; + crl->crlList = crle; + wc_UnLockMutex(&crl->crlLock); + + return 0; +} + + +/* Load CRL File of type, WOLFSSL_SUCCESS on ok */ +int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type, + int verify) +{ + int ret = WOLFSSL_SUCCESS; + const byte* myBuffer = buff; /* if DER ok, otherwise switch */ + DerBuffer* der = NULL; +#ifdef WOLFSSL_SMALL_STACK + DecodedCRL* dcrl; +#else + DecodedCRL dcrl[1]; +#endif + + WOLFSSL_ENTER("BufferLoadCRL"); + + if (crl == NULL || buff == NULL || sz == 0) + return BAD_FUNC_ARG; + + if (type == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, NULL, NULL); + if (ret == 0) { + myBuffer = der->buffer; + sz = der->length; + } + else { + WOLFSSL_MSG("Pem to Der failed"); + FreeDer(&der); + return -1; + } + #else + ret = NOT_COMPILED_IN; + #endif + } + +#ifdef WOLFSSL_SMALL_STACK + dcrl = (DecodedCRL*)XMALLOC(sizeof(DecodedCRL), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (dcrl == NULL) { + FreeDer(&der); + return MEMORY_E; + } +#endif + + InitDecodedCRL(dcrl, crl->heap); + ret = ParseCRL(dcrl, myBuffer, (word32)sz, crl->cm); + if (ret != 0 && !(ret == ASN_CRL_NO_SIGNER_E && verify == NO_VERIFY)) { + WOLFSSL_MSG("ParseCRL error"); + } + else { + ret = AddCRL(crl, dcrl, myBuffer, ret != ASN_CRL_NO_SIGNER_E); + if (ret != 0) { + WOLFSSL_MSG("AddCRL error"); + } + } + + FreeDecodedCRL(dcrl); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(dcrl, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + FreeDer(&der); + + return ret ? ret : WOLFSSL_SUCCESS; /* convert 0 to WOLFSSL_SUCCESS */ +} + +#if defined(OPENSSL_EXTRA) && defined(HAVE_CRL) +int wolfSSL_X509_STORE_add_crl(WOLFSSL_X509_STORE *store, WOLFSSL_X509_CRL *newcrl) +{ + CRL_Entry *crle; + WOLFSSL_CRL *crl; + + WOLFSSL_ENTER("wolfSSL_X509_STORE_add_crl"); + if (store == NULL || newcrl == NULL) + return BAD_FUNC_ARG; + + crl = store->crl; + crle = newcrl->crlList; + + if (wc_LockMutex(&crl->crlLock) != 0) + { + WOLFSSL_MSG("wc_LockMutex failed"); + return BAD_MUTEX_E; + } + crle->next = crl->crlList; + crl->crlList = crle; + newcrl->crlList = NULL; + wc_UnLockMutex(&crl->crlLock); + + WOLFSSL_LEAVE("wolfSSL_X509_STORE_add_crl", WOLFSSL_SUCCESS); + + return WOLFSSL_SUCCESS; +} +#endif + +#ifdef HAVE_CRL_MONITOR + + +/* Signal Monitor thread is setup, save status to setup flag, 0 on success */ +static int SignalSetup(WOLFSSL_CRL* crl, int status) +{ + int ret; + + /* signal to calling thread we're setup */ + if (wc_LockMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockMutex crlLock failed"); + return BAD_MUTEX_E; + } + + crl->setup = status; + ret = pthread_cond_signal(&crl->cond); + + wc_UnLockMutex(&crl->crlLock); + + if (ret != 0) + return BAD_COND_E; + + return 0; +} + + +/* read in new CRL entries and save new list */ +static int SwapLists(WOLFSSL_CRL* crl) +{ + int ret; + CRL_Entry* newList; +#ifdef WOLFSSL_SMALL_STACK + WOLFSSL_CRL* tmp; +#else + WOLFSSL_CRL tmp[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + tmp = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) + return MEMORY_E; +#endif + + if (InitCRL(tmp, crl->cm) < 0) { + WOLFSSL_MSG("Init tmp CRL failed"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return -1; + } + + if (crl->monitors[0].path) { + ret = LoadCRL(tmp, crl->monitors[0].path, WOLFSSL_FILETYPE_PEM, 0); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("PEM LoadCRL on dir change failed"); + FreeCRL(tmp, 0); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return -1; + } + } + + if (crl->monitors[1].path) { + ret = LoadCRL(tmp, crl->monitors[1].path, WOLFSSL_FILETYPE_ASN1, 0); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("DER LoadCRL on dir change failed"); + FreeCRL(tmp, 0); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return -1; + } + } + + if (wc_LockMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockMutex failed"); + FreeCRL(tmp, 0); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return -1; + } + + newList = tmp->crlList; + + /* swap lists */ + tmp->crlList = crl->crlList; + crl->crlList = newList; + + wc_UnLockMutex(&crl->crlLock); + + FreeCRL(tmp, 0); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return 0; +} + + +#if (defined(__MACH__) || defined(__FreeBSD__)) + +#include +#include +#include +#include +#include + +#ifdef __MACH__ + #define XEVENT_MODE O_EVTONLY +#elif defined(__FreeBSD__) + #define XEVENT_MODE EVFILT_VNODE +#endif + + +/* we need a unique kqueue user filter fd for crl in case user is doing custom + * events too */ +#ifndef CRL_CUSTOM_FD + #define CRL_CUSTOM_FD 123456 +#endif + + +/* shutdown monitor thread, 0 on success */ +static int StopMonitor(int mfd) +{ + struct kevent change; + + /* trigger custom shutdown */ + EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); + if (kevent(mfd, &change, 1, NULL, 0, NULL) < 0) { + WOLFSSL_MSG("kevent trigger customer event failed"); + return -1; + } + + return 0; +} + + +/* OS X monitoring */ +static void* DoMonitor(void* arg) +{ + int fPEM, fDER; + struct kevent change; + + WOLFSSL_CRL* crl = (WOLFSSL_CRL*)arg; + + WOLFSSL_ENTER("DoMonitor"); + + crl->mfd = kqueue(); + if (crl->mfd == -1) { + WOLFSSL_MSG("kqueue failed"); + SignalSetup(crl, MONITOR_SETUP_E); + return NULL; + } + + /* listen for custom shutdown event */ + EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, EV_ADD, 0, 0, NULL); + if (kevent(crl->mfd, &change, 1, NULL, 0, NULL) < 0) { + WOLFSSL_MSG("kevent monitor customer event failed"); + SignalSetup(crl, MONITOR_SETUP_E); + close(crl->mfd); + return NULL; + } + + fPEM = -1; + fDER = -1; + + if (crl->monitors[0].path) { + fPEM = open(crl->monitors[0].path, XEVENT_MODE); + if (fPEM == -1) { + WOLFSSL_MSG("PEM event dir open failed"); + SignalSetup(crl, MONITOR_SETUP_E); + close(crl->mfd); + return NULL; + } + } + + if (crl->monitors[1].path) { + fDER = open(crl->monitors[1].path, XEVENT_MODE); + if (fDER == -1) { + WOLFSSL_MSG("DER event dir open failed"); + if (fPEM != -1) + close(fPEM); + close(crl->mfd); + SignalSetup(crl, MONITOR_SETUP_E); + return NULL; + } + } + + if (fPEM != -1) + EV_SET(&change, fPEM, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, + NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0); + + if (fDER != -1) + EV_SET(&change, fDER, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, + NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0); + + /* signal to calling thread we're setup */ + if (SignalSetup(crl, 1) != 0) { + if (fPEM != -1) + close(fPEM); + if (fDER != -1) + close(fDER); + close(crl->mfd); + return NULL; + } + + for (;;) { + struct kevent event; + int numEvents = kevent(crl->mfd, &change, 1, &event, 1, NULL); + + WOLFSSL_MSG("Got kevent"); + + if (numEvents == -1) { + WOLFSSL_MSG("kevent problem, continue"); + continue; + } + + if (event.filter == EVFILT_USER) { + WOLFSSL_MSG("Got user shutdown event, breaking out"); + break; + } + + if (SwapLists(crl) < 0) { + WOLFSSL_MSG("SwapLists problem, continue"); + } + } + + if (fPEM != -1) + close(fPEM); + if (fDER != -1) + close(fDER); + + close(crl->mfd); + + return NULL; +} + + +#elif defined(__linux__) + +#include +#include +#include +#include + + +#ifndef max + static WC_INLINE int max(int a, int b) + { + return a > b ? a : b; + } +#endif /* max */ + + +/* shutdown monitor thread, 0 on success */ +static int StopMonitor(int mfd) +{ + word64 w64 = 1; + + /* write to our custom event */ + if (write(mfd, &w64, sizeof(w64)) < 0) { + WOLFSSL_MSG("StopMonitor write failed"); + return -1; + } + + return 0; +} + + +/* linux monitoring */ +static void* DoMonitor(void* arg) +{ + int notifyFd; + int wd = -1; + WOLFSSL_CRL* crl = (WOLFSSL_CRL*)arg; +#ifdef WOLFSSL_SMALL_STACK + char* buff; +#else + char buff[8192]; +#endif + + WOLFSSL_ENTER("DoMonitor"); + + crl->mfd = eventfd(0, 0); /* our custom shutdown event */ + if (crl->mfd < 0) { + WOLFSSL_MSG("eventfd failed"); + SignalSetup(crl, MONITOR_SETUP_E); + return NULL; + } + + notifyFd = inotify_init(); + if (notifyFd < 0) { + WOLFSSL_MSG("inotify failed"); + close(crl->mfd); + SignalSetup(crl, MONITOR_SETUP_E); + return NULL; + } + + if (crl->monitors[0].path) { + wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE | + IN_DELETE); + if (wd < 0) { + WOLFSSL_MSG("PEM notify add watch failed"); + close(crl->mfd); + close(notifyFd); + SignalSetup(crl, MONITOR_SETUP_E); + return NULL; + } + } + + if (crl->monitors[1].path) { + wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE | + IN_DELETE); + if (wd < 0) { + WOLFSSL_MSG("DER notify add watch failed"); + close(crl->mfd); + close(notifyFd); + SignalSetup(crl, MONITOR_SETUP_E); + return NULL; + } + } + +#ifdef WOLFSSL_SMALL_STACK + buff = (char*)XMALLOC(8192, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buff == NULL) + return NULL; +#endif + + /* signal to calling thread we're setup */ + if (SignalSetup(crl, 1) != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + + if (wd > 0) + inotify_rm_watch(notifyFd, wd); + close(crl->mfd); + close(notifyFd); + return NULL; + } + + for (;;) { + fd_set readfds; + int result; + int length; + + FD_ZERO(&readfds); + FD_SET(notifyFd, &readfds); + FD_SET(crl->mfd, &readfds); + + result = select(max(notifyFd, crl->mfd) + 1, &readfds, NULL, NULL,NULL); + + WOLFSSL_MSG("Got notify event"); + + if (result < 0) { + WOLFSSL_MSG("select problem, continue"); + continue; + } + + if (FD_ISSET(crl->mfd, &readfds)) { + WOLFSSL_MSG("got custom shutdown event, breaking out"); + break; + } + + length = (int) read(notifyFd, buff, 8192); + if (length < 0) { + WOLFSSL_MSG("notify read problem, continue"); + continue; + } + + if (SwapLists(crl) < 0) { + WOLFSSL_MSG("SwapLists problem, continue"); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (wd > 0) + inotify_rm_watch(notifyFd, wd); + close(crl->mfd); + close(notifyFd); + + return NULL; +} + +#endif /* MACH or linux */ + + +/* Start Monitoring the CRL path(s) in a thread */ +static int StartMonitorCRL(WOLFSSL_CRL* crl) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("StartMonitorCRL"); + + if (crl == NULL) + return BAD_FUNC_ARG; + + if (crl->tid != 0) { + WOLFSSL_MSG("Monitor thread already running"); + return ret; /* that's ok, someone already started */ + } + + if (pthread_create(&crl->tid, NULL, DoMonitor, crl) != 0) { + WOLFSSL_MSG("Thread creation error"); + return THREAD_CREATE_E; + } + + /* wait for setup to complete */ + if (wc_LockMutex(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockMutex crlLock error"); + return BAD_MUTEX_E; + } + + while (crl->setup == 0) { + if (pthread_cond_wait(&crl->cond, &crl->crlLock) != 0) { + ret = BAD_COND_E; + break; + } + } + + if (crl->setup < 0) + ret = crl->setup; /* store setup error */ + + wc_UnLockMutex(&crl->crlLock); + + if (ret < 0) { + WOLFSSL_MSG("DoMonitor setup failure"); + crl->tid = 0; /* thread already done */ + } + + return ret; +} + + +#else /* HAVE_CRL_MONITOR */ + +#ifndef NO_FILESYSTEM + +static int StartMonitorCRL(WOLFSSL_CRL* crl) +{ + (void)crl; + + WOLFSSL_ENTER("StartMonitorCRL"); + WOLFSSL_MSG("Not compiled in"); + + return NOT_COMPILED_IN; +} + +#endif /* NO_FILESYSTEM */ + +#endif /* HAVE_CRL_MONITOR */ + +#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) + +/* Load CRL path files of type, WOLFSSL_SUCCESS on ok */ +int LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int monitor) +{ + int ret = WOLFSSL_SUCCESS; + char* name = NULL; +#ifdef WOLFSSL_SMALL_STACK + ReadDirCtx* readCtx = NULL; +#else + ReadDirCtx readCtx[1]; +#endif + + WOLFSSL_ENTER("LoadCRL"); + if (crl == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), crl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (readCtx == NULL) + return MEMORY_E; +#endif + + /* try to load each regular file in path */ + ret = wc_ReadDirFirst(readCtx, path, &name); + while (ret == 0 && name) { + int skip = 0; + if (type == WOLFSSL_FILETYPE_PEM) { + if (XSTRSTR(name, ".pem") == NULL) { + WOLFSSL_MSG("not .pem file, skipping"); + skip = 1; + } + } + else { + if (XSTRSTR(name, ".der") == NULL && + XSTRSTR(name, ".crl") == NULL) + { + WOLFSSL_MSG("not .der or .crl file, skipping"); + skip = 1; + } + } + + if (!skip && ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl, + VERIFY) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("CRL file load failed, continuing"); + } + + ret = wc_ReadDirNext(readCtx, path, &name); + } + wc_ReadDirClose(readCtx); + ret = WOLFSSL_SUCCESS; /* load failures not reported, for backwards compat */ + +#ifdef WOLFSSL_SMALL_STACK + XFREE(readCtx, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (monitor & WOLFSSL_CRL_MONITOR) { + word32 pathLen; + char* pathBuf; + + WOLFSSL_MSG("monitor path requested"); + + pathLen = (word32)XSTRLEN(path); + pathBuf = (char*)XMALLOC(pathLen+1, crl->heap,DYNAMIC_TYPE_CRL_MONITOR); + if (pathBuf) { + XSTRNCPY(pathBuf, path, pathLen+1); + + if (type == WOLFSSL_FILETYPE_PEM) { + /* free old path before setting a new one */ + if (crl->monitors[0].path) { + XFREE(crl->monitors[0].path, crl->heap, + DYNAMIC_TYPE_CRL_MONITOR); + } + crl->monitors[0].path = pathBuf; + crl->monitors[0].type = WOLFSSL_FILETYPE_PEM; + } else { + /* free old path before setting a new one */ + if (crl->monitors[1].path) { + XFREE(crl->monitors[1].path, crl->heap, + DYNAMIC_TYPE_CRL_MONITOR); + } + crl->monitors[1].path = pathBuf; + crl->monitors[1].type = WOLFSSL_FILETYPE_ASN1; + } + + if (monitor & WOLFSSL_CRL_START_MON) { + WOLFSSL_MSG("start monitoring requested"); + + ret = StartMonitorCRL(crl); + } + } + else { + ret = MEMORY_E; + } + } + + return ret; +} + +#else +int LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int monitor) +{ + (void)crl; + (void)path; + (void)type; + (void)monitor; + + /* stub for scenario where file system is not supported */ + return NOT_COMPILED_IN; +} +#endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */ + +#endif /* HAVE_CRL */ +#endif /* !WOLFCRYPT_ONLY */ diff --git a/client/wolfssl/src/include.am b/client/wolfssl/src/include.am new file mode 100644 index 0000000..a7f20de --- /dev/null +++ b/client/wolfssl/src/include.am @@ -0,0 +1,531 @@ +# vim:ft=automake +# included from Top Level Makefile.am +# All paths should be given relative to the root + +lib_LTLIBRARIES+= src/libwolfssl.la +src_libwolfssl_la_SOURCES = +src_libwolfssl_la_LDFLAGS = ${AM_LDFLAGS} -no-undefined -version-info ${WOLFSSL_LIBRARY_VERSION} +src_libwolfssl_la_LIBADD = $(LIBM) $(LIB_ADD) $(LIB_STATIC_ADD) +src_libwolfssl_la_CFLAGS = -DBUILDING_WOLFSSL $(AM_CFLAGS) +src_libwolfssl_la_CPPFLAGS = -DBUILDING_WOLFSSL $(AM_CPPFLAGS) + +# install the packaged IPP libraries +if BUILD_FAST_RSA + +# Link needed IPP libraries +noinst_SCRIPTS+=IPP_links +IPP_links: + @$(IPPLINK) + +ippdir = $(libdir) +ipp_DATA = $(IPPLIBS) + +include_HEADERS+=$(IPPHEADERS) +endif # BUILD_FAST_RSA + +if BUILD_FIPS + +if BUILD_FIPS_V1 +# fips first file +src_libwolfssl_la_SOURCES += ctaocrypt/src/wolfcrypt_first.c + +src_libwolfssl_la_SOURCES += \ + ctaocrypt/src/hmac.c \ + ctaocrypt/src/random.c \ + ctaocrypt/src/sha256.c + +if BUILD_RSA +src_libwolfssl_la_SOURCES += ctaocrypt/src/rsa.c +endif + +if BUILD_AES +src_libwolfssl_la_SOURCES += ctaocrypt/src/aes.c +endif + +if BUILD_DES3 +src_libwolfssl_la_SOURCES += ctaocrypt/src/des3.c +endif + +if BUILD_SHA +src_libwolfssl_la_SOURCES += ctaocrypt/src/sha.c +endif + +if BUILD_SHA512 +src_libwolfssl_la_SOURCES += ctaocrypt/src/sha512.c +endif + +src_libwolfssl_la_SOURCES += ctaocrypt/src/fips.c +src_libwolfssl_la_SOURCES += ctaocrypt/src/fips_test.c + +# fips last file +src_libwolfssl_la_SOURCES += ctaocrypt/src/wolfcrypt_last.c +endif + +if BUILD_FIPS_V2 +# FIPSv2 first file +src_libwolfssl_la_SOURCES += \ + wolfcrypt/src/wolfcrypt_first.c + +src_libwolfssl_la_SOURCES += \ + wolfcrypt/src/hmac.c \ + wolfcrypt/src/random.c \ + wolfcrypt/src/sha256.c + +if BUILD_RSA +src_libwolfssl_la_SOURCES += wolfcrypt/src/rsa.c +endif + +if BUILD_ECC +src_libwolfssl_la_SOURCES += wolfcrypt/src/ecc.c +endif + +if BUILD_AES +src_libwolfssl_la_SOURCES += wolfcrypt/src/aes.c +endif + +if BUILD_AESNI +src_libwolfssl_la_SOURCES += wolfcrypt/src/aes_asm.S +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/aes_gcm_asm.S +endif +endif + +if BUILD_DES3 +src_libwolfssl_la_SOURCES += wolfcrypt/src/des3.c +endif + +if BUILD_SHA +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha.c +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha256_asm.S +endif +endif + +if BUILD_SHA512 +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha512.c +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha512_asm.S +endif +endif + +if BUILD_SHA3 +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha3.c +endif + +if BUILD_DH +src_libwolfssl_la_SOURCES += wolfcrypt/src/dh.c +endif + +if BUILD_CMAC +src_libwolfssl_la_SOURCES += wolfcrypt/src/cmac.c +endif + +src_libwolfssl_la_SOURCES += wolfcrypt/src/fips.c \ + wolfcrypt/src/fips_test.c + +# fips last file +src_libwolfssl_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c +endif + +if BUILD_FIPS_RAND +src_libwolfssl_la_SOURCES += \ + wolfcrypt/src/wolfcrypt_first.c \ + wolfcrypt/src/hmac.c \ + wolfcrypt/src/random.c \ + wolfcrypt/src/sha256.c \ + wolfcrypt/src/sha256_asm.S \ + wolfcrypt/src/fips.c \ + wolfcrypt/src/fips_test.c \ + wolfcrypt/src/wolfcrypt_last.c +endif BUILD_FIPS_RAND + +endif BUILD_FIPS + +# For wolfRand, exclude everything else. +if !BUILD_FIPS_RAND + +# For FIPSV2, exclude the wolfCrypt files included above. +# For wolfRand, exclude just a couple files. +# For old FIPS, keep the wolfCrypt versions of the +# CtaoCrypt files included above. +if !BUILD_FIPS_V2 +src_libwolfssl_la_SOURCES += wolfcrypt/src/hmac.c +endif + +# CAVP self test +if BUILD_SELFTEST +src_libwolfssl_la_SOURCES += wolfcrypt/src/selftest.c +endif + +endif !BUILD_FIPS_RAND + +src_libwolfssl_la_SOURCES += \ + wolfcrypt/src/hash.c \ + wolfcrypt/src/cpuid.c + +if !BUILD_FIPS_RAND + +if !BUILD_FIPS_V2 +if BUILD_RNG +src_libwolfssl_la_SOURCES += wolfcrypt/src/random.c +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha256.c +else +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha256.c +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha256_asm.S +endif +endif +endif + +if BUILD_AFALG +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/af_alg/afalg_hash.c +endif + +if BUILD_WOLFEVENT +src_libwolfssl_la_SOURCES += wolfcrypt/src/wolfevent.c +endif + +if BUILD_ASYNCCRYPT +src_libwolfssl_la_SOURCES += wolfcrypt/src/async.c +endif + +if !BUILD_USER_RSA +if BUILD_RSA +if BUILD_FAST_RSA +src_libwolfssl_la_SOURCES += wolfcrypt/user-crypto/src/rsa.c +else +if !BUILD_FIPS_V2 +src_libwolfssl_la_SOURCES += wolfcrypt/src/rsa.c +endif +endif +endif +endif + +if BUILD_SP +if BUILD_SP_C +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_c32.c +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_c64.c +endif +if BUILD_SP_X86_64 +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_x86_64.c +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_x86_64_asm.S +endif +if BUILD_SP_ARM32 +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_arm32.c +endif +if BUILD_SP_ARM_THUMB +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_armthumb.c +endif +if BUILD_SP_ARM64 +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_arm64.c +endif +if BUILD_SP_INT +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_int.c +endif +if BUILD_SP_ARM_CORTEX +src_libwolfssl_la_SOURCES += wolfcrypt/src/sp_cortexm.c +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_AES +src_libwolfssl_la_SOURCES += wolfcrypt/src/aes.c +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-aes.c +endif +if BUILD_AFALG +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/af_alg/afalg_aes.c +endif +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_CMAC +src_libwolfssl_la_SOURCES += wolfcrypt/src/cmac.c +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_DES3 +src_libwolfssl_la_SOURCES += wolfcrypt/src/des3.c +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_SHA +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha.c +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_SHA512 +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512.c +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm.S +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S +else +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha512.c +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha512_asm.S +endif +endif +endif +endif + +if !BUILD_FIPS_V2 +if BUILD_SHA3 +src_libwolfssl_la_SOURCES += wolfcrypt/src/sha3.c +endif +endif + + +endif !BUILD_FIPS_RAND + +src_libwolfssl_la_SOURCES += \ + wolfcrypt/src/logging.c \ + wolfcrypt/src/wc_port.c \ + wolfcrypt/src/error.c + +if !BUILD_FIPS_RAND +src_libwolfssl_la_SOURCES += \ + wolfcrypt/src/wc_encrypt.c \ + wolfcrypt/src/signature.c \ + wolfcrypt/src/wolfmath.c +endif !BUILD_FIPS_RAND + +if BUILD_MEMORY +src_libwolfssl_la_SOURCES += wolfcrypt/src/memory.c +endif + +if !BUILD_FIPS_RAND +if !BUILD_FIPS_V2 +if BUILD_DH +src_libwolfssl_la_SOURCES += wolfcrypt/src/dh.c +endif +endif + +if BUILD_ASN +src_libwolfssl_la_SOURCES += wolfcrypt/src/asn.c +endif + +endif !BUILD_FIPS_RAND + +if BUILD_CODING +src_libwolfssl_la_SOURCES += wolfcrypt/src/coding.c +endif + +if !BUILD_FIPS_RAND + +if BUILD_POLY1305 +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-poly1305.c +endif +src_libwolfssl_la_SOURCES += wolfcrypt/src/poly1305.c +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/poly1305_asm.S +endif +endif + +if BUILD_RC4 +src_libwolfssl_la_SOURCES += wolfcrypt/src/arc4.c +endif + +if BUILD_MD4 +src_libwolfssl_la_SOURCES += wolfcrypt/src/md4.c +endif + +if BUILD_MD5 +src_libwolfssl_la_SOURCES += wolfcrypt/src/md5.c +endif + +if BUILD_PWDBASED +src_libwolfssl_la_SOURCES += wolfcrypt/src/pwdbased.c +src_libwolfssl_la_SOURCES += wolfcrypt/src/pkcs12.c +endif + +if BUILD_DSA +src_libwolfssl_la_SOURCES += wolfcrypt/src/dsa.c +endif + +if !BUILD_FIPS_V2 +if BUILD_AESNI +src_libwolfssl_la_SOURCES += wolfcrypt/src/aes_asm.S +src_libwolfssl_la_SOURCES += wolfcrypt/src/aes_gcm_asm.S +endif +endif + +if BUILD_CAMELLIA +src_libwolfssl_la_SOURCES += wolfcrypt/src/camellia.c +endif + +if BUILD_MD2 +src_libwolfssl_la_SOURCES += wolfcrypt/src/md2.c +endif + +if BUILD_RIPEMD +src_libwolfssl_la_SOURCES += wolfcrypt/src/ripemd.c +endif + +if BUILD_BLAKE2 +src_libwolfssl_la_SOURCES += wolfcrypt/src/blake2b.c +endif +if BUILD_BLAKE2S +src_libwolfssl_la_SOURCES += wolfcrypt/src/blake2s.c +endif + +if BUILD_HC128 +src_libwolfssl_la_SOURCES += wolfcrypt/src/hc128.c +endif + +if BUILD_RABBIT +src_libwolfssl_la_SOURCES += wolfcrypt/src/rabbit.c +endif + +if BUILD_CHACHA +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-chacha.c +else +src_libwolfssl_la_SOURCES += wolfcrypt/src/chacha.c +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/chacha_asm.S +endif +endif +if BUILD_POLY1305 +src_libwolfssl_la_SOURCES += wolfcrypt/src/chacha20_poly1305.c +endif +endif + +if !BUILD_INLINE +src_libwolfssl_la_SOURCES += wolfcrypt/src/misc.c +endif + +if BUILD_FASTMATH +src_libwolfssl_la_SOURCES += wolfcrypt/src/tfm.c +endif + +if BUILD_SLOWMATH +src_libwolfssl_la_SOURCES += wolfcrypt/src/integer.c +endif + +if !BUILD_FIPS_V2 +if BUILD_ECC +src_libwolfssl_la_SOURCES += wolfcrypt/src/ecc.c +endif +endif + +if BUILD_CURVE25519 +src_libwolfssl_la_SOURCES += wolfcrypt/src/curve25519.c +endif + +if BUILD_ED25519 +src_libwolfssl_la_SOURCES += wolfcrypt/src/ed25519.c +endif + +if BUILD_FEMATH +if BUILD_CURVE25519_SMALL +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_low_mem.c +else +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_x25519_asm.S +else +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S +else +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_operations.c +endif +endif +endif +endif + +if BUILD_GEMATH +if BUILD_ED25519_SMALL +src_libwolfssl_la_SOURCES += wolfcrypt/src/ge_low_mem.c +else +src_libwolfssl_la_SOURCES += wolfcrypt/src/ge_operations.c +if !BUILD_FEMATH +if BUILD_INTELASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_x25519_asm.S +else +if BUILD_ARMASM +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S +else +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_operations.c +endif +endif +endif +endif +endif + +if BUILD_CURVE448 +src_libwolfssl_la_SOURCES += wolfcrypt/src/curve448.c +endif + +if BUILD_ED448 +src_libwolfssl_la_SOURCES += wolfcrypt/src/ed448.c +endif + +if BUILD_FE448 +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_448.c +endif + +if BUILD_GE448 +src_libwolfssl_la_SOURCES += wolfcrypt/src/ge_448.c +if !BUILD_FE448 +src_libwolfssl_la_SOURCES += wolfcrypt/src/fe_448.c +endif +endif + +if BUILD_LIBZ +src_libwolfssl_la_SOURCES += wolfcrypt/src/compress.c +endif + +if BUILD_PKCS7 +src_libwolfssl_la_SOURCES += wolfcrypt/src/pkcs7.c +endif + +if BUILD_SRP +src_libwolfssl_la_SOURCES += wolfcrypt/src/srp.c +endif + +if BUILD_IDEA +src_libwolfssl_la_SOURCES += wolfcrypt/src/idea.c +endif + +if BUILD_AFALG +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/af_alg/wc_afalg.c +endif + +if !BUILD_CRYPTONLY +# ssl files +src_libwolfssl_la_SOURCES += \ + src/internal.c \ + src/wolfio.c \ + src/keys.c \ + src/ssl.c \ + src/tls.c + +if BUILD_TLS13 +src_libwolfssl_la_SOURCES += src/tls13.c +endif + +if BUILD_OCSP +src_libwolfssl_la_SOURCES += src/ocsp.c +endif + +if BUILD_CRL +src_libwolfssl_la_SOURCES += src/crl.c +endif + +if BUILD_SNIFFER +src_libwolfssl_la_SOURCES += src/sniffer.c +endif + +endif !BUILD_CRYPTONLY + +endif !BUILD_FIPS_RAND diff --git a/client/wolfssl/src/internal.c b/client/wolfssl/src/internal.c new file mode 100644 index 0000000..fbdbb13 --- /dev/null +++ b/client/wolfssl/src/internal.c @@ -0,0 +1,29412 @@ +/* internal.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +/* + * WOLFSSL_SMALL_CERT_VERIFY: + * Verify the certificate signature without using DecodedCert. Doubles up + * on some code but allows smaller peak heap memory usage. + * Cannot be used with WOLFSSL_NONBLOCK_OCSP. + * WOLFSSL_ALT_CERT_CHAINS: + * Allows CA's to be presented by peer, but not part of a valid chain. + * Default wolfSSL behavior is to require validation of all presented peer + * certificates. This also allows loading intermediate CA's as trusted + * and ignoring no signer failures for CA's up the chain to root. + */ + + +#ifdef EXTERNAL_OPTS_OPENVPN +#error EXTERNAL_OPTS_OPENVPN should not be defined\ + when building wolfSSL +#endif + +#ifndef WOLFCRYPT_ONLY + +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif +#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA) + #include +#endif + +#ifdef HAVE_LIBZ + #include "zlib.h" +#endif + +#ifdef HAVE_NTRU + #include "libntruencrypt/ntru_crypto.h" +#endif + +#if defined(DEBUG_WOLFSSL) || defined(SHOW_SECRETS) || \ + defined(CHACHA_AEAD_TEST) || defined(WOLFSSL_SESSION_EXPORT_DEBUG) + #ifndef NO_STDIO_FILESYSTEM + #include + #endif +#endif + +#ifdef __sun + #include +#endif + + +#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; } + +#ifdef _MSC_VER + /* disable for while(0) cases at the .c level for now */ + #pragma warning(disable:4127) +#endif + +#if defined(WOLFSSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS) + #error \ +WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS +#endif + +#if defined(HAVE_SECURE_RENEGOTIATION) && defined(HAVE_RENEGOTIATION_INDICATION) + #error Cannot use both secure-renegotiation and renegotiation-indication +#endif + +#ifndef WOLFSSL_NO_TLS12 + +#ifndef NO_WOLFSSL_CLIENT + static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32*, + word32); + static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, word32*, + word32); + #ifndef NO_CERTS + static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32*, + word32); + #endif + #ifdef HAVE_SESSION_TICKET + static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32*, + word32); + #endif +#endif + + +#ifndef NO_WOLFSSL_SERVER + static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32*, word32); + #if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448)) && !defined(WOLFSSL_NO_CLIENT_AUTH) + static int DoCertificateVerify(WOLFSSL* ssl, byte*, word32*, word32); + #endif + #ifdef WOLFSSL_DTLS + static int SendHelloVerifyRequest(WOLFSSL*, const byte*, byte); + #endif /* WOLFSSL_DTLS */ +#endif + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef WOLFSSL_DTLS + static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl); + static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl); +#endif + + +enum processReply { + doProcessInit = 0, +#ifndef NO_WOLFSSL_SERVER + runProcessOldClientHello, +#endif + getRecordLayerHeader, + getData, + verifyEncryptedMessage, + decryptMessage, + verifyMessage, + runProcessingOneMessage +}; + + +#ifndef WOLFSSL_NO_TLS12 +#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT) + +/* Server random bytes for TLS v1.3 described downgrade protection mechanism. */ +static const byte tls13Downgrade[7] = { + 0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44 +}; +#define TLS13_DOWNGRADE_SZ sizeof(tls13Downgrade) + +#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */ + +#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_AEAD_ONLY) +static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, + int padSz, int content, int verify); + +#endif + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef HAVE_QSH + int QSH_Init(WOLFSSL* ssl); +#endif + +#ifdef WOLFSSL_RENESAS_TSIP_TLS + int tsip_useable(const WOLFSSL *ssl); + int tsip_generatePremasterSecret(); + int tsip_generateEncryptPreMasterSecret(WOLFSSL *ssl, byte *out, word32 *outSz); +#endif +int IsTLS(const WOLFSSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR) + return 1; + + return 0; +} + + +int IsAtLeastTLSv1_2(const WOLFSSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR) + return 1; +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR && ssl->version.minor <= DTLSv1_2_MINOR) + return 1; +#endif + + return 0; +} + +int IsAtLeastTLSv1_3(const ProtocolVersion pv) +{ + return (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR); +} + +static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend) +{ + (void)isSend; + + #ifdef WOLFSSL_DTLS + /* For DTLS, epoch 0 is always not encrypted. */ + if (ssl->options.dtls && !isSend && ssl->keys.curEpoch == 0) + return 0; + #endif /* WOLFSSL_DTLS */ + +#ifdef WOLFSSL_TLS13 + if (isSend) + return ssl->encrypt.setup; + else + return ssl->decrypt.setup; +#else + return ssl->keys.encryptionOn; +#endif +} + + +#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) +/* If SCTP is not enabled returns the state of the dtls option. + * If SCTP is enabled returns dtls && !sctp. */ +static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl) +{ + int result = ssl->options.dtls; + + if (result) { +#ifdef WOLFSSL_SCTP + result = !ssl->options.dtlsSctp; +#endif + } + + return result; +} +#endif /* DTLS || !WOLFSSL_NO_TLS12 */ + + +#ifdef HAVE_QSH +/* free all structs that where used with QSH */ +static int QSH_FreeAll(WOLFSSL* ssl) +{ + QSHKey* key = ssl->QSH_Key; + QSHKey* preKey = NULL; + QSHSecret* secret = ssl->QSH_secret; + QSHScheme* list = NULL; + QSHScheme* preList = NULL; + + /* free elements in struct */ + while (key) { + preKey = key; + if (key->pri.buffer) { + ForceZero(key->pri.buffer, key->pri.length); + XFREE(key->pri.buffer, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + } + if (key->pub.buffer) + XFREE(key->pub.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + key = (QSHKey*)key->next; + + /* free struct */ + XFREE(preKey, ssl->heap, DYNAMIC_TYPE_QSH); + } + + + /* free all of peers QSH keys */ + key = ssl->peerQSHKey; + while (key) { + preKey = key; + if (key->pri.buffer) { + ForceZero(key->pri.buffer, key->pri.length); + XFREE(key->pri.buffer, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + } + if (key->pub.buffer) + XFREE(key->pub.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + key = (QSHKey*)key->next; + + /* free struct */ + XFREE(preKey, ssl->heap, DYNAMIC_TYPE_QSH); + } + key = NULL; + + /* free secret information */ + if (secret) { + /* free up the QSHScheme list in QSHSecret */ + if (secret->list) + list = secret->list; + while (list) { + preList = list; + if (list->PK) + XFREE(list->PK, ssl->heap, DYNAMIC_TYPE_SECRET); + list = (QSHScheme*)list->next; + XFREE(preList, ssl->heap, DYNAMIC_TYPE_QSH); + } + + /* free secret buffers */ + if (secret->SerSi) { + if (secret->SerSi->buffer) { + /* clear extra secret material that supplemented Master Secret*/ + ForceZero(secret->SerSi->buffer, secret->SerSi->length); + XFREE(secret->SerSi->buffer, ssl->heap, DYNAMIC_TYPE_SECRET); + } + XFREE(secret->SerSi, ssl->heap, DYNAMIC_TYPE_SECRET); + } + if (secret->CliSi) { + if (secret->CliSi->buffer) { + /* clear extra secret material that supplemented Master Secret*/ + ForceZero(secret->CliSi->buffer, secret->CliSi->length); + XFREE(secret->CliSi->buffer, ssl->heap, DYNAMIC_TYPE_SECRET); + } + XFREE(secret->CliSi, ssl->heap, DYNAMIC_TYPE_SECRET); + } + } + XFREE(secret, ssl->heap, DYNAMIC_TYPE_QSH); + secret = NULL; + + return 0; +} +#endif + + +#ifdef HAVE_NTRU +static WOLFSSL_GLOBAL WC_RNG* rng; +static WOLFSSL_GLOBAL wolfSSL_Mutex* rngMutex; + +static word32 GetEntropy(unsigned char* out, word32 num_bytes) +{ + int ret = 0; + + if (rng == NULL) { + if ((rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), 0, + DYNAMIC_TYPE_RNG)) == NULL) + return DRBG_OUT_OF_MEMORY; + wc_InitRng(rng); + } + + if (rngMutex == NULL) { + if ((rngMutex = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), 0, + DYNAMIC_TYPE_MUTEX)) == NULL) + return DRBG_OUT_OF_MEMORY; + wc_InitMutex(rngMutex); + } + + ret |= wc_LockMutex(rngMutex); + ret |= wc_RNG_GenerateBlock(rng, out, num_bytes); + ret |= wc_UnLockMutex(rngMutex); + + if (ret != 0) + return DRBG_ENTROPY_FAIL; + + return DRBG_OK; +} +#endif /* HAVE_NTRU */ + +#ifdef HAVE_LIBZ + + /* alloc user allocs to work with zlib */ + static void* myAlloc(void* opaque, unsigned int item, unsigned int size) + { + (void)opaque; + return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ); + } + + + static void myFree(void* opaque, void* memory) + { + (void)opaque; + XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ); + } + + + /* init zlib comp/decomp streams, 0 on success */ + static int InitStreams(WOLFSSL* ssl) + { + ssl->c_stream.zalloc = (alloc_func)myAlloc; + ssl->c_stream.zfree = (free_func)myFree; + ssl->c_stream.opaque = (voidpf)ssl->heap; + + if (deflateInit(&ssl->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) + return ZLIB_INIT_ERROR; + + ssl->didStreamInit = 1; + + ssl->d_stream.zalloc = (alloc_func)myAlloc; + ssl->d_stream.zfree = (free_func)myFree; + ssl->d_stream.opaque = (voidpf)ssl->heap; + + if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR; + + return 0; + } + + + static void FreeStreams(WOLFSSL* ssl) + { + if (ssl->didStreamInit) { + deflateEnd(&ssl->c_stream); + inflateEnd(&ssl->d_stream); + } + } + + + /* compress in to out, return out size or error */ + static int myCompress(WOLFSSL* ssl, byte* in, int inSz, byte* out, int outSz) + { + int err; + int currTotal = (int)ssl->c_stream.total_out; + + ssl->c_stream.next_in = in; + ssl->c_stream.avail_in = inSz; + ssl->c_stream.next_out = out; + ssl->c_stream.avail_out = outSz; + + err = deflate(&ssl->c_stream, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR; + + return (int)ssl->c_stream.total_out - currTotal; + } + + + /* decompress in to out, return out size or error */ + static int myDeCompress(WOLFSSL* ssl, byte* in,int inSz, byte* out,int outSz) + { + int err; + int currTotal = (int)ssl->d_stream.total_out; + + ssl->d_stream.next_in = in; + ssl->d_stream.avail_in = inSz; + ssl->d_stream.next_out = out; + ssl->d_stream.avail_out = outSz; + + err = inflate(&ssl->d_stream, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR; + + return (int)ssl->d_stream.total_out - currTotal; + } + +#endif /* HAVE_LIBZ */ + + +#ifdef WOLFSSL_SESSION_EXPORT +#ifdef WOLFSSL_DTLS +/* serializes the cipher specs struct for exporting */ +static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +{ + word32 idx = 0; + CipherSpecs* specs; + + WOLFSSL_ENTER("ExportCipherSpecState"); + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + specs= &(ssl->specs); + + if (DTLS_EXPORT_SPC_SZ > len) { + return BUFFER_E; + } + + XMEMSET(exp, 0, DTLS_EXPORT_SPC_SZ); + + c16toa(specs->key_size, exp + idx); idx += OPAQUE16_LEN; + c16toa(specs->iv_size, exp + idx); idx += OPAQUE16_LEN; + c16toa(specs->block_size, exp + idx); idx += OPAQUE16_LEN; + c16toa(specs->aead_mac_size, exp + idx); idx += OPAQUE16_LEN; + exp[idx++] = specs->bulk_cipher_algorithm; + exp[idx++] = specs->cipher_type; + exp[idx++] = specs->mac_algorithm; + exp[idx++] = specs->kea; + exp[idx++] = specs->sig_algo; + exp[idx++] = specs->hash_size; + exp[idx++] = specs->pad_size; + exp[idx++] = specs->static_ecdh; + + if (idx != DTLS_EXPORT_SPC_SZ) { + WOLFSSL_MSG("DTLS_EXPORT_SPC_SZ needs updated and export version"); + return DTLS_EXPORT_VER_E; + } + + WOLFSSL_LEAVE("ExportCipherSpecState", idx); + (void)ver; + return idx; +} + + +/* serializes the key struct for exporting */ +static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, + byte small) +{ + word32 idx = 0; + byte sz; + Keys* keys; + + WOLFSSL_ENTER("ExportKeyState"); + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + keys = &(ssl->keys); + + if (DTLS_EXPORT_MIN_KEY_SZ > len) { + WOLFSSL_MSG("Buffer not large enough for minimum key struct size"); + return BUFFER_E; + } + + XMEMSET(exp, 0, DTLS_EXPORT_MIN_KEY_SZ); + + c32toa(keys->peer_sequence_number_hi, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->peer_sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->sequence_number_hi, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; + + c16toa(keys->peerSeq[0].nextEpoch, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->peerSeq[0].nextSeq_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->peerSeq[0].nextSeq_lo, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->curEpoch, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->curSeq_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->curSeq_lo, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->peerSeq[0].prevSeq_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->peerSeq[0].prevSeq_lo, exp + idx); idx += OPAQUE32_LEN; + + c16toa(keys->dtls_peer_handshake_number, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->dtls_expected_peer_handshake_number, exp + idx); + idx += OPAQUE16_LEN; + + c16toa(keys->dtls_sequence_number_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->dtls_sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->dtls_prev_sequence_number_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->dtls_prev_sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->dtls_epoch, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->dtls_handshake_number, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->encryptSz, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->padSz, exp + idx); idx += OPAQUE32_LEN; + exp[idx++] = keys->encryptionOn; + exp[idx++] = keys->decryptedCur; + + /* from here on the buffer needs checked because is variable length that + * can be larger than DTLS_EXPORT_MIN_KEY_SZ */ + { + word32 i; + if ((OPAQUE16_LEN * 2) + idx + + (2 * (WOLFSSL_DTLS_WINDOW_WORDS * OPAQUE32_LEN)) > len) { + WOLFSSL_MSG("Buffer not large enough for WOLFSSL_DTLS_WINDOW_WORDS"); + return BUFFER_E; + } + + c16toa(WOLFSSL_DTLS_WINDOW_WORDS, exp + idx); idx += OPAQUE16_LEN; + for (i = 0; i < WOLFSSL_DTLS_WINDOW_WORDS; i++) { + c32toa(keys->peerSeq[0].window[i], exp + idx); + idx += OPAQUE32_LEN; + } + c16toa(WOLFSSL_DTLS_WINDOW_WORDS, exp + idx); idx += OPAQUE16_LEN; + for (i = 0; i < WOLFSSL_DTLS_WINDOW_WORDS; i++) { + c32toa(keys->peerSeq[0].prevWindow[i], exp + idx); + idx += OPAQUE32_LEN; + } + } + + if (idx >= len) { + WOLFSSL_MSG("Buffer not large enough for truncated hmac flag"); + return BUFFER_E; + } + +#ifdef HAVE_TRUNCATED_HMAC + sz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ: ssl->specs.hash_size; + exp[idx++] = ssl->truncated_hmac; +#else + sz = ssl->specs.hash_size; + exp[idx++] = 0; /* no truncated hmac */ +#endif + + sz = (small)? 0: sz; + if (idx + (sz * 2) + OPAQUE8_LEN > len) { + WOLFSSL_MSG("Buffer not large enough for MAC secret"); + return BUFFER_E; + } + + exp[idx++] = sz; + if (sz > 0) { + #ifndef WOLFSSL_AEAD_ONLY + XMEMCPY(exp + idx, keys->client_write_MAC_secret, sz); idx += sz; + XMEMCPY(exp + idx, keys->server_write_MAC_secret, sz); idx += sz; + #else + XMEMSET(exp + idx, 0, sz); idx += sz; + XMEMSET(exp + idx, 0, sz); idx += sz; + #endif + } + + sz = (small)? 0: ssl->specs.key_size; + if (idx + (sz * 2) + OPAQUE8_LEN > len) { + WOLFSSL_MSG("Buffer not large enough for write key"); + return BUFFER_E; + } + + exp[idx++] = sz; + if (sz > 0) { + XMEMCPY(exp + idx, keys->client_write_key, sz); idx += sz; + XMEMCPY(exp + idx, keys->server_write_key, sz); idx += sz; + } + + sz = (small)? 0: ssl->specs.iv_size; + if (idx + (sz * 2) + OPAQUE8_LEN + AEAD_MAX_EXP_SZ > len) { + WOLFSSL_MSG("Buffer not large enough for IVs"); + return BUFFER_E; + } + + exp[idx++] = sz; + if (sz > 0) { + XMEMCPY(exp + idx, keys->client_write_IV, sz); idx += sz; + XMEMCPY(exp + idx, keys->server_write_IV, sz); idx += sz; + } + XMEMCPY(exp + idx, keys->aead_exp_IV, AEAD_MAX_EXP_SZ); + idx += AEAD_MAX_EXP_SZ; + + sz = (small)? 0: AEAD_MAX_IMP_SZ; + if (idx + (sz * 2) + OPAQUE8_LEN > len) { + WOLFSSL_MSG("Buffer not large enough for imp IVs"); + return BUFFER_E; + } + exp[idx++] = sz; + if (sz > 0) { + XMEMCPY(exp + idx, keys->aead_enc_imp_IV, sz); idx += sz; + XMEMCPY(exp + idx, keys->aead_dec_imp_IV, sz); idx += sz; + } + + /* DTLS_EXPORT_KEY_SZ is max value. idx size can vary */ + if (idx > DTLS_EXPORT_KEY_SZ) { + WOLFSSL_MSG("DTLS_EXPORT_KEY_SZ needs updated and export version"); + return DTLS_EXPORT_VER_E; + } + + WOLFSSL_LEAVE("ExportKeyState", idx); + (void)ver; + return idx; +} + +static int ImportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +{ + word32 idx = 0; + CipherSpecs* specs; + + WOLFSSL_ENTER("ImportCipherSpecState"); + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + specs= &(ssl->specs); + + if (DTLS_EXPORT_SPC_SZ > len) { + WOLFSSL_MSG("Buffer not large enough for max spec struct size"); + return BUFFER_E; + } + + ato16(exp + idx, &specs->key_size); idx += OPAQUE16_LEN; + ato16(exp + idx, &specs->iv_size); idx += OPAQUE16_LEN; + ato16(exp + idx, &specs->block_size); idx += OPAQUE16_LEN; + ato16(exp + idx, &specs->aead_mac_size); idx += OPAQUE16_LEN; + specs->bulk_cipher_algorithm = exp[idx++]; + specs->cipher_type = exp[idx++]; + specs->mac_algorithm = exp[idx++]; + specs->kea = exp[idx++]; + specs->sig_algo = exp[idx++]; + specs->hash_size = exp[idx++]; + specs->pad_size = exp[idx++]; + specs->static_ecdh = exp[idx++]; + + WOLFSSL_LEAVE("ImportCipherSpecState", idx); + (void)ver; + return idx; +} + + +static int ImportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +{ + word32 idx = 0; + byte sz; + Keys* keys; + + WOLFSSL_ENTER("ImportKeyState"); + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + keys = &(ssl->keys); + + /* check minimum length -- includes byte used for size indicators */ + if (len < DTLS_EXPORT_MIN_KEY_SZ) { + WOLFSSL_MSG("Buffer not large enough for minimum expected size"); + return BUFFER_E; + } + ato32(exp + idx, &keys->peer_sequence_number_hi); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->peer_sequence_number_lo); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->sequence_number_hi); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->sequence_number_lo); idx += OPAQUE32_LEN; + + ato16(exp + idx, &keys->peerSeq[0].nextEpoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->peerSeq[0].nextSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->peerSeq[0].nextSeq_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->curEpoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->curSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->curSeq_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->peerSeq[0].prevSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->peerSeq[0].prevSeq_lo); idx += OPAQUE32_LEN; + + ato16(exp + idx, &keys->dtls_peer_handshake_number); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->dtls_expected_peer_handshake_number); + idx += OPAQUE16_LEN; + + ato16(exp + idx, &keys->dtls_sequence_number_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->dtls_sequence_number_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->dtls_prev_sequence_number_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->dtls_prev_sequence_number_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->dtls_epoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->dtls_handshake_number); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->encryptSz); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->padSz); idx += OPAQUE32_LEN; + keys->encryptionOn = exp[idx++]; + keys->decryptedCur = exp[idx++]; + + { + word16 i, wordCount, wordAdj = 0; + + /* do window */ + ato16(exp + idx, &wordCount); + idx += OPAQUE16_LEN; + + if (wordCount > WOLFSSL_DTLS_WINDOW_WORDS) { + wordCount = WOLFSSL_DTLS_WINDOW_WORDS; + wordAdj = (WOLFSSL_DTLS_WINDOW_WORDS - wordCount) * sizeof(word32); + } + + XMEMSET(keys->peerSeq[0].window, 0xFF, DTLS_SEQ_SZ); + for (i = 0; i < wordCount; i++) { + ato32(exp + idx, &keys->peerSeq[0].window[i]); + idx += OPAQUE32_LEN; + } + idx += wordAdj; + + /* do prevWindow */ + ato16(exp + idx, &wordCount); + idx += OPAQUE16_LEN; + + if (wordCount > WOLFSSL_DTLS_WINDOW_WORDS) { + wordCount = WOLFSSL_DTLS_WINDOW_WORDS; + wordAdj = (WOLFSSL_DTLS_WINDOW_WORDS - wordCount) * sizeof(word32); + } + + XMEMSET(keys->peerSeq[0].prevWindow, 0xFF, DTLS_SEQ_SZ); + for (i = 0; i < wordCount; i++) { + ato32(exp + idx, &keys->peerSeq[0].prevWindow[i]); + idx += OPAQUE32_LEN; + } + idx += wordAdj; + + } + +#ifdef HAVE_TRUNCATED_HMAC + ssl->truncated_hmac = exp[idx++]; +#else + idx++; /* no truncated hmac */ +#endif + sz = exp[idx++]; +#ifndef WOLFSSL_AEAD_ONLY + if (sz > sizeof(keys->client_write_MAC_secret) || (sz * 2) + idx > len) { + WOLFSSL_MSG("Buffer not large enough for MAC import"); + return BUFFER_E; + } + if (sz > 0) { + XMEMCPY(keys->client_write_MAC_secret, exp + idx, sz); idx += sz; + XMEMCPY(keys->server_write_MAC_secret, exp + idx, sz); idx += sz; + } +#else + if (sz + idx > len) { + return BUFFER_E; + } + idx += sz; idx += sz; +#endif + + sz = exp[idx++]; + if (sz > sizeof(keys->client_write_key) || (sz * 2) + idx > len) { + WOLFSSL_MSG("Buffer not large enough for key import"); + return BUFFER_E; + } + if (sz > 0) { + XMEMCPY(keys->client_write_key, exp + idx, sz); idx += sz; + XMEMCPY(keys->server_write_key, exp + idx, sz); idx += sz; + } + + sz = exp[idx++]; + if (sz > sizeof(keys->client_write_IV) || (sz * 2) + idx > len) { + WOLFSSL_MSG("Buffer not large enough for write IV import"); + return BUFFER_E; + } + if (sz > 0) { + XMEMCPY(keys->client_write_IV, exp + idx, sz); idx += sz; + XMEMCPY(keys->server_write_IV, exp + idx, sz); idx += sz; + } + XMEMCPY(keys->aead_exp_IV, exp + idx, AEAD_MAX_EXP_SZ); + idx += AEAD_MAX_EXP_SZ; + + sz = exp[idx++]; + if (sz > sizeof(keys->aead_enc_imp_IV) || (sz * 2) + idx > len) { + WOLFSSL_MSG("Buffer not large enough for imp IV import"); + return BUFFER_E; + } + if (sz > 0) { + XMEMCPY(keys->aead_enc_imp_IV, exp + idx, sz); idx += sz; + XMEMCPY(keys->aead_dec_imp_IV, exp + idx, sz); idx += sz; + } + + WOLFSSL_LEAVE("ImportKeyState", idx); + (void)ver; + return idx; +} + + +/* copy over necessary information from Options struct to buffer + * On success returns size of buffer used on failure returns a negative value */ +static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +{ + int idx = 0; + word16 zero = 0; + Options* options = &ssl->options; + + WOLFSSL_ENTER("dtls_export_new"); + + if (exp == NULL || options == NULL || len < DTLS_EXPORT_OPT_SZ) { + return BAD_FUNC_ARG; + } + + XMEMSET(exp, 0, DTLS_EXPORT_OPT_SZ); + + /* these options are kept and sent to indicate verify status and strength + * of handshake */ + exp[idx++] = options->sendVerify; + exp[idx++] = options->verifyPeer; + exp[idx++] = options->verifyNone; + exp[idx++] = options->downgrade; +#ifndef NO_DH + c16toa(options->minDhKeySz, exp + idx); idx += OPAQUE16_LEN; + c16toa(options->maxDhKeySz, exp + idx); idx += OPAQUE16_LEN; + c16toa(options->dhKeySz, exp + idx); idx += OPAQUE16_LEN; +#else + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; +#endif +#ifndef NO_RSA + c16toa((word16)(options->minRsaKeySz), exp + idx); idx += OPAQUE16_LEN; +#else + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; +#endif +#ifdef HAVE_ECC + c16toa((word16)(options->minEccKeySz), exp + idx); idx += OPAQUE16_LEN; +#else + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; +#endif + + /* these options are kept to indicate state and behavior */ +#ifndef NO_PSK + exp[idx++] = options->havePSK; +#else + exp[idx++] = 0; +#endif + exp[idx++] = options->sessionCacheOff; + exp[idx++] = options->sessionCacheFlushOff; + exp[idx++] = options->side; + exp[idx++] = options->resuming; + exp[idx++] = options->haveSessionId; + exp[idx++] = options->tls; + exp[idx++] = options->tls1_1; + exp[idx++] = options->dtls; + exp[idx++] = options->connReset; + exp[idx++] = options->isClosed; + exp[idx++] = options->closeNotify; + exp[idx++] = options->sentNotify; + exp[idx++] = options->usingCompression; + exp[idx++] = options->haveRSA; + exp[idx++] = options->haveECC; + exp[idx++] = options->haveDH; + exp[idx++] = options->haveNTRU; + exp[idx++] = options->haveQSH; + exp[idx++] = options->haveECDSAsig; + exp[idx++] = options->haveStaticECC; + exp[idx++] = options->havePeerVerify; + exp[idx++] = options->usingPSK_cipher; + exp[idx++] = options->usingAnon_cipher; + exp[idx++] = options->sendAlertState; + exp[idx++] = options->partialWrite; + exp[idx++] = options->quietShutdown; + exp[idx++] = options->groupMessages; +#ifdef HAVE_POLY1305 + exp[idx++] = options->oldPoly; +#else + exp[idx++] = 0; +#endif +#ifdef HAVE_ANON + exp[idx++] = options->haveAnon; +#else + exp[idx++] = 0; +#endif +#ifdef HAVE_SESSION_TICKET + exp[idx++] = options->createTicket; + exp[idx++] = options->useTicket; +#ifdef WOLFSSL_TLS13 + if (ver > DTLS_EXPORT_VERSION_3) { + exp[idx++] = options->noTicketTls13; + } +#else + if (ver > DTLS_EXPORT_VERSION_3) { + exp[idx++] = 0; + } +#endif +#else + exp[idx++] = 0; + exp[idx++] = 0; + if (ver > DTLS_EXPORT_VERSION_3) { + exp[idx++] = 0; + } +#endif + exp[idx++] = options->processReply; + exp[idx++] = options->cipherSuite0; + exp[idx++] = options->cipherSuite; + exp[idx++] = options->serverState; + exp[idx++] = options->clientState; + exp[idx++] = options->handShakeState; + exp[idx++] = options->handShakeDone; + exp[idx++] = options->minDowngrade; + exp[idx++] = options->connectState; + exp[idx++] = options->acceptState; + exp[idx++] = options->asyncState; + + /* version of connection */ + exp[idx++] = ssl->version.major; + exp[idx++] = ssl->version.minor; + + (void)zero; + + /* check if changes were made and notify of need to update export version */ + switch (ver) { + case DTLS_EXPORT_VERSION_3: + if (idx != DTLS_EXPORT_OPT_SZ_3) { + WOLFSSL_MSG("Update DTLS_EXPORT_OPT_SZ and version of export"); + return DTLS_EXPORT_VER_E; + } + break; + + case DTLS_EXPORT_VERSION: + if (idx != DTLS_EXPORT_OPT_SZ) { + WOLFSSL_MSG("Update DTLS_EXPORT_OPT_SZ and version of export"); + return DTLS_EXPORT_VER_E; + } + break; + + default: + WOLFSSL_MSG("New version case needs added to wolfSSL export"); + return DTLS_EXPORT_VER_E; + } + + WOLFSSL_LEAVE("dtls_export_new", idx); + + return idx; +} + + +/* copy items from Export struct to Options struct + * On success returns size of buffer used on failure returns a negative value */ +static int dtls_export_load(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +{ + int idx = 0; + Options* options = &ssl->options; + + switch (ver) { + case DTLS_EXPORT_VERSION: + if (len < DTLS_EXPORT_OPT_SZ) { + WOLFSSL_MSG("Sanity check on buffer size failed"); + return BAD_FUNC_ARG; + } + break; + + case DTLS_EXPORT_VERSION_3: + if (len < DTLS_EXPORT_OPT_SZ_3) { + WOLFSSL_MSG("Sanity check on buffer size failed"); + return BAD_FUNC_ARG; + } + break; + + default: + WOLFSSL_MSG("Export version not supported"); + return BAD_FUNC_ARG; + } + + if (exp == NULL || options == NULL) { + return BAD_FUNC_ARG; + } + + + /* these options are kept and sent to indicate verify status and strength + * of handshake */ + options->sendVerify = exp[idx++]; + options->verifyPeer = exp[idx++]; + options->verifyNone = exp[idx++]; + options->downgrade = exp[idx++]; +#ifndef NO_DH + ato16(exp + idx, &(options->minDhKeySz)); idx += OPAQUE16_LEN; + ato16(exp + idx, &(options->maxDhKeySz)); idx += OPAQUE16_LEN; + ato16(exp + idx, &(options->dhKeySz)); idx += OPAQUE16_LEN; +#else + idx += OPAQUE16_LEN; + idx += OPAQUE16_LEN; + idx += OPAQUE16_LEN; +#endif +#ifndef NO_RSA + ato16(exp + idx, (word16*)&(options->minRsaKeySz)); idx += OPAQUE16_LEN; +#else + idx += OPAQUE16_LEN; +#endif +#ifdef HAVE_ECC + ato16(exp + idx, (word16*)&(options->minEccKeySz)); idx += OPAQUE16_LEN; +#else + idx += OPAQUE16_LEN; +#endif + + /* these options are kept to indicate state and behavior */ +#ifndef NO_PSK + options->havePSK = exp[idx++]; +#else + idx++; +#endif + options->sessionCacheOff = exp[idx++]; + options->sessionCacheFlushOff = exp[idx++]; + options->side = exp[idx++]; + options->resuming = exp[idx++]; + options->haveSessionId = exp[idx++]; + options->tls = exp[idx++]; + options->tls1_1 = exp[idx++]; + options->dtls = exp[idx++]; + options->connReset = exp[idx++]; + options->isClosed = exp[idx++]; + options->closeNotify = exp[idx++]; + options->sentNotify = exp[idx++]; + options->usingCompression = exp[idx++]; + options->haveRSA = exp[idx++]; + options->haveECC = exp[idx++]; + options->haveDH = exp[idx++]; + options->haveNTRU = exp[idx++]; + options->haveQSH = exp[idx++]; + options->haveECDSAsig = exp[idx++]; + options->haveStaticECC = exp[idx++]; + options->havePeerVerify = exp[idx++]; + options->usingPSK_cipher = exp[idx++]; + options->usingAnon_cipher = exp[idx++]; + options->sendAlertState = exp[idx++]; + options->partialWrite = exp[idx++]; + options->quietShutdown = exp[idx++]; + options->groupMessages = exp[idx++]; +#ifdef HAVE_POLY1305 + options->oldPoly = exp[idx++]; /* set when to use old rfc way of poly*/ +#else + idx++; +#endif +#ifdef HAVE_ANON + options->haveAnon = exp[idx++]; /* User wants to allow Anon suites */ +#else + idx++; +#endif +#ifdef HAVE_SESSION_TICKET + options->createTicket = exp[idx++]; /* Server to create new Ticket */ + options->useTicket = exp[idx++]; /* Use Ticket not session cache */ +#ifdef WOLFSSL_TLS13 + if (ver > DTLS_EXPORT_VERSION_3) { + options->noTicketTls13 = exp[idx++];/* Server won't create new Ticket */ + } +#else + if (ver > DTLS_EXPORT_VERSION_3) { + exp[idx++] = 0; + } +#endif +#else + idx++; + idx++; + if (ver > DTLS_EXPORT_VERSION_3) { + idx++; + } +#endif + options->processReply = exp[idx++]; + options->cipherSuite0 = exp[idx++]; + options->cipherSuite = exp[idx++]; + options->serverState = exp[idx++]; + options->clientState = exp[idx++]; + options->handShakeState = exp[idx++]; + options->handShakeDone = exp[idx++]; + options->minDowngrade = exp[idx++]; + options->connectState = exp[idx++]; + options->acceptState = exp[idx++]; + options->asyncState = exp[idx++]; + + /* version of connection */ + if (ssl->version.major != exp[idx++] || ssl->version.minor != exp[idx++]) { + WOLFSSL_MSG("Version mismatch ie DTLS v1 vs v1.2"); + return VERSION_ERROR; + } + + return idx; +} + +#ifndef WOLFSSL_SESSION_EXPORT_NOPEER +static int ExportPeerInfo(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +{ + int idx = 0; + int ipSz = DTLS_EXPORT_IP; /* start as max size */ + int fam = 0; + word16 port = 0; + char ip[DTLS_EXPORT_IP]; + + if (ver != DTLS_EXPORT_VERSION) { + WOLFSSL_MSG("Export version not supported"); + return BAD_FUNC_ARG; + } + + if (ssl == NULL || exp == NULL || len < sizeof(ip) + 3 * DTLS_EXPORT_LEN) { + return BAD_FUNC_ARG; + } + + if (ssl->ctx->CBGetPeer == NULL) { + WOLFSSL_MSG("No get peer call back set"); + return BAD_FUNC_ARG; + } + if (ssl->ctx->CBGetPeer(ssl, ip, &ipSz, &port, &fam) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Get peer callback error"); + return SOCKET_ERROR_E; + } + + /* check that ipSz/fam is not negative or too large since user can set cb */ + if (ipSz < 0 || ipSz > DTLS_EXPORT_IP || fam < 0) { + WOLFSSL_MSG("Bad ipSz or fam returned from get peer callback"); + return SOCKET_ERROR_E; + } + + c16toa((word16)fam, exp + idx); idx += DTLS_EXPORT_LEN; + c16toa((word16)ipSz, exp + idx); idx += DTLS_EXPORT_LEN; + XMEMCPY(exp + idx, ip, ipSz); idx += ipSz; + c16toa(port, exp + idx); idx += DTLS_EXPORT_LEN; + + return idx; +} +#endif /* !WOLFSSL_SESSION_EXPORT_NOPEER */ + + +static int ImportPeerInfo(WOLFSSL* ssl, byte* buf, word32 len, byte ver) +{ + word16 idx = 0; + word16 ipSz; + word16 fam; + word16 port; + char ip[DTLS_EXPORT_IP]; + + if (ver != DTLS_EXPORT_VERSION && ver != DTLS_EXPORT_VERSION_3) { + WOLFSSL_MSG("Export version not supported"); + return BAD_FUNC_ARG; + } + + if (len == 0) { + WOLFSSL_MSG("No peer info sent"); + return 0; + } + + if (ssl == NULL || buf == NULL || len < 3 * DTLS_EXPORT_LEN) { + return BAD_FUNC_ARG; + } + + /* import sin family */ + ato16(buf + idx, &fam); idx += DTLS_EXPORT_LEN; + + /* import ip address idx, and ipSz are unsigned but cast for enum */ + ato16(buf + idx, &ipSz); idx += DTLS_EXPORT_LEN; + if (ipSz >= sizeof(ip) || (word16)(idx + ipSz + DTLS_EXPORT_LEN) > len) { + return BUFFER_E; + } + XMEMSET(ip, 0, sizeof(ip)); + XMEMCPY(ip, buf + idx, ipSz); idx += ipSz; + ip[ipSz] = '\0'; /* with check that ipSz less than ip this is valid */ + ato16(buf + idx, &port); idx += DTLS_EXPORT_LEN; + + /* sanity check for a function to call, then use it to import peer info */ + if (ssl->ctx->CBSetPeer == NULL) { + WOLFSSL_MSG("No set peer function"); + return BAD_FUNC_ARG; + } + if (ssl->ctx->CBSetPeer(ssl, ip, ipSz, port, fam) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error setting peer info"); + return SOCKET_ERROR_E; + } + + return idx; +} + + +/* WOLFSSL_LOCAL function that serializes the current WOLFSSL session state only + * buf is used to hold the serialized WOLFSSL struct and sz is the size of buf + * passed in. + * On success returns the size of serialized session state.*/ +int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) +{ + int ret; + word32 idx = 0; + word32 totalLen = 0; + + WOLFSSL_ENTER("wolfSSL_dtls_export_state_internal"); + + if (buf == NULL || ssl == NULL) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + totalLen += DTLS_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ + /* each of the following have a 2 byte length before data */ + totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_MIN_KEY_SZ; + if (totalLen > sz) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", BUFFER_E); + return BUFFER_E; + } + + buf[idx++] = (byte)DTLS_EXPORT_STATE_PRO; + buf[idx++] = ((byte)DTLS_EXPORT_STATE_PRO & 0xF0) | + ((byte)DTLS_EXPORT_VERSION & 0X0F); + idx += DTLS_EXPORT_LEN; /* leave room for total length */ + + /* export keys struct and dtls state -- variable length stored in ret */ + idx += DTLS_EXPORT_LEN; /* leave room for length */ + if ((ret = ExportKeyState(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION, 1)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", ret); + return ret; + } + c16toa((word16)ret, buf + idx - DTLS_EXPORT_LEN); idx += ret; + + /* place total length of exported buffer minus 2 bytes protocol/version */ + c16toa((word16)(idx - DTLS_EXPORT_LEN), buf + DTLS_EXPORT_LEN); + +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + /* if compiled with debug options then print the version, protocol, size */ + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Exporting DTLS session state\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)DTLS_EXPORT_VERSION, buf[0], (buf[1] >> 4), idx - 2); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", idx); + return idx; +} + + +/* WOLFSSL_LOCAL function that serializes the current WOLFSSL session + * buf is used to hold the serialized WOLFSSL struct and sz is the size of buf + * passed in. + * On success returns the size of serialized session.*/ +int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, word32 sz) +{ + int ret; + word32 idx = 0; + word32 totalLen = 0; + + WOLFSSL_ENTER("wolfSSL_dtls_export_internal"); + + if (buf == NULL || ssl == NULL) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + totalLen += DTLS_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ + /* each of the following have a 2 byte length before data */ + totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_OPT_SZ; + totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_KEY_SZ; + totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ; + totalLen += DTLS_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; + + if (totalLen > sz) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", BUFFER_E); + return BUFFER_E; + } + + buf[idx++] = (byte)DTLS_EXPORT_PRO; + buf[idx++] = ((byte)DTLS_EXPORT_PRO & 0xF0) | + ((byte)DTLS_EXPORT_VERSION & 0X0F); + + idx += DTLS_EXPORT_LEN; /* leave spot for length */ + + c16toa((word16)DTLS_EXPORT_OPT_SZ, buf + idx); idx += DTLS_EXPORT_LEN; + if ((ret = dtls_export_new(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); + return ret; + } + idx += ret; + + /* export keys struct and dtls state -- variable length stored in ret */ + idx += DTLS_EXPORT_LEN; /* leave room for length */ + if ((ret = ExportKeyState(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION, 0)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); + return ret; + } + c16toa((word16)ret, buf + idx - DTLS_EXPORT_LEN); idx += ret; + + /* export of cipher specs struct */ + c16toa((word16)DTLS_EXPORT_SPC_SZ, buf + idx); idx += DTLS_EXPORT_LEN; + if ((ret = ExportCipherSpecState(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); + return ret; + } + idx += ret; + + /* export of dtls peer information */ + idx += DTLS_EXPORT_LEN; +#ifdef WOLFSSL_SESSION_EXPORT_NOPEER + ret = 0; /* not saving peer port/ip information */ +#else + if ((ret = ExportPeerInfo(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); + return ret; + } +#endif + c16toa(ret, buf + idx - DTLS_EXPORT_LEN); + idx += ret; + + /* place total length of exported buffer minus 2 bytes protocol/version */ + c16toa((word16)(idx - DTLS_EXPORT_LEN), buf + DTLS_EXPORT_LEN); + + /* if compiled with debug options then print the version, protocol, size */ +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Exporting DTLS session\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)DTLS_EXPORT_VERSION, buf[0], (buf[1] >> 4), idx - 2); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", idx); + return idx; +} + + +/* On success return amount of buffer consumed */ +int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) +{ + word32 idx = 0; + word16 length = 0; + int version; + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_import_state_internal"); + /* check at least enough room for protocol and length */ + if (sz < DTLS_EXPORT_LEN * 2 || ssl == NULL) { + WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + if (buf[idx++] != (byte)DTLS_EXPORT_STATE_PRO || + (buf[idx] & 0xF0) != ((byte)DTLS_EXPORT_PRO & 0xF0)) { + WOLFSSL_MSG("Incorrect protocol"); + return BAD_FUNC_ARG; + } + version = buf[idx++] & 0x0F; + + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length > sz - DTLS_EXPORT_LEN) { /* subtract 2 for protocol */ + WOLFSSL_MSG("Buffer size sanity check failed"); + return BUFFER_E; + } + +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + /* if compiled with debug options then print the version, protocol, size */ + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Importing DTLS session state\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)version, buf[0], (buf[1] >> 4), length); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + /* perform sanity checks and extract Options information used */ + switch (version) { + case DTLS_EXPORT_VERSION: + break; + + default: + WOLFSSL_MSG("Bad export state version"); + return BAD_FUNC_ARG; + + } + + /* perform sanity checks and extract Keys struct */ + if (DTLS_EXPORT_LEN + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + return BUFFER_E; + } + if ((ret = ImportKeyState(ssl, buf + idx, length, version)) < 0) { + WOLFSSL_MSG("Import Key struct error"); + WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret); + return ret; + } + idx += ret; + + WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret); + return ret; +} + + +/* On success return amount of buffer consumed */ +int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, word32 sz) +{ + word32 idx = 0; + word16 length = 0; + int version; + int ret; + int optSz; + + WOLFSSL_ENTER("wolfSSL_dtls_import_internal"); + /* check at least enough room for protocol and length */ + if (sz < DTLS_EXPORT_LEN * 2 || ssl == NULL) { + return BAD_FUNC_ARG; + } + + /* sanity check on protocol ID and size of buffer */ + if (buf[idx++] != (byte)DTLS_EXPORT_PRO || + (buf[idx] & 0xF0) != ((byte)DTLS_EXPORT_PRO & 0xF0)) { + /* don't increment on second idx to next get version */ + + /* check if importing state only */ + return wolfSSL_dtls_import_state_internal(ssl, buf, sz); + } + version = buf[idx++] & 0x0F; + + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length > sz - DTLS_EXPORT_LEN) { /* subtract 2 for protocol */ + return BUFFER_E; + } + + /* if compiled with debug options then print the version, protocol, size */ +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Importing DTLS session\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)version, buf[0], (buf[1] >> 4), length); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + /* perform sanity checks and extract Options information used */ + switch (version) { + case DTLS_EXPORT_VERSION: + optSz = DTLS_EXPORT_OPT_SZ; + break; + + case DTLS_EXPORT_VERSION_3: + WOLFSSL_MSG("Importing older version 3"); + optSz = DTLS_EXPORT_OPT_SZ_3; + break; + + default: + WOLFSSL_MSG("Bad export version"); + return BAD_FUNC_ARG; + + } + + if (DTLS_EXPORT_LEN + optSz + idx > sz) { + WOLFSSL_MSG("Import Options struct error"); + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length != optSz) { + WOLFSSL_MSG("Import Options struct error"); + return BUFFER_E; + } + if ((ret = dtls_export_load(ssl, buf + idx, length, version)) < 0) { + WOLFSSL_MSG("Import Options struct error"); + return ret; + } + idx += length; + + /* perform sanity checks and extract Keys struct */ + if (DTLS_EXPORT_LEN + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + return BUFFER_E; + } + if ((ret = ImportKeyState(ssl, buf + idx, length, version)) < 0) { + WOLFSSL_MSG("Import Key struct error"); + return ret; + } + idx += ret; + + /* perform sanity checks and extract CipherSpecs struct */ + if (DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ + idx > sz) { + WOLFSSL_MSG("Import CipherSpecs struct error"); + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if ( length != DTLS_EXPORT_SPC_SZ) { + WOLFSSL_MSG("Import CipherSpecs struct error"); + return BUFFER_E; + } + if ((ret = ImportCipherSpecState(ssl, buf + idx, length, version)) < 0) { + WOLFSSL_MSG("Import CipherSpecs struct error"); + return ret; + } + idx += ret; + + /* perform sanity checks and extract DTLS peer info */ + if (DTLS_EXPORT_LEN + idx > sz) { + WOLFSSL_MSG("Import DTLS peer info error"); + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (idx + length > sz) { + WOLFSSL_MSG("Import DTLS peer info error"); + return BUFFER_E; + } + if ((ret = ImportPeerInfo(ssl, buf + idx, length, version)) < 0) { + WOLFSSL_MSG("Import Peer Addr error"); + return ret; + } + idx += ret; + + SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + + /* set hmac function to use when verifying */ + if (ssl->options.tls == 1 || ssl->options.tls1_1 == 1 || + ssl->options.dtls == 1) { + ssl->hmac = TLS_hmac; + } + + /* make sure is a valid suite used */ + if (wolfSSL_get_cipher(ssl) == NULL) { + WOLFSSL_MSG("Can not match cipher suite imported"); + return MATCH_SUITE_ERROR; + } + + /* do not allow stream ciphers with DTLS, except for NULL cipher */ + if (ssl->specs.cipher_type == stream && + ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null) { + WOLFSSL_MSG("Can not import stream ciphers for DTLS"); + return SANITY_CIPHER_E; + } + + return idx; +} +#endif /* WOLFSSL_DTLS */ +#endif /* WOLFSSL_SESSION_EXPORT */ + + +void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv) +{ + method->version = pv; + method->side = WOLFSSL_CLIENT_END; + method->downgrade = 0; +} + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) +int InitSSL_Side(WOLFSSL* ssl, word16 side) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + /* set side */ + ssl->options.side = side; + + /* reset options that are side specific */ +#ifdef HAVE_NTRU + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.haveNTRU = 1; /* always on client side */ + /* server can turn on by loading key */ + } +#endif +#ifdef HAVE_ECC + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.haveECDSAsig = 1; /* always on client side */ + ssl->options.haveECC = 1; /* server turns on with ECC key cert */ + ssl->options.haveStaticECC = 1; /* server can turn on by loading key */ + } +#elif defined(HAVE_ED25519) || defined(HAVE_ED448) + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.haveECDSAsig = 1; /* always on client side */ + ssl->options.haveECC = 1; /* server turns on with ECC key cert */ + } +#endif + +#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT) + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if ((ssl->ctx->method->version.major == SSLv3_MAJOR) && + (ssl->ctx->method->version.minor >= TLSv1_MINOR)) { + ssl->options.haveEMS = 1; + } + #ifdef WOLFSSL_DTLS + if (ssl->ctx->method->version.major == DTLS_MAJOR) + ssl->options.haveEMS = 1; + #endif /* WOLFSSL_DTLS */ + } +#endif /* HAVE_EXTENDED_MASTER && !NO_WOLFSSL_CLIENT */ + +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) + if (ssl->options.dtls && ssl->options.side == WOLFSSL_SERVER_END) { + int ret; + ret = wolfSSL_DTLS_SetCookieSecret(ssl, NULL, 0); + if (ret != 0) { + WOLFSSL_MSG("DTLS Cookie Secret error"); + return ret; + } + } +#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ + + return InitSSL_Suites(ssl); +} +#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + +/* Initialize SSL context, return 0 on success */ +int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap) +{ + int ret = 0; + + XMEMSET(ctx, 0, sizeof(WOLFSSL_CTX)); + + ctx->method = method; + ctx->refCount = 1; /* so either CTX_free or SSL_free can release */ + ctx->heap = ctx; /* defaults to self */ + ctx->timeout = WOLFSSL_SESSION_TIMEOUT; + ctx->minDowngrade = WOLFSSL_MIN_DOWNGRADE; /* current default: TLSv1_MINOR */ + + if (wc_InitMutex(&ctx->countMutex) < 0) { + WOLFSSL_MSG("Mutex error on CTX init"); + ctx->err = CTX_INIT_MUTEX_E; + return BAD_MUTEX_E; + } + +#ifndef NO_DH + ctx->minDhKeySz = MIN_DHKEY_SZ; + ctx->maxDhKeySz = MAX_DHKEY_SZ; +#endif +#ifndef NO_RSA + ctx->minRsaKeySz = MIN_RSAKEY_SZ; +#endif +#ifdef HAVE_ECC + ctx->minEccKeySz = MIN_ECCKEY_SZ; + ctx->eccTempKeySz = ECDHE_SIZE; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ctx->verifyDepth = MAX_CHAIN_DEPTH; +#endif +#ifdef OPENSSL_EXTRA + ctx->cbioFlag = WOLFSSL_CBIO_NONE; +#endif + +#ifndef WOLFSSL_USER_IO + #ifdef MICRIUM + ctx->CBIORecv = MicriumReceive; + ctx->CBIOSend = MicriumSend; + #ifdef WOLFSSL_DTLS + if (method->version.major == DTLS_MAJOR) { + ctx->CBIORecv = MicriumReceiveFrom; + ctx->CBIOSend = MicriumSendTo; + } + #ifdef WOLFSSL_SESSION_EXPORT + #error Micrium port does not support DTLS session export yet + #endif + #endif + #elif defined WOLFSSL_UIP + ctx->CBIORecv = uIPReceive; + ctx->CBIOSend = uIPSend; + #ifdef WOLFSSL_DTLS + if (method->version.major == DTLS_MAJOR) { + ctx->CBIOSendTo = uIPSendTo; + ctx->CBIORecvFrom = uIPRecvFrom; + } + #endif + #else + ctx->CBIORecv = EmbedReceive; + ctx->CBIOSend = EmbedSend; + #ifdef WOLFSSL_DTLS + if (method->version.major == DTLS_MAJOR) { + ctx->CBIORecv = EmbedReceiveFrom; + ctx->CBIOSend = EmbedSendTo; + } + #ifdef WOLFSSL_SESSION_EXPORT + ctx->CBGetPeer = EmbedGetPeer; + ctx->CBSetPeer = EmbedSetPeer; + #endif + #endif + #endif /* MICRIUM */ +#endif /* WOLFSSL_USER_IO */ + +#ifdef HAVE_NETX + ctx->CBIORecv = NetX_Receive; + ctx->CBIOSend = NetX_Send; +#elif defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) + ctx->CBIORecv = Mynewt_Receive; + ctx->CBIOSend = Mynewt_Send; +#elif defined(WOLFSSL_GNRC) + ctx->CBIORecv = GNRC_ReceiveFrom; + ctx->CBIOSend = GNRC_SendTo; +#endif + +#ifdef HAVE_NTRU + if (method->side == WOLFSSL_CLIENT_END) + ctx->haveNTRU = 1; /* always on client side */ + /* server can turn on by loading key */ +#endif +#ifdef HAVE_ECC + if (method->side == WOLFSSL_CLIENT_END) { + ctx->haveECDSAsig = 1; /* always on client side */ + ctx->haveECC = 1; /* server turns on with ECC key cert */ + ctx->haveStaticECC = 1; /* server can turn on by loading key */ + } +#elif defined(HAVE_ED25519) || defined(HAVE_ED448) + if (method->side == WOLFSSL_CLIENT_END) { + ctx->haveECDSAsig = 1; /* always on client side */ + ctx->haveECC = 1; /* server turns on with ECC key cert */ + } +#endif + + ctx->devId = INVALID_DEVID; + +#if defined(WOLFSSL_DTLS) + #ifdef WOLFSSL_SCTP + ctx->dtlsMtuSz = MAX_RECORD_SIZE; + #elif defined(WOLFSSL_DTLS_MTU) + ctx->dtlsMtuSz = MAX_MTU; + #endif +#endif + +#ifndef NO_CERTS + ctx->cm = wolfSSL_CertManagerNew_ex(heap); + if (ctx->cm == NULL) { + WOLFSSL_MSG("Bad Cert Manager New"); + return BAD_CERT_MANAGER_ERROR; + } + #ifdef OPENSSL_EXTRA + /* setup WOLFSSL_X509_STORE */ + ctx->x509_store.cm = ctx->cm; + #endif +#endif + +#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT) + if (method->side == WOLFSSL_CLIENT_END) { + if ((method->version.major == SSLv3_MAJOR) && + (method->version.minor >= TLSv1_MINOR)) { + + ctx->haveEMS = 1; + } +#ifdef WOLFSSL_DTLS + if (method->version.major == DTLS_MAJOR) + ctx->haveEMS = 1; +#endif /* WOLFSSL_DTLS */ + } +#endif /* HAVE_EXTENDED_MASTER && !NO_WOLFSSL_CLIENT */ + +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) + ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT; +#endif + +#ifdef HAVE_WOLF_EVENT + ret = wolfEventQueue_Init(&ctx->event_queue); +#endif /* HAVE_WOLF_EVENT */ + +#ifdef WOLFSSL_EARLY_DATA + ctx->maxEarlyDataSz = MAX_EARLY_DATA_SZ; +#endif + + ctx->heap = heap; /* wolfSSL_CTX_load_static_memory sets */ + ctx->verifyDepth = MAX_CHAIN_DEPTH; + + return ret; +} + + +/* In case contexts are held in array and don't want to free actual ctx */ +void SSL_CtxResourceFree(WOLFSSL_CTX* ctx) +{ +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) && \ + defined(HAVE_TLS_EXTENSIONS) && !defined(NO_WOLFSSL_SERVER) + int i; +#endif + +#ifdef HAVE_WOLF_EVENT + wolfEventQueue_Free(&ctx->event_queue); +#endif /* HAVE_WOLF_EVENT */ + +#ifdef WOLFSSL_STATIC_MEMORY + if (ctx->onHeap == 1) { + XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); + } + else { + XFREE(ctx->method, NULL, DYNAMIC_TYPE_METHOD); + } +#else + XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); +#endif + ctx->method = NULL; + if (ctx->suites) { + XFREE(ctx->suites, ctx->heap, DYNAMIC_TYPE_SUITES); + ctx->suites = NULL; + } + +#ifndef NO_DH + XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ctx->serverDH_G.buffer = NULL; + XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ctx->serverDH_P.buffer = NULL; +#endif /* !NO_DH */ + +#ifdef SINGLE_THREADED + if (ctx->rng) { + wc_FreeRng(ctx->rng); + XFREE(ctx->rng, ctx->heap, DYNAMIC_TYPE_RNG); + ctx->rng = NULL; + } +#endif /* SINGLE_THREADED */ + +#ifndef NO_CERTS + FreeDer(&ctx->privateKey); + FreeDer(&ctx->certificate); + #ifdef KEEP_OUR_CERT + if (ctx->ourCert && ctx->ownOurCert) { + FreeX509(ctx->ourCert); + XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509); + ctx->ourCert = NULL; + } + #endif /* KEEP_OUR_CERT */ + FreeDer(&ctx->certChain); + wolfSSL_CertManagerFree(ctx->cm); + ctx->cm = NULL; + #ifdef OPENSSL_EXTRA + /* ctx->cm was free'd so cm of x509 store should now be NULL */ + if (ctx->x509_store_pt != NULL) { + ctx->x509_store_pt->cm = NULL; + } + wolfSSL_X509_STORE_free(ctx->x509_store_pt); + while (ctx->ca_names != NULL) { + WOLFSSL_STACK *next = ctx->ca_names->next; + wolfSSL_X509_NAME_free(ctx->ca_names->data.name); + XFREE(ctx->ca_names, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->ca_names = next; + } + #endif + #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + while (ctx->x509Chain != NULL) { + WOLFSSL_STACK *next = ctx->x509Chain->next; + wolfSSL_X509_free(ctx->x509Chain->data.x509); + XFREE(ctx->x509Chain, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->x509Chain = next; + } + #endif +#endif /* !NO_CERTS */ + +#ifdef HAVE_TLS_EXTENSIONS + TLSX_FreeAll(ctx->extensions, ctx->heap); + +#ifndef NO_WOLFSSL_SERVER +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + if (ctx->certOcspRequest) { + FreeOcspRequest(ctx->certOcspRequest); + XFREE(ctx->certOcspRequest, ctx->heap, DYNAMIC_TYPE_OCSP_REQUEST); + } +#endif + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + for (i = 0; i < MAX_CHAIN_DEPTH; i++) { + if (ctx->chainOcspRequest[i]) { + FreeOcspRequest(ctx->chainOcspRequest[i]); + XFREE(ctx->chainOcspRequest[i], ctx->heap, DYNAMIC_TYPE_OCSP_REQUEST); + ctx->chainOcspRequest[i] = NULL; + } + } +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ +#endif /* !NO_WOLFSSL_SERVER */ + +#endif /* HAVE_TLS_EXTENSIONS */ +#ifdef OPENSSL_EXTRA + if(ctx->alpn_cli_protos) { + XFREE((void *)ctx->alpn_cli_protos, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->alpn_cli_protos = NULL; + } +#endif +#ifdef WOLFSSL_STATIC_MEMORY + if (ctx->heap != NULL) { +#ifdef WOLFSSL_HEAP_TEST + /* avoid dereferencing a test value */ + if (ctx->heap != (void*)WOLFSSL_HEAP_TEST) +#endif + { + WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)(ctx->heap); + wc_FreeMutex(&((WOLFSSL_HEAP*)(hint->memory))->memory_mutex); + } + } +#endif /* WOLFSSL_STATIC_MEMORY */ +} + + +void FreeSSL_Ctx(WOLFSSL_CTX* ctx) +{ + int refCount; + + /* decrement CTX reference count */ + if ((refCount = SSL_CTX_RefCount(ctx, -1)) < 0) { + /* check error state, if mutex error code then mutex init failed but + * CTX was still malloc'd */ + if (ctx->err == CTX_INIT_MUTEX_E) { + SSL_CtxResourceFree(ctx); + XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX); + } + return; + } + + if (refCount == 0) { + void* heap = ctx->heap; + WOLFSSL_MSG("CTX ref count down to 0, doing full free"); + SSL_CtxResourceFree(ctx); + wc_FreeMutex(&ctx->countMutex); +#ifdef WOLFSSL_STATIC_MEMORY + if (ctx->onHeap == 0) { + heap = NULL; + } +#endif + XFREE(ctx, heap, DYNAMIC_TYPE_CTX); + (void)heap; /* not used in some builds */ + } + else { + (void)ctx; + WOLFSSL_MSG("CTX ref count not 0 yet, no free"); + } +} + + +/* Set cipher pointers to null */ +void InitCiphers(WOLFSSL* ssl) +{ +#ifdef BUILD_ARC4 + ssl->encrypt.arc4 = NULL; + ssl->decrypt.arc4 = NULL; +#endif +#ifdef BUILD_DES3 + ssl->encrypt.des3 = NULL; + ssl->decrypt.des3 = NULL; +#endif +#ifdef BUILD_AES + ssl->encrypt.aes = NULL; + ssl->decrypt.aes = NULL; +#endif +#ifdef HAVE_CAMELLIA + ssl->encrypt.cam = NULL; + ssl->decrypt.cam = NULL; +#endif +#ifdef HAVE_HC128 + ssl->encrypt.hc128 = NULL; + ssl->decrypt.hc128 = NULL; +#endif +#ifdef BUILD_RABBIT + ssl->encrypt.rabbit = NULL; + ssl->decrypt.rabbit = NULL; +#endif +#ifdef HAVE_CHACHA + ssl->encrypt.chacha = NULL; + ssl->decrypt.chacha = NULL; +#endif +#if defined(HAVE_POLY1305) && defined(HAVE_ONE_TIME_AUTH) + ssl->auth.poly1305 = NULL; +#endif + ssl->encrypt.setup = 0; + ssl->decrypt.setup = 0; +#ifdef HAVE_ONE_TIME_AUTH + ssl->auth.setup = 0; +#endif +#ifdef HAVE_IDEA + ssl->encrypt.idea = NULL; + ssl->decrypt.idea = NULL; +#endif +} + + +/* Free ciphers */ +void FreeCiphers(WOLFSSL* ssl) +{ + (void)ssl; +#ifdef BUILD_ARC4 + wc_Arc4Free(ssl->encrypt.arc4); + wc_Arc4Free(ssl->decrypt.arc4); + XFREE(ssl->encrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef BUILD_DES3 + wc_Des3Free(ssl->encrypt.des3); + wc_Des3Free(ssl->decrypt.des3); + XFREE(ssl->encrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#if defined(BUILD_AES) || defined(BUILD_AESGCM) /* See: InitKeys() in keys.c + * on addition of BUILD_AESGCM + * check (enc->aes, dec->aes) */ + wc_AesFree(ssl->encrypt.aes); + wc_AesFree(ssl->decrypt.aes); + #if (defined(BUILD_AESGCM) || defined(HAVE_AESCCM)) && \ + !defined(WOLFSSL_NO_TLS12) + XFREE(ssl->decrypt.additional, ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + XFREE(ssl->encrypt.additional, ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + #endif + XFREE(ssl->encrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef CIPHER_NONCE + XFREE(ssl->decrypt.nonce, ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + XFREE(ssl->encrypt.nonce, ssl->heap, DYNAMIC_TYPE_AES_BUFFER); +#endif +#ifdef HAVE_CAMELLIA + XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef HAVE_HC128 + XFREE(ssl->encrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef BUILD_RABBIT + XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef HAVE_CHACHA + XFREE(ssl->encrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#if defined(HAVE_POLY1305) && defined(HAVE_ONE_TIME_AUTH) + XFREE(ssl->auth.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef HAVE_IDEA + XFREE(ssl->encrypt.idea, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.idea, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) + wc_HmacFree(ssl->encrypt.hmac); + wc_HmacFree(ssl->decrypt.hmac); + XFREE(ssl->encrypt.hmac, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.hmac, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +} + + +void InitCipherSpecs(CipherSpecs* cs) +{ + XMEMSET(cs, 0, sizeof(CipherSpecs)); + + cs->bulk_cipher_algorithm = INVALID_BYTE; + cs->cipher_type = INVALID_BYTE; + cs->mac_algorithm = INVALID_BYTE; + cs->kea = INVALID_BYTE; + cs->sig_algo = INVALID_BYTE; +} + +#if defined(USE_ECDSA_KEYSZ_HASH_ALGO) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_ECC)) +static int GetMacDigestSize(byte macAlgo) +{ + switch (macAlgo) { + #ifndef NO_SHA + case sha_mac: + return WC_SHA_DIGEST_SIZE; + #endif + #ifndef NO_SHA256 + case sha256_mac: + return WC_SHA256_DIGEST_SIZE; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + return WC_SHA384_DIGEST_SIZE; + #endif + #ifdef WOLFSSL_SHA512 + case sha512_mac: + return WC_SHA512_DIGEST_SIZE; + #endif + default: + break; + } + return NOT_COMPILED_IN; +} +#endif /* USE_ECDSA_KEYSZ_HASH_ALGO */ + +static WC_INLINE void AddSuiteHashSigAlgo(Suites* suites, byte macAlgo, byte sigAlgo, + int keySz, word16* inOutIdx) +{ + int addSigAlgo = 1; + +#ifdef USE_ECDSA_KEYSZ_HASH_ALGO + if (sigAlgo == ecc_dsa_sa_algo) { + int digestSz = GetMacDigestSize(macAlgo); + /* do not add sig/algos with digest size larger than key size */ + if (digestSz <= 0 || (keySz > 0 && digestSz > keySz)) { + addSigAlgo = 0; + } + } +#else + (void)keySz; +#endif /* USE_ECDSA_KEYSZ_HASH_ALGO */ + + if (addSigAlgo) { +#ifdef WC_RSA_PSS + if (sigAlgo == rsa_pss_sa_algo) { + /* RSA PSS is sig then mac */ + suites->hashSigAlgo[*inOutIdx] = sigAlgo; + *inOutIdx += 1; + suites->hashSigAlgo[*inOutIdx] = macAlgo; + *inOutIdx += 1; + #ifdef WOLFSSL_TLS13 + /* Add the certificate algorithm as well */ + suites->hashSigAlgo[*inOutIdx] = sigAlgo; + *inOutIdx += 1; + suites->hashSigAlgo[*inOutIdx] = PSS_RSAE_TO_PSS_PSS(macAlgo); + *inOutIdx += 1; + #endif + } + else +#endif + { + suites->hashSigAlgo[*inOutIdx] = macAlgo; + *inOutIdx += 1; + suites->hashSigAlgo[*inOutIdx] = sigAlgo; + *inOutIdx += 1; + } + } +} + +void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig, int haveRSAsig, + int haveAnon, int tls1_2, int keySz) +{ + word16 idx = 0; + + (void)tls1_2; + (void)keySz; + +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + if (haveECDSAsig) { +#ifdef HAVE_ECC + #ifdef WOLFSSL_SHA512 + AddSuiteHashSigAlgo(suites, sha512_mac, ecc_dsa_sa_algo, keySz, &idx); + #endif + #ifdef WOLFSSL_SHA384 + AddSuiteHashSigAlgo(suites, sha384_mac, ecc_dsa_sa_algo, keySz, &idx); + #endif + #ifndef NO_SHA256 + AddSuiteHashSigAlgo(suites, sha256_mac, ecc_dsa_sa_algo, keySz, &idx); + #endif + #if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \ + defined(WOLFSSL_ALLOW_TLS_SHA1)) + AddSuiteHashSigAlgo(suites, sha_mac, ecc_dsa_sa_algo, keySz, &idx); + #endif +#endif + #ifdef HAVE_ED25519 + AddSuiteHashSigAlgo(suites, ED25519_SA_MAJOR, ED25519_SA_MINOR, keySz, + &idx); + #endif + #ifdef HAVE_ED448 + AddSuiteHashSigAlgo(suites, ED448_SA_MAJOR, ED448_SA_MINOR, keySz, + &idx); + #endif + } +#endif /* HAVE_ECC || HAVE_ED25519 || defined(HAVE_ED448 */ + + if (haveRSAsig) { + #ifdef WC_RSA_PSS + if (tls1_2) { + #ifdef WOLFSSL_SHA512 + AddSuiteHashSigAlgo(suites, sha512_mac, rsa_pss_sa_algo, keySz, + &idx); + #endif + #ifdef WOLFSSL_SHA384 + AddSuiteHashSigAlgo(suites, sha384_mac, rsa_pss_sa_algo, keySz, + &idx); + #endif + #ifndef NO_SHA256 + AddSuiteHashSigAlgo(suites, sha256_mac, rsa_pss_sa_algo, keySz, + &idx); + #endif + } + #endif + #ifdef WOLFSSL_SHA512 + AddSuiteHashSigAlgo(suites, sha512_mac, rsa_sa_algo, keySz, &idx); + #endif + #ifdef WOLFSSL_SHA384 + AddSuiteHashSigAlgo(suites, sha384_mac, rsa_sa_algo, keySz, &idx); + #endif + #ifndef NO_SHA256 + AddSuiteHashSigAlgo(suites, sha256_mac, rsa_sa_algo, keySz, &idx); + #endif + #ifdef WOLFSSL_SHA224 + AddSuiteHashSigAlgo(suites, sha224_mac, rsa_sa_algo, keySz, &idx); + #endif + #if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \ + defined(WOLFSSL_ALLOW_TLS_SHA1)) + AddSuiteHashSigAlgo(suites, sha_mac, rsa_sa_algo, keySz, &idx); + #endif + } + +#ifdef HAVE_ANON + if (haveAnon) { + AddSuiteHashSigAlgo(suites, sha_mac, anonymous_sa_algo, keySz, &idx); + } +#endif + + (void)haveAnon; + (void)haveECDSAsig; + suites->hashSigAlgoSz = idx; +} + +void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, + word16 havePSK, word16 haveDH, word16 haveNTRU, + word16 haveECDSAsig, word16 haveECC, + word16 haveStaticECC, int side) +{ + word16 idx = 0; + int tls = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR; + int tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR; +#ifdef WOLFSSL_TLS13 + int tls1_3 = IsAtLeastTLSv1_3(pv); +#endif + int dtls = 0; + int haveRSAsig = 1; + + (void)tls; /* shut up compiler */ + (void)tls1_2; + (void)dtls; + (void)haveDH; + (void)havePSK; + (void)haveNTRU; + (void)haveStaticECC; + (void)haveECC; + (void)side; + (void)haveRSA; /* some builds won't read */ + (void)haveRSAsig; /* non ecc builds won't read */ + + if (suites == NULL) { + WOLFSSL_MSG("InitSuites pointer error"); + return; + } + + if (suites->setSuites) + return; /* trust user settings, don't override */ + +#ifdef WOLFSSL_TLS13 +#ifdef BUILD_TLS_AES_128_GCM_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_AES_256_GCM_SHA384 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_AES_128_CCM_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_128_CCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_128_CCM_8_SHA256; + } +#endif + +#ifdef HAVE_NULL_CIPHER + #ifdef BUILD_TLS_SHA256_SHA256 + if (tls1_3) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_SHA256_SHA256; + } + #endif + + #ifdef BUILD_TLS_SHA384_SHA384 + if (tls1_3) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_SHA384_SHA384; + } + #endif +#endif +#endif /* WOLFSSL_TLS13 */ + +#ifndef WOLFSSL_NO_TLS12 + +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_RSA) + if (side == WOLFSSL_SERVER_END && haveStaticECC) { + haveRSA = 0; /* can't do RSA with ECDSA key */ + } + + if (side == WOLFSSL_SERVER_END && haveECDSAsig) { + haveRSAsig = 0; /* can't have RSA sig if signed by ECDSA */ + } +#endif /* !NO_WOLFSSL_SERVER */ + +#ifdef WOLFSSL_DTLS + if (pv.major == DTLS_MAJOR) { + dtls = 1; + tls = 1; + /* May be dead assignments dependent upon configuration */ + (void) dtls; + (void) tls; + tls1_2 = pv.minor <= DTLSv1_2_MINOR; + } +#endif + +#ifdef HAVE_RENEGOTIATION_INDICATION + if (side == WOLFSSL_CLIENT_END) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV; + } +#endif + +#ifdef BUILD_TLS_QSH + if (tls) { + suites->suites[idx++] = QSH_BYTE; + suites->suites[idx++] = TLS_QSH; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + if (!dtls && tls && haveNTRU && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveDH && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA + if (tls1_2 && haveDH) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveDH) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DH_anon_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveDH && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384 + if (tls1_2 && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256 + if (tls1_2 && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + if (tls1_2 && haveECC) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +/* Place as higher priority for MYSQL */ +#if defined(WOLFSSL_MYSQL_COMPATIBLE) +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + if (tls && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + if (tls && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + if (tls && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + if (tls && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + if (!dtls && tls && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + if (!dtls && tls && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveECC && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + if (!dtls && tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + if (!dtls && tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + if (tls1_2 && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CCM_8; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CCM_8; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && haveRSA) +#else + if (tls && haveDH && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && haveRSA) +#else + if (tls && haveDH && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +/* Place as higher priority for MYSQL testing */ +#if !defined(WOLFSSL_MYSQL_COMPATIBLE) +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveRSA) +#else + if (tls && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveRSA) +#else + if (tls && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + if (tls1_2 && haveECC) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = + TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA + if (tls && haveECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_NULL_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_MD5 + if (tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_NULL_MD5; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + if (tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveRSA) +#else + if (tls && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + if (tls && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && havePSK) +#else + if (tls && haveDH && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && havePSK) +#else + if (tls && haveDH && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls1 && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + if (tls && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM + if (tls && haveDH && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CCM; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM + if (tls && haveDH && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CCM; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM + if (tls && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM + if (tls && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + if (tls && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM_8; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + if (tls && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM_8; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && havePSK) +#else + if (tls && haveDH && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA384; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_PSK_WITH_NULL_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && havePSK) +#else + if (tls && haveDH && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && havePSK) +#else + if (tls && havePSK) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + if (tls && havePSK) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + if (!dtls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + if (!dtls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + if (haveRSA ) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + if (!dtls && tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + if (!dtls && tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + if (!dtls && tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveRSA) +#else + if (tls && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && haveRSA) +#else + if (tls && haveDH && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveRSA) +#else + if (tls && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#ifndef WOLFSSL_OLDTLS_SHA2_CIPHERSUITES + if (tls1_2 && haveDH && haveRSA) +#else + if (tls && haveDH && haveRSA) +#endif + { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + if (haveRSA) { + suites->suites[idx++] = CIPHER_BYTE; + suites->suites[idx++] = SSL_RSA_WITH_IDEA_CBC_SHA; + } +#endif + +#endif /* !WOLFSSL_NO_TLS12 */ + + suites->suiteSz = idx; + + InitSuitesHashSigAlgo(suites, haveECDSAsig | haveECC, haveRSAsig | haveRSA, + 0, tls1_2, keySz); +} + +#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) || \ + (!defined(NO_WOLFSSL_CLIENT) && (!defined(NO_DH) || defined(HAVE_ECC))) + +/* Decode the signature algorithm. + * + * input The encoded signature algorithm. + * hashalgo The hash algorithm. + * hsType The signature type. + */ +static WC_INLINE void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType) +{ + switch (input[0]) { + case NEW_SA_MAJOR: + #ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + if (input[1] == ED25519_SA_MINOR) { + *hsType = ed25519_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + else + #endif + #ifdef HAVE_ED448 + /* ED448: 0x0808 */ + if (input[1] == ED448_SA_MINOR) { + *hsType = ed448_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + else + #endif + #ifdef WC_RSA_PSS + /* PSS PSS signatures: 0x080[9-b] */ + if (input[1] >= pss_sha256 && input[1] <= pss_sha512) { + *hsType = rsa_pss_pss_algo; + *hashAlgo = PSS_PSS_HASH_TO_MAC(input[1]); + } + else + #endif + { + *hsType = input[0]; + *hashAlgo = input[1]; + } + break; + default: + *hashAlgo = input[0]; + *hsType = input[1]; + break; + } +} +#endif /* !NO_WOLFSSL_SERVER || !NO_CERTS */ + +#ifndef WOLFSSL_NO_TLS12 +#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT) +#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) || (!defined(NO_RSA) && defined(WC_RSA_PSS)) + +static enum wc_HashType HashAlgoToType(int hashAlgo) +{ + switch (hashAlgo) { + #ifdef WOLFSSL_SHA512 + case sha512_mac: + return WC_HASH_TYPE_SHA512; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + return WC_HASH_TYPE_SHA384; + #endif + #ifndef NO_SHA256 + case sha256_mac: + return WC_HASH_TYPE_SHA256; + #endif + #ifdef WOLFSSL_SHA224 + case sha224_mac: + return WC_HASH_TYPE_SHA224; + #endif + #if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \ + defined(WOLFSSL_ALLOW_TLS_SHA1)) + case sha_mac: + return WC_HASH_TYPE_SHA; + #endif + default: + WOLFSSL_MSG("Bad hash sig algo"); + break; + } + + return WC_HASH_TYPE_NONE; +} +#endif /* !NO_DH || HAVE_ECC || (!NO_RSA && WC_RSA_PSS) */ +#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */ +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifndef NO_CERTS + +void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag) +{ + (void)dynamicFlag; + + if (name != NULL) { + name->name = name->staticName; + name->dynamicName = 0; + name->sz = 0; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + XMEMSET(&name->fullName, 0, sizeof(DecodedName)); + XMEMSET(&name->cnEntry, 0, sizeof(WOLFSSL_X509_NAME_ENTRY)); + XMEMSET(&name->extra, 0, sizeof(name->extra)); + name->cnEntry.value = &(name->cnEntry.data); /* point to internal data*/ + name->cnEntry.nid = ASN_COMMON_NAME; + name->x509 = NULL; +#endif /* OPENSSL_EXTRA */ + } +} + + +void FreeX509Name(WOLFSSL_X509_NAME* name, void* heap) +{ + if (name != NULL) { + if (name->dynamicName) { + XFREE(name->name, heap, DYNAMIC_TYPE_SUBJECT_CN); + name->name = NULL; + } +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + { + int i; + if (name->fullName.fullName != NULL) { + XFREE(name->fullName.fullName, heap, DYNAMIC_TYPE_X509); + name->fullName.fullName = NULL; + } + for (i = 0; i < MAX_NAME_ENTRIES; i++) { + /* free ASN1 string data */ + if (name->extra[i].set && name->extra[i].data.data != NULL) { + XFREE(name->extra[i].data.data, heap, DYNAMIC_TYPE_OPENSSL); + } + } + wolfSSL_ASN1_OBJECT_free(&name->cnEntry.object); + } +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + } + (void)heap; +} + + +/* Initialize wolfSSL X509 type */ +void InitX509(WOLFSSL_X509* x509, int dynamicFlag, void* heap) +{ + if (x509 == NULL) { + WOLFSSL_MSG("Null parameter passed in!"); + return; + } + + XMEMSET(x509, 0, sizeof(WOLFSSL_X509)); + + x509->heap = heap; + InitX509Name(&x509->issuer, 0); + InitX509Name(&x509->subject, 0); + x509->dynamicMemory = (byte)dynamicFlag; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + x509->refCount = 1; + (void)wc_InitMutex(&x509->refMutex); + #endif +} + + +/* Free wolfSSL X509 type */ +void FreeX509(WOLFSSL_X509* x509) +{ + if (x509 == NULL) + return; + + FreeX509Name(&x509->issuer, x509->heap); + FreeX509Name(&x509->subject, x509->heap); + if (x509->pubKey.buffer) { + XFREE(x509->pubKey.buffer, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + x509->pubKey.buffer = NULL; + } + FreeDer(&x509->derCert); + XFREE(x509->sig.buffer, x509->heap, DYNAMIC_TYPE_SIGNATURE); + x509->sig.buffer = NULL; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + XFREE(x509->authKeyId, x509->heap, DYNAMIC_TYPE_X509_EXT); + x509->authKeyId = NULL; + XFREE(x509->subjKeyId, x509->heap, DYNAMIC_TYPE_X509_EXT); + x509->subjKeyId = NULL; + if (x509->authInfo != NULL) { + XFREE(x509->authInfo, x509->heap, DYNAMIC_TYPE_X509_EXT); + x509->authInfo = NULL; + } + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + if (x509->authInfoCaIssuer != NULL) { + XFREE(x509->authInfoCaIssuer, x509->heap, DYNAMIC_TYPE_X509_EXT); + } + if (x509->ext_sk != NULL) { + wolfSSL_sk_X509_EXTENSION_free(x509->ext_sk); + } + #endif /* OPENSSL_ALL || WOLFSSL_QT */ + #ifdef OPENSSL_EXTRA + /* Free serialNumber that was set by wolfSSL_X509_get_serialNumber */ + if (x509->serialNumber != NULL) { + wolfSSL_ASN1_INTEGER_free(x509->serialNumber); + } + #endif + if (x509->extKeyUsageSrc != NULL) { + XFREE(x509->extKeyUsageSrc, x509->heap, DYNAMIC_TYPE_X509_EXT); + x509->extKeyUsageSrc= NULL; + } + #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + #if defined(OPENSSL_ALL) + if (x509->algor.algorithm) { + wolfSSL_ASN1_OBJECT_free(x509->algor.algorithm); + x509->algor.algorithm = NULL; + } + if (x509->key.algor) { + wolfSSL_X509_ALGOR_free(x509->key.algor); + x509->key.algor = NULL; + } + if (x509->key.pkey) { + wolfSSL_EVP_PKEY_free(x509->key.pkey); + x509->key.pkey = NULL; + } + #endif /* OPENSSL_ALL */ + if (x509->altNames) { + FreeAltNames(x509->altNames, x509->heap); + x509->altNames = NULL; + } + + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + wc_FreeMutex(&x509->refMutex); + #endif +} + + +#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT) +#if !defined(WOLFSSL_NO_TLS12) +/* Encode the signature algorithm into buffer. + * + * hashalgo The hash algorithm. + * hsType The signature type. + * output The buffer to encode into. + */ +static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) +{ + switch (hsType) { +#ifdef HAVE_ECC + case ecc_dsa_sa_algo: + output[0] = hashAlgo; + output[1] = ecc_dsa_sa_algo; + break; +#endif +#ifdef HAVE_ED25519 + case ed25519_sa_algo: + output[0] = ED25519_SA_MAJOR; + output[1] = ED25519_SA_MINOR; + (void)hashAlgo; + break; +#endif +#ifdef HAVE_ED448 + case ed448_sa_algo: + output[0] = ED448_SA_MAJOR; + output[1] = ED448_SA_MINOR; + (void)hashAlgo; + break; +#endif +#ifndef NO_RSA + case rsa_sa_algo: + output[0] = hashAlgo; + output[1] = rsa_sa_algo; + break; + #ifdef WC_RSA_PSS + /* PSS signatures: 0x080[4-6] */ + case rsa_pss_sa_algo: + output[0] = rsa_pss_sa_algo; + output[1] = hashAlgo; + break; + #endif +#endif + } + (void)hashAlgo; + (void)output; +} +#endif + +#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_NO_CLIENT_AUTH) +static void SetDigest(WOLFSSL* ssl, int hashAlgo) +{ + switch (hashAlgo) { + #ifndef NO_SHA + case sha_mac: + ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha; + ssl->buffers.digest.length = WC_SHA_DIGEST_SIZE; + break; + #endif /* !NO_SHA */ + #ifndef NO_SHA256 + case sha256_mac: + ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha256; + ssl->buffers.digest.length = WC_SHA256_DIGEST_SIZE; + break; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha384; + ssl->buffers.digest.length = WC_SHA384_DIGEST_SIZE; + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case sha512_mac: + ssl->buffers.digest.buffer = ssl->hsHashes->certHashes.sha512; + ssl->buffers.digest.length = WC_SHA512_DIGEST_SIZE; + break; + #endif /* WOLFSSL_SHA512 */ + } /* switch */ +} +#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_NO_CLIENT_AUTH */ +#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */ +#endif /* !NO_CERTS */ + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +static word32 MacSize(WOLFSSL* ssl) +{ +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 digestSz = ssl->specs.hash_size; +#endif + + return digestSz; +} +#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ + +#ifndef NO_RSA +#ifndef WOLFSSL_NO_TLS12 +#if !defined(NO_WOLFSSL_SERVER) || (!defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_CLIENT_AUTH)) +static int TypeHash(int hashAlgo) +{ + switch (hashAlgo) { + #ifdef WOLFSSL_SHA512 + case sha512_mac: + return SHA512h; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + return SHA384h; + #endif + #ifndef NO_SHA256 + case sha256_mac: + return SHA256h; + #endif + #ifdef WOLFSSL_SHA224 + case sha224_mac: + return SHA224h; + #endif + #ifndef NO_SHA + case sha_mac: + return SHAh; + #endif + } + + return 0; +} +#endif /* !NO_WOLFSSL_SERVER && !NO_WOLFSSL_CLIENT */ +#endif /* !WOLFSSL_NO_TLS12 */ + +#if defined(WC_RSA_PSS) +int ConvertHashPss(int hashAlgo, enum wc_HashType* hashType, int* mgf) +{ + switch (hashAlgo) { + #ifdef WOLFSSL_SHA512 + case sha512_mac: + *hashType = WC_HASH_TYPE_SHA512; + if (mgf != NULL) + *mgf = WC_MGF1SHA512; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + *hashType = WC_HASH_TYPE_SHA384; + if (mgf != NULL) + *mgf = WC_MGF1SHA384; + break; + #endif + #ifndef NO_SHA256 + case sha256_mac: + *hashType = WC_HASH_TYPE_SHA256; + if (mgf != NULL) + *mgf = WC_MGF1SHA256; + break; + #endif + default: + return BAD_FUNC_ARG; + } + + return 0; +} +#endif + +#if !defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH) +int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, int sigAlgo, int hashAlgo, RsaKey* key, + DerBuffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + (void)sigAlgo; + (void)hashAlgo; + + WOLFSSL_ENTER("RsaSign"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + if (key) { + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; + } +#endif + +#if defined(WC_RSA_PSS) + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int mgf = 0; + + ret = ConvertHashPss(hashAlgo, &hashType, &mgf); + if (ret != 0) + return ret; + + #if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->RsaPssSignCb) { + void* ctx = wolfSSL_GetRsaPssSignCtx(ssl); + ret = ssl->ctx->RsaPssSignCb(ssl, in, inSz, out, outSz, + TypeHash(hashAlgo), mgf, + keyBuf, keySz, ctx); + } + else + #endif + { + ret = wc_RsaPSS_Sign(in, inSz, out, *outSz, hashType, mgf, key, + ssl->rng); + } + } + else +#endif +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->RsaSignCb) { + void* ctx = wolfSSL_GetRsaSignCtx(ssl); + ret = ssl->ctx->RsaSignCb(ssl, in, inSz, out, outSz, keyBuf, keySz, + ctx); + } + else +#endif /*HAVE_PK_CALLBACKS */ + ret = wc_RsaSSL_Sign(in, inSz, out, *outSz, key, ssl->rng); + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (key && ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* For positive response return in outSz */ + if (ret > 0) { + *outSz = ret; + ret = 0; + } + + WOLFSSL_LEAVE("RsaSign", ret); + + return ret; +} +#endif + +int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, int sigAlgo, + int hashAlgo, RsaKey* key, buffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + (void)sigAlgo; + (void)hashAlgo; + + WOLFSSL_ENTER("RsaVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#if defined(WC_RSA_PSS) + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int mgf = 0; + + ret = ConvertHashPss(hashAlgo, &hashType, &mgf); + if (ret != 0) + return ret; +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaPssVerifyCb) { + void* ctx = wolfSSL_GetRsaPssVerifyCtx(ssl); + ret = ssl->ctx->RsaPssVerifyCb(ssl, in, inSz, out, + TypeHash(hashAlgo), mgf, + keyBuf, keySz, ctx); + } + else +#endif /*HAVE_PK_CALLBACKS */ + ret = wc_RsaPSS_VerifyInline(in, inSz, out, hashType, mgf, key); + } + else +#endif +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaVerifyCb) { + void* ctx = wolfSSL_GetRsaVerifyCtx(ssl); + ret = ssl->ctx->RsaVerifyCb(ssl, in, inSz, out, keyBuf, keySz, ctx); + } + else +#endif /*HAVE_PK_CALLBACKS */ + { + ret = wc_RsaSSL_VerifyInline(in, inSz, out, key); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("RsaVerify", ret); + + return ret; +} + +/* Verify RSA signature, 0 on success */ +/* This function is used to check the sign result */ +int VerifyRsaSign(WOLFSSL* ssl, byte* verifySig, word32 sigSz, + const byte* plain, word32 plainSz, int sigAlgo, int hashAlgo, RsaKey* key, + DerBuffer* keyBufInfo) +{ + byte* out = NULL; /* inline result */ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + (void)sigAlgo; + (void)hashAlgo; + + WOLFSSL_ENTER("VerifyRsaSign"); + + if (verifySig == NULL || plain == NULL) { + return BAD_FUNC_ARG; + } + + if (sigSz > ENCRYPT_LEN) { + WOLFSSL_MSG("Signature buffer too big"); + return BUFFER_E; + } + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + if (key) { + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; + } +#endif + +#if defined(WC_RSA_PSS) + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int mgf = 0; + + ret = ConvertHashPss(hashAlgo, &hashType, &mgf); + if (ret != 0) + return ret; + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaPssSignCheckCb) { + /* The key buffer includes private/public portion, + but only public is used */ + /* If HSM hardware is checking the signature result you can + optionally skip the sign check and return 0 */ + /* The ctx here is the RsaSignCtx set using wolfSSL_SetRsaSignCtx */ + void* ctx = wolfSSL_GetRsaPssSignCtx(ssl); + ret = ssl->ctx->RsaPssSignCheckCb(ssl, verifySig, sigSz, &out, + TypeHash(hashAlgo), mgf, + keyBuf, keySz, ctx); + if (ret > 0) { + ret = wc_RsaPSS_CheckPadding(plain, plainSz, out, ret, + hashType); + if (ret != 0) + ret = VERIFY_CERT_ERROR; + } + } + else + #endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_RsaPSS_VerifyInline(verifySig, sigSz, &out, hashType, mgf, + key); + if (ret > 0) { + #ifdef HAVE_SELFTEST + ret = wc_RsaPSS_CheckPadding(plain, plainSz, out, ret, + hashType); + #else + ret = wc_RsaPSS_CheckPadding_ex(plain, plainSz, out, ret, + hashType, -1, + mp_count_bits(&key->n)); + #endif + if (ret != 0) + ret = VERIFY_CERT_ERROR; + } + } + + } + else +#endif /* WC_RSA_PSS */ + { + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaSignCheckCb) { + /* The key buffer includes private/public portion, + but only public is used */ + /* If HSM hardware is checking the signature result you can + optionally skip the sign check and return 0 */ + /* The ctx here is the RsaSignCtx set using wolfSSL_SetRsaSignCtx */ + void* ctx = wolfSSL_GetRsaSignCtx(ssl); + ret = ssl->ctx->RsaSignCheckCb(ssl, verifySig, sigSz, &out, + keyBuf, keySz, ctx); + } + else + #endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_RsaSSL_VerifyInline(verifySig, sigSz, &out, key); + } + + if (ret > 0) { + if (ret != (int)plainSz || !out || + XMEMCMP(plain, out, plainSz) != 0) { + WOLFSSL_MSG("RSA Signature verification failed"); + ret = RSA_SIGN_FAULT; + } else { + ret = 0; /* RSA reset */ + } + } + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (key && ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("VerifyRsaSign", ret); + + return ret; +} + +#ifndef WOLFSSL_NO_TLS12 + +#if !defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH) +int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, word32* outSz, + RsaKey* key, DerBuffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("RsaDec"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaDecCb) { + void* ctx = wolfSSL_GetRsaDecCtx(ssl); + ret = ssl->ctx->RsaDecCb(ssl, in, inSz, out, keyBuf, keySz, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + #ifdef WC_RSA_BLINDING + ret = wc_RsaSetRNG(key, ssl->rng); + if (ret != 0) + return ret; + #endif + ret = wc_RsaPrivateDecryptInline(in, inSz, out, key); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* For positive response return in outSz */ + if (ret > 0) { + *outSz = ret; + ret = 0; + } + + WOLFSSL_LEAVE("RsaDec", ret); + + return ret; +} +#endif /* !NO_WOLFSSL_SERVER) || !WOLFSSL_NO_CLIENT_AUTH */ + +int RsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, + RsaKey* key, buffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("RsaEnc"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaEncCb) { + void* ctx = wolfSSL_GetRsaEncCtx(ssl); + ret = ssl->ctx->RsaEncCb(ssl, in, inSz, out, outSz, keyBuf, keySz, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_RsaPublicEncrypt(in, inSz, out, *outSz, key, ssl->rng); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* For positive response return in outSz */ + if (ret > 0) { + *outSz = ret; + ret = 0; + } + + WOLFSSL_LEAVE("RsaEnc", ret); + + return ret; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#endif /* NO_RSA */ + +#ifdef HAVE_ECC + +int EccSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, ecc_key* key, DerBuffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("EccSign"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + if (key) { + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; + } +#endif + +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->EccSignCb) { + void* ctx = wolfSSL_GetEccSignCtx(ssl); + ret = ssl->ctx->EccSignCb(ssl, in, inSz, out, outSz, keyBuf, + keySz, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ecc_sign_hash(in, inSz, out, outSz, ssl->rng, key); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (key && ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("EccSign", ret); + + return ret; +} + +int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* out, + word32 outSz, ecc_key* key, buffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("EccVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccVerifyCb) { + void* ctx = wolfSSL_GetEccVerifyCtx(ssl); + ret = ssl->ctx->EccVerifyCb(ssl, in, inSz, out, outSz, keyBuf, keySz, + &ssl->eccVerifyRes, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ecc_verify_hash(in, inSz, out, outSz, &ssl->eccVerifyRes, key); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } + else +#endif /* WOLFSSL_ASYNC_CRYPT */ + { + ret = (ret != 0 || ssl->eccVerifyRes == 0) ? VERIFY_SIGN_ERROR : 0; + } + + WOLFSSL_LEAVE("EccVerify", ret); + + return ret; +} + +#ifdef HAVE_PK_CALLBACKS + /* Gets ECC key for shared secret callback testing + * Client side: returns peer key + * Server side: returns private key + */ + static int EccGetKey(WOLFSSL* ssl, ecc_key** otherKey) + { + int ret = NO_PEER_KEY; + ecc_key* tmpKey = NULL; + + if (ssl == NULL || otherKey == NULL) { + return BAD_FUNC_ARG; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->specs.static_ecdh) { + if (!ssl->peerEccDsaKey || !ssl->peerEccDsaKeyPresent || + !ssl->peerEccDsaKey->dp) { + return NO_PEER_KEY; + } + tmpKey = (struct ecc_key*)ssl->peerEccDsaKey; + } + else { + if (!ssl->peerEccKey || !ssl->peerEccKeyPresent || + !ssl->peerEccKey->dp) { + return NO_PEER_KEY; + } + tmpKey = (struct ecc_key*)ssl->peerEccKey; + } + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->specs.static_ecdh) { + if (ssl->hsKey == NULL) { + return NO_PRIVATE_KEY; + } + tmpKey = (struct ecc_key*)ssl->hsKey; + } + else { + if (!ssl->eccTempKeyPresent) { + return NO_PRIVATE_KEY; + } + tmpKey = (struct ecc_key*)ssl->eccTempKey; + } + } + + if (tmpKey) { + *otherKey = tmpKey; + ret = 0; + } + + return ret; + } +#endif /* HAVE_PK_CALLBACKS */ + +int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key, + byte* pubKeyDer, word32* pubKeySz, byte* out, word32* outlen, + int side) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + ecc_key* otherKey = NULL; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV* asyncDev = &priv_key->asyncDev; +#endif + + (void)ssl; + (void)pubKeyDer; + (void)pubKeySz; + (void)side; + + WOLFSSL_ENTER("EccSharedSecret"); + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccSharedSecretCb) { + ret = EccGetKey(ssl, &otherKey); + if (ret != 0) + return ret; + #ifdef WOLFSSL_ASYNC_CRYPT + asyncDev = &otherKey->asyncDev; + #endif + } +#endif + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccSharedSecretCb) { + void* ctx = wolfSSL_GetEccSharedSecretCtx(ssl); + ret = ssl->ctx->EccSharedSecretCb(ssl, otherKey, pubKeyDer, + pubKeySz, out, outlen, side, ctx); + } + else +#endif + { + ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("EccSharedSecret", ret); + + return ret; +} + +int EccMakeKey(WOLFSSL* ssl, ecc_key* key, ecc_key* peer) +{ + int ret = 0; + int keySz = 0; + int ecc_curve = ECC_CURVE_DEF; + + WOLFSSL_ENTER("EccMakeKey"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_NONE); + if (ret != 0) + return ret; +#endif + + /* get key size */ + if (peer == NULL) { + keySz = ssl->eccTempKeySz; + } + else { + keySz = peer->dp->size; + } + + /* get curve type */ + if (ssl->ecdhCurveOID > 0) { + ecc_curve = wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, NULL); + } + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccKeyGenCb) { + void* ctx = wolfSSL_GetEccKeyGenCtx(ssl); + ret = ssl->ctx->EccKeyGenCb(ssl, key, keySz, ecc_curve, ctx); + } + else +#endif + { + ret = wc_ecc_make_key_ex(ssl->rng, keySz, key, ecc_curve); + } + + /* make sure the curve is set for TLS */ + if (ret == 0 && key->dp) { + ssl->ecdhCurveOID = key->dp->oidSum; + #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE) + ssl->namedGroup = 0; + #endif + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("EccMakeKey", ret); + + return ret; +} +#endif /* HAVE_ECC */ + +#ifdef HAVE_ED25519 +/* Check whether the key contains a public key. + * If not then pull it out of the leaf certificate. + * + * ssl SSL/TLS object. + * returns MEMORY_E when unable to allocate memory, a parsing error, otherwise + * 0 on success. + */ +int Ed25519CheckPubKey(WOLFSSL* ssl) +{ + ed25519_key* key = (ed25519_key*)ssl->hsKey; + int ret = 0; + + /* Public key required for signing. */ + if (!key->pubKeySet) { + DerBuffer* leaf = ssl->buffers.certificate; + DecodedCert* cert = (DecodedCert*)XMALLOC(sizeof(*cert), + ssl->heap, DYNAMIC_TYPE_DCERT); + if (cert == NULL) + ret = MEMORY_E; + + if (ret == 0) { + InitDecodedCert(cert, leaf->buffer, leaf->length, ssl->heap); + ret = DecodeToKey(cert, 0); + } + if (ret == 0) { + ret = wc_ed25519_import_public(cert->publicKey, cert->pubKeySize, + key); + } + if (cert != NULL) { + FreeDecodedCert(cert); + XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT); + } + } + + return ret; +} + +/* Sign the data using EdDSA and key using Ed25519. + * + * ssl SSL object. + * in Data or message to sign. + * inSz Length of the data. + * out Buffer to hold signature. + * outSz On entry, size of the buffer. On exit, the size of the signature. + * key The private Ed25519 key data. + * keySz The length of the private key data in bytes. + * ctx The callback context. + * returns 0 on success, otherwise the value is an error. + */ +int Ed25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, ed25519_key* key, DerBuffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("Ed25519Sign"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->Ed25519SignCb) { + void* ctx = wolfSSL_GetEd25519SignCtx(ssl); + ret = ssl->ctx->Ed25519SignCb(ssl, in, inSz, out, outSz, keyBuf, + keySz, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ed25519_sign_msg(in, inSz, out, outSz, key); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("Ed25519Sign", ret); + + return ret; +} + +/* Verify the data using EdDSA and key using Ed25519. + * + * ssl SSL object. + * in Signature data. + * inSz Length of the signature data in bytes. + * msg Message to verify. + * outSz Length of message in bytes. + * key The public Ed25519 key data. + * keySz The length of the private key data in bytes. + * ctx The callback context. + * returns 0 on success, otherwise the value is an error. + */ +int Ed25519Verify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* msg, + word32 msgSz, ed25519_key* key, buffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("Ed25519Verify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->Ed25519VerifyCb) { + void* ctx = wolfSSL_GetEd25519VerifyCtx(ssl); + ret = ssl->ctx->Ed25519VerifyCb(ssl, in, inSz, msg, msgSz, keyBuf, + keySz, &ssl->eccVerifyRes, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ed25519_verify_msg(in, inSz, msg, msgSz, + &ssl->eccVerifyRes, key); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } + else +#endif /* WOLFSSL_ASYNC_CRYPT */ + { + ret = (ret != 0 || ssl->eccVerifyRes == 0) ? VERIFY_SIGN_ERROR : 0; + } + + WOLFSSL_LEAVE("Ed25519Verify", ret); + + return ret; +} +#endif /* HAVE_ED25519 */ + +#ifndef WOLFSSL_NO_TLS12 + +#ifdef HAVE_CURVE25519 +#ifdef HAVE_PK_CALLBACKS + /* Gets X25519 key for shared secret callback testing + * Client side: returns peer key + * Server side: returns private key + */ + static int X25519GetKey(WOLFSSL* ssl, curve25519_key** otherKey) + { + int ret = NO_PEER_KEY; + struct curve25519_key* tmpKey = NULL; + + if (ssl == NULL || otherKey == NULL) { + return BAD_FUNC_ARG; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->peerX25519Key || !ssl->peerX25519KeyPresent || + !ssl->peerX25519Key->dp) { + return NO_PEER_KEY; + } + tmpKey = (struct curve25519_key*)ssl->peerX25519Key; + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + if (!ssl->eccTempKeyPresent) { + return NO_PRIVATE_KEY; + } + tmpKey = (struct curve25519_key*)ssl->eccTempKey; + } + + if (tmpKey) { + *otherKey = (curve25519_key *)tmpKey; + ret = 0; + } + + return ret; + } +#endif /* HAVE_PK_CALLBACKS */ + +static int X25519SharedSecret(WOLFSSL* ssl, curve25519_key* priv_key, + curve25519_key* pub_key, byte* pubKeyDer, word32* pubKeySz, + byte* out, word32* outlen, int side) +{ + int ret; + + (void)ssl; + (void)pubKeyDer; + (void)pubKeySz; + (void)side; + + WOLFSSL_ENTER("X25519SharedSecret"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->X25519SharedSecretCb) { + curve25519_key* otherKey = NULL; + + ret = X25519GetKey(ssl, &otherKey); + if (ret == 0) { + void* ctx = wolfSSL_GetX25519SharedSecretCtx(ssl); + ret = ssl->ctx->X25519SharedSecretCb(ssl, otherKey, pubKeyDer, + pubKeySz, out, outlen, side, ctx); + } + } + else +#endif + { + ret = wc_curve25519_shared_secret_ex(priv_key, pub_key, out, outlen, + EC25519_LITTLE_ENDIAN); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &priv_key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("X25519SharedSecret", ret); + + return ret; +} + +static int X25519MakeKey(WOLFSSL* ssl, curve25519_key* key, + curve25519_key* peer) +{ + int ret = 0; + + (void)peer; + + WOLFSSL_ENTER("X25519MakeKey"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_NONE); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->X25519KeyGenCb) { + void* ctx = wolfSSL_GetX25519KeyGenCtx(ssl); + ret = ssl->ctx->X25519KeyGenCb(ssl, key, CURVE25519_KEYSIZE, ctx); + } + else +#endif + { + ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key); + } + + if (ret == 0) { + ssl->ecdhCurveOID = ECC_X25519_OID; + #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE) + ssl->namedGroup = 0; + #endif + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("X25519MakeKey", ret); + + return ret; +} +#endif /* HAVE_CURVE25519 */ + +#ifdef HAVE_ED448 +/* Check whether the key contains a public key. + * If not then pull it out of the leaf certificate. + * + * ssl SSL/TLS object. + * returns MEMORY_E when unable to allocate memory, a parsing error, otherwise + * 0 on success. + */ +int Ed448CheckPubKey(WOLFSSL* ssl) +{ + ed448_key* key = (ed448_key*)ssl->hsKey; + int ret = 0; + + /* Public key required for signing. */ + if (!key->pubKeySet) { + DerBuffer* leaf = ssl->buffers.certificate; + DecodedCert* cert = (DecodedCert*)XMALLOC(sizeof(*cert), ssl->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + ret = MEMORY_E; + + if (ret == 0) { + InitDecodedCert(cert, leaf->buffer, leaf->length, ssl->heap); + ret = DecodeToKey(cert, 0); + } + if (ret == 0) { + ret = wc_ed448_import_public(cert->publicKey, cert->pubKeySize, + key); + } + if (cert != NULL) { + FreeDecodedCert(cert); + XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT); + } + } + + return ret; +} + +/* Sign the data using EdDSA and key using Ed448. + * + * ssl SSL object. + * in Data or message to sign. + * inSz Length of the data. + * out Buffer to hold signature. + * outSz On entry, size of the buffer. On exit, the size of the signature. + * key The private Ed448 key data. + * keySz The length of the private key data in bytes. + * ctx The callback context. + * returns 0 on success, otherwise the value is an error. + */ +int Ed448Sign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, ed448_key* key, DerBuffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("Ed448Sign"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->Ed448SignCb) { + void* ctx = wolfSSL_GetEd448SignCtx(ssl); + ret = ssl->ctx->Ed448SignCb(ssl, in, inSz, out, outSz, keyBuf, keySz, + ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ed448_sign_msg(in, inSz, out, outSz, key, NULL, 0); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("Ed448Sign", ret); + + return ret; +} + +/* Verify the data using EdDSA and key using Ed448. + * + * ssl SSL object. + * in Signature data. + * inSz Length of the signature data in bytes. + * msg Message to verify. + * outSz Length of message in bytes. + * key The public Ed448 key data. + * keySz The length of the private key data in bytes. + * ctx The callback context. + * returns 0 on success, otherwise the value is an error. + */ +int Ed448Verify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* msg, + word32 msgSz, ed448_key* key, buffer* keyBufInfo) +{ + int ret; +#ifdef HAVE_PK_CALLBACKS + const byte* keyBuf = NULL; + word32 keySz = 0; + + if (keyBufInfo) { + keyBuf = keyBufInfo->buffer; + keySz = keyBufInfo->length; + } +#endif + + (void)ssl; + (void)keyBufInfo; + + WOLFSSL_ENTER("Ed448Verify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->Ed448VerifyCb) { + void* ctx = wolfSSL_GetEd448VerifyCtx(ssl); + ret = ssl->ctx->Ed448VerifyCb(ssl, in, inSz, msg, msgSz, keyBuf, keySz, + &ssl->eccVerifyRes, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ed448_verify_msg(in, inSz, msg, msgSz, &ssl->eccVerifyRes, key, + NULL, 0); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } + else +#endif /* WOLFSSL_ASYNC_CRYPT */ + { + ret = (ret != 0 || ssl->eccVerifyRes == 0) ? VERIFY_SIGN_ERROR : 0; + } + + WOLFSSL_LEAVE("Ed448Verify", ret); + + return ret; +} +#endif /* HAVE_ED448 */ + +#ifdef HAVE_CURVE448 +#ifdef HAVE_PK_CALLBACKS + /* Gets X448 key for shared secret callback testing + * Client side: returns peer key + * Server side: returns private key + */ + static int X448GetKey(WOLFSSL* ssl, curve448_key** otherKey) + { + int ret = NO_PEER_KEY; + struct curve448_key* tmpKey = NULL; + + if (ssl == NULL || otherKey == NULL) { + return BAD_FUNC_ARG; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->peerX448Key || !ssl->peerX448KeyPresent) { + return NO_PEER_KEY; + } + tmpKey = (struct curve448_key*)ssl->peerX448Key; + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + if (!ssl->eccTempKeyPresent) { + return NO_PRIVATE_KEY; + } + tmpKey = (struct curve448_key*)ssl->eccTempKey; + } + + if (tmpKey) { + *otherKey = (curve448_key *)tmpKey; + ret = 0; + } + + return ret; + } +#endif /* HAVE_PK_CALLBACKS */ + +static int X448SharedSecret(WOLFSSL* ssl, curve448_key* priv_key, + curve448_key* pub_key, byte* pubKeyDer, + word32* pubKeySz, byte* out, word32* outlen, + int side) +{ + int ret; + + (void)ssl; + (void)pubKeyDer; + (void)pubKeySz; + (void)side; + + WOLFSSL_ENTER("X448SharedSecret"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->X448SharedSecretCb) { + curve448_key* otherKey = NULL; + + ret = X448GetKey(ssl, &otherKey); + if (ret == 0) { + void* ctx = wolfSSL_GetX448SharedSecretCtx(ssl); + ret = ssl->ctx->X448SharedSecretCb(ssl, otherKey, pubKeyDer, + pubKeySz, out, outlen, side, ctx); + } + } + else +#endif + { + ret = wc_curve448_shared_secret_ex(priv_key, pub_key, out, outlen, + EC448_LITTLE_ENDIAN); + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &priv_key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("X448SharedSecret", ret); + + return ret; +} + +static int X448MakeKey(WOLFSSL* ssl, curve448_key* key, curve448_key* peer) +{ + int ret = 0; + + (void)peer; + + WOLFSSL_ENTER("X448MakeKey"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_NONE); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->X448KeyGenCb) { + void* ctx = wolfSSL_GetX448KeyGenCtx(ssl); + ret = ssl->ctx->X448KeyGenCb(ssl, key, CURVE448_KEY_SIZE, ctx); + } + else +#endif + { + ret = wc_curve448_make_key(ssl->rng, CURVE448_KEY_SIZE, key); + } + + if (ret == 0) { + ssl->ecdhCurveOID = ECC_X448_OID; + #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE) + ssl->namedGroup = 0; + #endif + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &key->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("X448MakeKey", ret); + + return ret; +} +#endif /* HAVE_CURVE448 */ + +#if !defined(NO_CERTS) || !defined(NO_PSK) +#if !defined(NO_DH) + +int DhGenKeyPair(WOLFSSL* ssl, DhKey* dhKey, + byte* priv, word32* privSz, + byte* pub, word32* pubSz) +{ + int ret; + + WOLFSSL_ENTER("DhGenKeyPair"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE); + if (ret != 0) + return ret; +#endif + + ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, priv, privSz, pub, pubSz); + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &dhKey->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("DhGenKeyPair", ret); + + return ret; +} + +int DhAgree(WOLFSSL* ssl, DhKey* dhKey, + const byte* priv, word32 privSz, + const byte* otherPub, word32 otherPubSz, + byte* agree, word32* agreeSz) +{ + int ret; + + (void)ssl; + + WOLFSSL_ENTER("DhAgree"); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE); + if (ret != 0) + return ret; +#endif + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->DhAgreeCb) { + void* ctx = wolfSSL_GetDhAgreeCtx(ssl); + + WOLFSSL_MSG("Calling DhAgree Callback Function"); + ret = ssl->ctx->DhAgreeCb(ssl, dhKey, priv, privSz, + otherPub, otherPubSz, agree, agreeSz, ctx); + } + else +#endif + { +#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) + ret = wc_DhCheckPubValue(ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, otherPub, otherPubSz); + if (ret != 0) { + #ifdef OPENSSL_EXTRA + SendAlert(ssl, alert_fatal, illegal_parameter); + #endif + } + else +#endif + { + ret = wc_DhAgree(dhKey, agree, agreeSz, priv, privSz, otherPub, + otherPubSz); + } + } + + /* Handle async pending response */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &dhKey->asyncDev); + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + WOLFSSL_LEAVE("DhAgree", ret); + + return ret; +} +#endif /* !NO_DH */ +#endif /* !NO_CERTS || !NO_PSK */ + +#endif /* !WOLFSSL_NO_TLS12 */ + + +#ifdef HAVE_PK_CALLBACKS +int wolfSSL_IsPrivatePkSet(WOLFSSL* ssl) +{ + int pkcbset = 0; + (void)ssl; + +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + !defined(NO_RSA) + if (0 + #ifdef HAVE_ECC + || (ssl->ctx->EccSignCb != NULL && + ssl->buffers.keyType == ecc_dsa_sa_algo) + #endif + #ifdef HAVE_ED25519 + || (ssl->ctx->Ed25519SignCb != NULL && + ssl->buffers.keyType == ed25519_sa_algo) + #endif + #ifdef HAVE_ED448 + || (ssl->ctx->Ed448SignCb != NULL && + ssl->buffers.keyType == ed448_sa_algo) + #endif + #ifndef NO_RSA + || (ssl->ctx->RsaSignCb != NULL && ssl->buffers.keyType == rsa_sa_algo) + || (ssl->ctx->RsaDecCb != NULL && ssl->buffers.keyType == rsa_kea) + #ifdef WC_RSA_PSS + || (ssl->ctx->RsaPssSignCb != NULL && + ssl->buffers.keyType == rsa_pss_sa_algo) + #endif + #endif + ) { + pkcbset = 1; + } +#endif + return pkcbset; +} + +int wolfSSL_CTX_IsPrivatePkSet(WOLFSSL_CTX* ctx) +{ + int pkcbset = 0; + (void)ctx; +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + !defined(NO_RSA) + if (0 + #ifdef HAVE_ECC + || ctx->EccSignCb != NULL + #endif + #ifdef HAVE_ED25519 + || ctx->Ed25519SignCb != NULL + #endif + #ifdef HAVE_ED448 + || ctx->Ed448SignCb != NULL + #endif + #ifndef NO_RSA + || ctx->RsaSignCb != NULL + || ctx->RsaDecCb != NULL + #ifdef WC_RSA_PSS + || ctx->RsaPssSignCb != NULL + #endif + #endif + ) { + pkcbset = 1; + } +#endif + return pkcbset; +} +#endif /* HAVE_PK_CALLBACKS */ + + +int InitSSL_Suites(WOLFSSL* ssl) +{ + int keySz = 0; + byte havePSK = 0; + byte haveAnon = 0; + byte haveRSA = 0; + byte haveMcast = 0; + + (void)haveAnon; /* Squash unused var warnings */ + (void)haveMcast; + + if (!ssl) + return BAD_FUNC_ARG; + +#ifndef NO_RSA + haveRSA = 1; +#endif +#ifndef NO_PSK + havePSK = (byte)ssl->options.havePSK; +#endif /* NO_PSK */ +#ifdef HAVE_ANON + haveAnon = (byte)ssl->options.haveAnon; +#endif /* HAVE_ANON*/ +#ifdef WOLFSSL_MULTICAST + haveMcast = (byte)ssl->options.haveMcast; +#endif /* WOLFSSL_MULTICAST */ + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->options.side == WOLFSSL_SERVER_END) + ssl->options.maxEarlyDataSz = ssl->ctx->maxEarlyDataSz; +#endif +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + ssl->options.cacheMessages = ssl->options.side == WOLFSSL_SERVER_END || + ssl->buffers.keyType == ed25519_sa_algo || + ssl->buffers.keyType == ed448_sa_algo; +#endif + +#ifndef NO_CERTS + keySz = ssl->buffers.keySz; +#endif + + /* make sure server has DH parms, and add PSK if there, add NTRU too */ + if (ssl->options.side == WOLFSSL_SERVER_END) { + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + else { + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + TRUE, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + +#if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT) + /* make sure server has cert and key unless using PSK, Anon, or + * Multicast. This should be true even if just switching ssl ctx */ + if (ssl->options.side == WOLFSSL_SERVER_END && + !havePSK && !haveAnon && !haveMcast) { + + /* server certificate must be loaded */ + if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer) { + WOLFSSL_MSG("Server missing certificate"); + return NO_PRIVATE_KEY; + } + + /* allow no private key if using PK callbacks and CB is set */ + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + WOLFSSL_MSG("Using PK for server private key"); + } + else + #endif + if (!ssl->buffers.key || !ssl->buffers.key->buffer) { + WOLFSSL_MSG("Server missing private key"); + return NO_PRIVATE_KEY; + } + } +#endif + + return WOLFSSL_SUCCESS; +} + +/* returns new reference count. Arg incr positive=up or negative=down */ +int SSL_CTX_RefCount(WOLFSSL_CTX* ctx, int incr) +{ + int refCount; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + if (wc_LockMutex(&ctx->countMutex) != 0) { + WOLFSSL_MSG("Couldn't lock CTX count mutex"); + return BAD_MUTEX_E; + } + + ctx->refCount += incr; + /* make sure refCount is never negative */ + if (ctx->refCount < 0) { + ctx->refCount = 0; + } + refCount = ctx->refCount; + + wc_UnLockMutex(&ctx->countMutex); + + return refCount; +} + +/* This function inherits a WOLFSSL_CTX's fields into an SSL object. + It is used during initialization and to switch an ssl's CTX with + wolfSSL_Set_SSL_CTX. Requires ssl->suites alloc and ssl-arrays with PSK + unless writeDup is on. + + ssl object to initialize + ctx parent factory + writeDup flag indicating this is a write dup only + + WOLFSSL_SUCCESS return value on success */ +int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) +{ + int ret; + byte newSSL; + + if (!ssl || !ctx) + return BAD_FUNC_ARG; + +#ifndef SINGLE_THREADED + if (ssl->suites == NULL && !writeDup) + return BAD_FUNC_ARG; +#endif + + newSSL = ssl->ctx == NULL; /* Assign after null check */ + +#ifndef NO_PSK + if (ctx->server_hint[0] && ssl->arrays == NULL && !writeDup) { + return BAD_FUNC_ARG; /* needed for copy below */ + } +#endif + + /* decrement previous CTX reference count if exists. + * This should only happen if switching ctxs!*/ + if (!newSSL) { + WOLFSSL_MSG("freeing old ctx to decrement reference count. Switching ctx."); + wolfSSL_CTX_free(ssl->ctx); + } + + /* increment CTX reference count */ + if ((ret = SSL_CTX_RefCount(ctx, 1)) < 0) { + return ret; + } + ret = WOLFSSL_SUCCESS; /* set default ret */ + + ssl->ctx = ctx; /* only for passing to calls, options could change */ + ssl->version = ctx->method->version; + +#ifdef HAVE_ECC + ssl->eccTempKeySz = ctx->eccTempKeySz; + ssl->ecdhCurveOID = ctx->ecdhCurveOID; +#endif +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + ssl->pkCurveOID = ctx->pkCurveOID; +#endif + +#ifdef OPENSSL_EXTRA + ssl->options.mask = ctx->mask; + ssl->CBIS = ctx->CBIS; +#endif + ssl->timeout = ctx->timeout; + ssl->verifyCallback = ctx->verifyCallback; + ssl->options.side = ctx->method->side; + ssl->options.downgrade = ctx->method->downgrade; + ssl->options.minDowngrade = ctx->minDowngrade; + + ssl->options.haveDH = ctx->haveDH; + ssl->options.haveNTRU = ctx->haveNTRU; + ssl->options.haveECDSAsig = ctx->haveECDSAsig; + ssl->options.haveECC = ctx->haveECC; + ssl->options.haveStaticECC = ctx->haveStaticECC; + +#ifndef NO_PSK + ssl->options.havePSK = ctx->havePSK; + ssl->options.client_psk_cb = ctx->client_psk_cb; + ssl->options.server_psk_cb = ctx->server_psk_cb; +#ifdef WOLFSSL_TLS13 + ssl->options.client_psk_tls13_cb = ctx->client_psk_tls13_cb; + ssl->options.server_psk_tls13_cb = ctx->server_psk_tls13_cb; +#endif +#endif /* NO_PSK */ +#ifdef WOLFSSL_EARLY_DATA + if (ssl->options.side == WOLFSSL_SERVER_END) + ssl->options.maxEarlyDataSz = ctx->maxEarlyDataSz; +#endif + +#ifdef HAVE_ANON + ssl->options.haveAnon = ctx->haveAnon; +#endif +#ifndef NO_DH + ssl->options.minDhKeySz = ctx->minDhKeySz; + ssl->options.maxDhKeySz = ctx->maxDhKeySz; +#endif +#ifndef NO_RSA + ssl->options.minRsaKeySz = ctx->minRsaKeySz; +#endif +#ifdef HAVE_ECC + ssl->options.minEccKeySz = ctx->minEccKeySz; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->options.verifyDepth = ctx->verifyDepth; +#endif + + ssl->options.sessionCacheOff = ctx->sessionCacheOff; + ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff; +#ifdef HAVE_EXT_CACHE + ssl->options.internalCacheOff = ctx->internalCacheOff; +#endif + + ssl->options.verifyPeer = ctx->verifyPeer; + ssl->options.verifyNone = ctx->verifyNone; + ssl->options.failNoCert = ctx->failNoCert; + ssl->options.failNoCertxPSK = ctx->failNoCertxPSK; + ssl->options.sendVerify = ctx->sendVerify; + + ssl->options.partialWrite = ctx->partialWrite; + ssl->options.quietShutdown = ctx->quietShutdown; + ssl->options.groupMessages = ctx->groupMessages; + +#ifndef NO_DH + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ssl->options.dhKeyTested = ctx->dhKeyTested; + #endif + ssl->buffers.serverDH_P = ctx->serverDH_P; + ssl->buffers.serverDH_G = ctx->serverDH_G; +#endif + +#ifndef NO_CERTS + /* ctx still owns certificate, certChain, key, dh, and cm */ + ssl->buffers.certificate = ctx->certificate; + ssl->buffers.certChain = ctx->certChain; +#ifdef WOLFSSL_TLS13 + ssl->buffers.certChainCnt = ctx->certChainCnt; +#endif + ssl->buffers.key = ctx->privateKey; + ssl->buffers.keyType = ctx->privateKeyType; + ssl->buffers.keyId = ctx->privateKeyId; + ssl->buffers.keySz = ctx->privateKeySz; + ssl->buffers.keyDevId = ctx->privateKeyDevId; +#endif +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + ssl->options.cacheMessages = ssl->options.side == WOLFSSL_SERVER_END || + ssl->buffers.keyType == ed25519_sa_algo || + ssl->buffers.keyType == ed448_sa_algo; +#endif + + +#ifdef WOLFSSL_ASYNC_CRYPT + ssl->devId = ctx->devId; +#endif + + if (writeDup == 0) { +#ifndef NO_PSK + if (ctx->server_hint[0]) { /* set in CTX */ + XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint, + sizeof(ssl->arrays->server_hint)); + ssl->arrays->server_hint[MAX_PSK_ID_LEN] = '\0'; /* null term */ + } +#endif /* NO_PSK */ + + if (ctx->suites) { +#ifndef SINGLE_THREADED + *ssl->suites = *ctx->suites; +#else + ssl->suites = ctx->suites; +#endif + } + else { + XMEMSET(ssl->suites, 0, sizeof(Suites)); + } + + if (ssl->options.side != WOLFSSL_NEITHER_END) { + /* Defer initializing suites until accept or connect */ + ret = InitSSL_Suites(ssl); + } + } /* writeDup check */ + +#ifdef WOLFSSL_SESSION_EXPORT + #ifdef WOLFSSL_DTLS + ssl->dtls_export = ctx->dtls_export; /* export function for session */ + #endif +#endif + + ssl->CBIORecv = ctx->CBIORecv; + ssl->CBIOSend = ctx->CBIOSend; +#ifdef OPENSSL_EXTRA + ssl->readAhead = ctx->readAhead; +#endif + ssl->verifyDepth = ctx->verifyDepth; + + return ret; +} + +int InitHandshakeHashes(WOLFSSL* ssl) +{ + int ret; + + /* make sure existing handshake hashes are free'd */ + if (ssl->hsHashes != NULL) { + FreeHandshakeHashes(ssl); + } + + /* allocate handshake hashes */ + ssl->hsHashes = (HS_Hashes*)XMALLOC(sizeof(HS_Hashes), ssl->heap, + DYNAMIC_TYPE_HASHES); + if (ssl->hsHashes == NULL) { + WOLFSSL_MSG("HS_Hashes Memory error"); + return MEMORY_E; + } + XMEMSET(ssl->hsHashes, 0, sizeof(HS_Hashes)); + +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + ret = wc_InitMd5_ex(&ssl->hsHashes->hashMd5, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Md5SetFlags(&ssl->hsHashes->hashMd5, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#ifndef NO_SHA + ret = wc_InitSha_ex(&ssl->hsHashes->hashSha, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_ShaSetFlags(&ssl->hsHashes->hashSha, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#endif /* !NO_OLD_TLS */ +#ifndef NO_SHA256 + ret = wc_InitSha256_ex(&ssl->hsHashes->hashSha256, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Sha256SetFlags(&ssl->hsHashes->hashSha256, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#ifdef WOLFSSL_SHA384 + ret = wc_InitSha384_ex(&ssl->hsHashes->hashSha384, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Sha384SetFlags(&ssl->hsHashes->hashSha384, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#ifdef WOLFSSL_SHA512 + ret = wc_InitSha512_ex(&ssl->hsHashes->hashSha512, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Sha512SetFlags(&ssl->hsHashes->hashSha512, WC_HASH_FLAG_WILLCOPY); + #endif +#endif + + return ret; +} + +void FreeHandshakeHashes(WOLFSSL* ssl) +{ + if (ssl->hsHashes) { +#ifndef NO_OLD_TLS + #ifndef NO_MD5 + wc_Md5Free(&ssl->hsHashes->hashMd5); + #endif + #ifndef NO_SHA + wc_ShaFree(&ssl->hsHashes->hashSha); + #endif +#endif /* !NO_OLD_TLS */ + #ifndef NO_SHA256 + wc_Sha256Free(&ssl->hsHashes->hashSha256); + #endif + #ifdef WOLFSSL_SHA384 + wc_Sha384Free(&ssl->hsHashes->hashSha384); + #endif + #ifdef WOLFSSL_SHA512 + wc_Sha512Free(&ssl->hsHashes->hashSha512); + #endif + #if (defined(HAVE_ED25519) || defined(HAVE_ED448)) && \ + !defined(WOLFSSL_NO_CLIENT_AUTH) + if (ssl->hsHashes->messages != NULL) { + XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } + #endif + + XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes = NULL; + } +} + + +/* init everything to 0, NULL, default values before calling anything that may + fail so that destructor has a "good" state to cleanup + + ssl object to initialize + ctx parent factory + writeDup flag indicating this is a write dup only + + 0 on success */ +int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) +{ + int ret; + + XMEMSET(ssl, 0, sizeof(WOLFSSL)); + +#if defined(WOLFSSL_STATIC_MEMORY) + if (ctx->heap != NULL) { + WOLFSSL_HEAP_HINT* ssl_hint; + WOLFSSL_HEAP_HINT* ctx_hint; + + /* avoid dereferencing a test value */ + #ifdef WOLFSSL_HEAP_TEST + if (ctx->heap == (void*)WOLFSSL_HEAP_TEST) { + ssl->heap = ctx->heap; + } + else { + #endif + ssl->heap = (WOLFSSL_HEAP_HINT*)XMALLOC(sizeof(WOLFSSL_HEAP_HINT), + ctx->heap, DYNAMIC_TYPE_SSL); + if (ssl->heap == NULL) { + return MEMORY_E; + } + XMEMSET(ssl->heap, 0, sizeof(WOLFSSL_HEAP_HINT)); + ssl_hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); + ctx_hint = ((WOLFSSL_HEAP_HINT*)(ctx->heap)); + + /* lock and check IO count / handshake count */ + if (wc_LockMutex(&(ctx_hint->memory->memory_mutex)) != 0) { + WOLFSSL_MSG("Bad memory_mutex lock"); + XFREE(ssl->heap, ctx->heap, DYNAMIC_TYPE_SSL); + ssl->heap = NULL; /* free and set to NULL for IO counter */ + return BAD_MUTEX_E; + } + if (ctx_hint->memory->maxHa > 0 && + ctx_hint->memory->maxHa <= ctx_hint->memory->curHa) { + WOLFSSL_MSG("At max number of handshakes for static memory"); + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + XFREE(ssl->heap, ctx->heap, DYNAMIC_TYPE_SSL); + ssl->heap = NULL; /* free and set to NULL for IO counter */ + return MEMORY_E; + } + + if (ctx_hint->memory->maxIO > 0 && + ctx_hint->memory->maxIO <= ctx_hint->memory->curIO) { + WOLFSSL_MSG("At max number of IO allowed for static memory"); + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + XFREE(ssl->heap, ctx->heap, DYNAMIC_TYPE_SSL); + ssl->heap = NULL; /* free and set to NULL for IO counter */ + return MEMORY_E; + } + ctx_hint->memory->curIO++; + ctx_hint->memory->curHa++; + ssl_hint->memory = ctx_hint->memory; + ssl_hint->haFlag = 1; + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + + /* check if tracking stats */ + if (ctx_hint->memory->flag & WOLFMEM_TRACK_STATS) { + ssl_hint->stats = (WOLFSSL_MEM_CONN_STATS*)XMALLOC( + sizeof(WOLFSSL_MEM_CONN_STATS), ctx->heap, DYNAMIC_TYPE_SSL); + if (ssl_hint->stats == NULL) { + return MEMORY_E; + } + XMEMSET(ssl_hint->stats, 0, sizeof(WOLFSSL_MEM_CONN_STATS)); + } + + /* check if using fixed IO buffers */ + if (ctx_hint->memory->flag & WOLFMEM_IO_POOL_FIXED) { + if (wc_LockMutex(&(ctx_hint->memory->memory_mutex)) != 0) { + WOLFSSL_MSG("Bad memory_mutex lock"); + return BAD_MUTEX_E; + } + if (SetFixedIO(ctx_hint->memory, &(ssl_hint->inBuf)) != 1) { + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + return MEMORY_E; + } + if (SetFixedIO(ctx_hint->memory, &(ssl_hint->outBuf)) != 1) { + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + return MEMORY_E; + } + if (ssl_hint->outBuf == NULL || ssl_hint->inBuf == NULL) { + WOLFSSL_MSG("Not enough memory to create fixed IO buffers"); + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + return MEMORY_E; + } + wc_UnLockMutex(&(ctx_hint->memory->memory_mutex)); + } + #ifdef WOLFSSL_HEAP_TEST + } + #endif + } + else { + ssl->heap = ctx->heap; + } +#else + ssl->heap = ctx->heap; /* carry over user heap without static memory */ +#endif /* WOLFSSL_STATIC_MEMORY */ + + ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; + ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; + + ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; + ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; + +#ifdef KEEP_PEER_CERT + InitX509(&ssl->peerCert, 0, ssl->heap); +#endif + + ssl->rfd = -1; /* set to invalid descriptor */ + ssl->wfd = -1; + ssl->devId = ctx->devId; /* device for async HW (from wolfAsync_DevOpen) */ + + ssl->IOCB_ReadCtx = &ssl->rfd; /* prevent invalid pointer access if not */ + ssl->IOCB_WriteCtx = &ssl->wfd; /* correctly set */ + +#ifdef HAVE_NETX + ssl->IOCB_ReadCtx = &ssl->nxCtx; /* default NetX IO ctx, same for read */ + ssl->IOCB_WriteCtx = &ssl->nxCtx; /* and write */ +#elif defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) + ssl->mnCtx = mynewt_ctx_new(); + if(!ssl->mnCtx) { + return MEMORY_E; + } + ssl->IOCB_ReadCtx = ssl->mnCtx; /* default Mynewt IO ctx, same for read */ + ssl->IOCB_WriteCtx = ssl->mnCtx; /* and write */ +#elif defined (WOLFSSL_GNRC) + ssl->IOCB_ReadCtx = ssl->gnrcCtx; + ssl->IOCB_WriteCtx = ssl->gnrcCtx; +#endif + /* initialize states */ + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = doProcessInit; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + ssl->encrypt.state = CIPHER_STATE_BEGIN; + ssl->decrypt.state = CIPHER_STATE_BEGIN; +#ifndef NO_DH + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ssl->options.dhDoKeyTest = 1; + #endif +#endif + +#ifdef WOLFSSL_DTLS + #ifdef WOLFSSL_SCTP + ssl->options.dtlsSctp = ctx->dtlsSctp; + #endif + #if defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU) + ssl->dtlsMtuSz = ctx->dtlsMtuSz; + ssl->dtls_expected_rx = ssl->dtlsMtuSz; + #else + ssl->dtls_expected_rx = MAX_MTU; + #endif + ssl->dtls_timeout_init = DTLS_TIMEOUT_INIT; + ssl->dtls_timeout_max = DTLS_TIMEOUT_MAX; + ssl->dtls_timeout = ssl->dtls_timeout_init; + ssl->buffers.dtlsCtx.rfd = -1; + ssl->buffers.dtlsCtx.wfd = -1; +#endif + +#ifndef WOLFSSL_AEAD_ONLY + #ifndef NO_OLD_TLS + ssl->hmac = SSL_hmac; /* default to SSLv3 */ + #elif !defined(WOLFSSL_NO_TLS12) + ssl->hmac = TLS_hmac; + #endif +#endif + + + ssl->cipher.ssl = ssl; + +#ifdef HAVE_EXTENDED_MASTER + ssl->options.haveEMS = ctx->haveEMS; +#endif + ssl->options.useClientOrder = ctx->useClientOrder; + ssl->options.mutualAuth = ctx->mutualAuth; + +#ifdef WOLFSSL_TLS13 + #ifdef HAVE_SESSION_TICKET + ssl->options.noTicketTls13 = ctx->noTicketTls13; + #endif + ssl->options.noPskDheKe = ctx->noPskDheKe; + #if defined(WOLFSSL_POST_HANDSHAKE_AUTH) + ssl->options.postHandshakeAuth = ctx->postHandshakeAuth; + #endif + + if (ctx->numGroups > 0) { + XMEMCPY(ssl->group, ctx->group, sizeof(*ctx->group) * ctx->numGroups); + ssl->numGroups = ctx->numGroups; + } +#endif + +#ifdef HAVE_TLS_EXTENSIONS +#ifdef HAVE_MAX_FRAGMENT + ssl->max_fragment = MAX_RECORD_SIZE; +#endif +#ifdef HAVE_ALPN + ssl->alpn_client_list = NULL; + #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + ssl->alpnSelect = ctx->alpnSelect; + ssl->alpnSelectArg = ctx->alpnSelectArg; + #endif +#endif +#ifdef HAVE_SUPPORTED_CURVES + ssl->options.userCurves = ctx->userCurves; +#endif +#endif /* HAVE_TLS_EXTENSIONS */ + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + ssl->options.disallowEncThenMac = ctx->disallowEncThenMac; +#endif + + /* default alert state (none) */ + ssl->alert_history.last_rx.code = -1; + ssl->alert_history.last_rx.level = -1; + ssl->alert_history.last_tx.code = -1; + ssl->alert_history.last_tx.level = -1; + +#ifdef OPENSSL_EXTRA + /* copy over application session context ID */ + ssl->sessionCtxSz = ctx->sessionCtxSz; + XMEMCPY(ssl->sessionCtx, ctx->sessionCtx, ctx->sessionCtxSz); + ssl->cbioFlag = ctx->cbioFlag; + +#endif + + InitCiphers(ssl); + InitCipherSpecs(&ssl->specs); + + /* all done with init, now can return errors, call other stuff */ + + if (!writeDup) { + /* arrays */ + ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays == NULL) { + WOLFSSL_MSG("Arrays Memory error"); + return MEMORY_E; + } + XMEMSET(ssl->arrays, 0, sizeof(Arrays)); +#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER) + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, + DYNAMIC_TYPE_SECRET); + if (ssl->arrays->preMasterSecret == NULL) { + return MEMORY_E; + } + XMEMSET(ssl->arrays->preMasterSecret, 0, ENCRYPT_LEN); +#endif + +#ifdef OPENSSL_EXTRA + if ((ssl->param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC( + sizeof(WOLFSSL_X509_VERIFY_PARAM), + ssl->heap, DYNAMIC_TYPE_OPENSSL)) == NULL) { + WOLFSSL_MSG("ssl->param memory error"); + return MEMORY_E; + } + XMEMSET(ssl->param, 0, sizeof(WOLFSSL_X509_VERIFY_PARAM)); +#endif + +#ifdef SINGLE_THREADED + if (ctx->suites == NULL) +#endif + { + /* suites */ + ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, + DYNAMIC_TYPE_SUITES); + if (ssl->suites == NULL) { + WOLFSSL_MSG("Suites Memory error"); + return MEMORY_E; + } + #ifdef OPENSSL_ALL + ssl->suites->stack = NULL; + #endif +#ifdef SINGLE_THREADED + ssl->options.ownSuites = 1; +#endif + } +#ifdef SINGLE_THREADED + else { + ssl->options.ownSuites = 0; + } +#endif + } + + /* Initialize SSL with the appropriate fields from it's ctx */ + /* requires valid arrays and suites unless writeDup ing */ + if ((ret = SetSSL_CTX(ssl, ctx, writeDup)) != WOLFSSL_SUCCESS) + return ret; + + ssl->options.dtls = ssl->version.major == DTLS_MAJOR; + +#ifdef SINGLE_THREADED + ssl->rng = ctx->rng; /* CTX may have one, if so use it */ +#endif + + if (ssl->rng == NULL) { + /* RNG */ + ssl->rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ssl->heap,DYNAMIC_TYPE_RNG); + if (ssl->rng == NULL) { + WOLFSSL_MSG("RNG Memory error"); + return MEMORY_E; + } + XMEMSET(ssl->rng, 0, sizeof(WC_RNG)); + ssl->options.weOwnRng = 1; + + /* FIPS RNG API does not accept a heap hint */ +#ifndef HAVE_FIPS + if ( (ret = wc_InitRng_ex(ssl->rng, ssl->heap, ssl->devId)) != 0) { + WOLFSSL_MSG("RNG Init error"); + return ret; + } +#else + if ( (ret = wc_InitRng(ssl->rng)) != 0) { + WOLFSSL_MSG("RNG Init error"); + return ret; + } +#endif + } + +#ifdef HAVE_WRITE_DUP + if (writeDup) { + /* all done */ + return 0; + } +#endif + + /* hsHashes */ + ret = InitHandshakeHashes(ssl); + if (ret != 0) + return ret; + +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) + if (ssl->options.dtls && ssl->options.side == WOLFSSL_SERVER_END) { + ret = wolfSSL_DTLS_SetCookieSecret(ssl, NULL, 0); + if (ret != 0) { + WOLFSSL_MSG("DTLS Cookie Secret error"); + return ret; + } + } +#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ + +#ifdef HAVE_SECRET_CALLBACK + ssl->sessionSecretCb = NULL; + ssl->sessionSecretCtx = NULL; +#ifdef WOLFSSL_TLS13 + ssl->tls13SecretCb = NULL; + ssl->tls13SecretCtx = NULL; +#endif +#endif + +#ifdef HAVE_SESSION_TICKET + ssl->session.ticket = ssl->session.staticTicket; +#endif + +#ifdef WOLFSSL_MULTICAST + if (ctx->haveMcast) { + int i; + + ssl->options.haveMcast = 1; + ssl->options.mcastID = ctx->mcastID; + + /* Force the state to look like handshake has completed. */ + /* Keying material is supplied externally. */ + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.connectState = SECOND_REPLY_DONE; + ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) + ssl->keys.peerSeq[i].peerId = INVALID_PEER_ID; + } +#endif + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->options.side == WOLFSSL_CLIENT_END) { + int useSecureReneg = ssl->ctx->useSecureReneg; + /* use secure renegotiation by default (not recommend) */ + #ifdef WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT + useSecureReneg = 1; + #endif + if (useSecureReneg) { + ret = wolfSSL_UseSecureRenegotiation(ssl); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + } +#endif /* HAVE_SECURE_RENEGOTIATION */ + + return 0; +} + + +/* free use of temporary arrays */ +void FreeArrays(WOLFSSL* ssl, int keep) +{ + if (ssl->arrays) { + if (keep) { + /* keeps session id for user retrieval */ + XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN); + ssl->session.sessionIDSz = ssl->arrays->sessionIDSz; + } + if (ssl->arrays->preMasterSecret) { + XFREE(ssl->arrays->preMasterSecret, ssl->heap, DYNAMIC_TYPE_SECRET); + ssl->arrays->preMasterSecret = NULL; + } + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + ForceZero(ssl->arrays, sizeof(Arrays)); /* clear arrays struct */ + } + XFREE(ssl->arrays, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays = NULL; +} + +void FreeKey(WOLFSSL* ssl, int type, void** pKey) +{ + if (ssl && pKey && *pKey) { + switch (type) { + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + wc_FreeRsaKey((RsaKey*)*pKey); + break; + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + wc_ecc_free((ecc_key*)*pKey); + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + wc_ed25519_free((ed25519_key*)*pKey); + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + wc_curve25519_free((curve25519_key*)*pKey); + break; + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_ED448 + case DYNAMIC_TYPE_ED448: + wc_ed448_free((ed448_key*)*pKey); + break; + #endif /* HAVE_ED448 */ + #ifdef HAVE_CURVE448 + case DYNAMIC_TYPE_CURVE448: + wc_curve448_free((curve448_key*)*pKey); + break; + #endif /* HAVE_CURVE448 */ + #ifndef NO_DH + case DYNAMIC_TYPE_DH: + wc_FreeDhKey((DhKey*)*pKey); + break; + #endif /* !NO_DH */ + default: + break; + } + XFREE(*pKey, ssl->heap, type); + + /* Reset pointer */ + *pKey = NULL; + } +} + +int AllocKey(WOLFSSL* ssl, int type, void** pKey) +{ + int ret = BAD_FUNC_ARG; + int sz = 0; + + if (ssl == NULL || pKey == NULL) { + return BAD_FUNC_ARG; + } + + /* Sanity check key destination */ + if (*pKey != NULL) { + WOLFSSL_MSG("Key already present!"); + return BAD_STATE_E; + } + + /* Determine size */ + switch (type) { + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + sz = sizeof(RsaKey); + break; + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + sz = sizeof(ecc_key); + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + sz = sizeof(ed25519_key); + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + sz = sizeof(curve25519_key); + break; + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_ED448 + case DYNAMIC_TYPE_ED448: + sz = sizeof(ed448_key); + break; + #endif /* HAVE_ED448 */ + #ifdef HAVE_CURVE448 + case DYNAMIC_TYPE_CURVE448: + sz = sizeof(curve448_key); + break; + #endif /* HAVE_CURVE448 */ + #ifndef NO_DH + case DYNAMIC_TYPE_DH: + sz = sizeof(DhKey); + break; + #endif /* !NO_DH */ + default: + return BAD_FUNC_ARG; + } + + if (sz == 0) { + return NOT_COMPILED_IN; + } + + /* Allocate memory for key */ + *pKey = XMALLOC(sz, ssl->heap, type); + if (*pKey == NULL) { + return MEMORY_E; + } + + /* Initialize key */ + switch (type) { + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + ret = wc_InitRsaKey_ex((RsaKey*)*pKey, ssl->heap, ssl->devId); + break; + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + ret = wc_ecc_init_ex((ecc_key*)*pKey, ssl->heap, ssl->devId); + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + wc_ed25519_init((ed25519_key*)*pKey); + ret = 0; + break; + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + wc_curve25519_init((curve25519_key*)*pKey); + ret = 0; + break; + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_ED448 + case DYNAMIC_TYPE_ED448: + wc_ed448_init((ed448_key*)*pKey); + ret = 0; + break; + #endif /* HAVE_CURVE448 */ + #ifdef HAVE_CURVE448 + case DYNAMIC_TYPE_CURVE448: + wc_curve448_init((curve448_key*)*pKey); + ret = 0; + break; + #endif /* HAVE_CURVE448 */ + #ifndef NO_DH + case DYNAMIC_TYPE_DH: + ret = wc_InitDhKey_ex((DhKey*)*pKey, ssl->heap, ssl->devId); + break; + #endif /* !NO_DH */ + default: + return BAD_FUNC_ARG; + } + + /* On error free handshake key */ + if (ret != 0) { + FreeKey(ssl, type, pKey); + } + + return ret; +} + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_CURVE25519) || defined(HHAVE_ED448) || defined(HAVE_CURVE448) +static int ReuseKey(WOLFSSL* ssl, int type, void* pKey) +{ + int ret = 0; + + (void)ssl; + + switch (type) { + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + wc_FreeRsaKey((RsaKey*)pKey); + ret = wc_InitRsaKey_ex((RsaKey*)pKey, ssl->heap, ssl->devId); + break; + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + wc_ecc_free((ecc_key*)pKey); + ret = wc_ecc_init_ex((ecc_key*)pKey, ssl->heap, ssl->devId); + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + wc_ed25519_free((ed25519_key*)pKey); + ret = wc_ed25519_init((ed25519_key*)pKey); + break; + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_CURVE25519 + case DYNAMIC_TYPE_CURVE25519: + wc_curve25519_free((curve25519_key*)pKey); + ret = wc_curve25519_init((curve25519_key*)pKey); + break; + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_ED448 + case DYNAMIC_TYPE_ED448: + wc_ed448_free((ed448_key*)pKey); + ret = wc_ed448_init((ed448_key*)pKey); + break; + #endif /* HAVE_CURVE448 */ + #ifdef HAVE_CURVE448 + case DYNAMIC_TYPE_CURVE448: + wc_curve448_free((curve448_key*)pKey); + ret = wc_curve448_init((curve448_key*)pKey); + break; + #endif /* HAVE_CURVE448 */ + #ifndef NO_DH + case DYNAMIC_TYPE_DH: + wc_FreeDhKey((DhKey*)pKey); + ret = wc_InitDhKey_ex((DhKey*)pKey, ssl->heap, ssl->devId); + break; + #endif /* !NO_DH */ + default: + return BAD_FUNC_ARG; + } + + return ret; +} +#endif + +void FreeKeyExchange(WOLFSSL* ssl) +{ + /* Cleanup signature buffer */ + if (ssl->buffers.sig.buffer) { + XFREE(ssl->buffers.sig.buffer, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + ssl->buffers.sig.buffer = NULL; + ssl->buffers.sig.length = 0; + } + + /* Cleanup digest buffer */ + if (ssl->buffers.digest.buffer) { + XFREE(ssl->buffers.digest.buffer, ssl->heap, DYNAMIC_TYPE_DIGEST); + ssl->buffers.digest.buffer = NULL; + ssl->buffers.digest.length = 0; + } + + /* Free handshake key */ + FreeKey(ssl, ssl->hsType, &ssl->hsKey); + +#ifndef NO_DH + /* Free temp DH key */ + FreeKey(ssl, DYNAMIC_TYPE_DH, (void**)&ssl->buffers.serverDH_Key); +#endif + + /* Cleanup async */ +#ifdef WOLFSSL_ASYNC_CRYPT + if (ssl->async.freeArgs) { + ssl->async.freeArgs(ssl, ssl->async.args); + ssl->async.freeArgs = NULL; + } +#endif +} + + +/* Free up all memory used by Suites structure from WOLFSSL */ +void FreeSuites(WOLFSSL* ssl) +{ +#ifdef SINGLE_THREADED + if (ssl->options.ownSuites) +#endif + { + #ifdef OPENSSL_ALL + wolfSSL_sk_SSL_CIPHER_free(ssl->suites->stack); + #endif + XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); + } + ssl->suites = NULL; +} + + +/* In case holding SSL object in array and don't want to free actual ssl */ +void SSL_ResourceFree(WOLFSSL* ssl) +{ + /* Note: any resources used during the handshake should be released in the + * function FreeHandshakeResources(). Be careful with the special cases + * like the RNG which may optionally be kept for the whole session. (For + * example with the RNG, it isn't used beyond the handshake except when + * using stream ciphers where it is retained. */ + + FreeCiphers(ssl); + FreeArrays(ssl, 0); + FreeKeyExchange(ssl); + if (ssl->options.weOwnRng) { + wc_FreeRng(ssl->rng); + XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); + } + FreeSuites(ssl); + FreeHandshakeHashes(ssl); + XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); + + /* clear keys struct after session */ + ForceZero(&ssl->keys, sizeof(Keys)); + +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + ForceZero(&ssl->clientSecret, sizeof(ssl->clientSecret)); + ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret)); + } +#endif + +#ifndef NO_DH + if (ssl->buffers.serverDH_Priv.buffer) { + ForceZero(ssl->buffers.serverDH_Priv.buffer, + ssl->buffers.serverDH_Priv.length); + } + XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + /* parameters (p,g) may be owned by ctx */ + if (ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } +#endif /* !NO_DH */ +#ifndef NO_CERTS + ssl->keepCert = 0; /* make sure certificate is free'd */ + wolfSSL_UnloadCertsKeys(ssl); +#endif +#ifndef NO_RSA + FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; +#endif +#ifdef WOLFSSL_RENESAS_TSIP_TLS + XFREE(ssl->peerTsipEncRsaKeyIndex, ssl->heap, DYNAMIC_TYPE_RSA); +#endif + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, FORCED_FREE); + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); +#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER) + XFREE(ssl->buffers.tls13CookieSecret.buffer, ssl->heap, + DYNAMIC_TYPE_COOKIE_PWD); +#endif +#ifdef WOLFSSL_DTLS + DtlsMsgPoolReset(ssl); + if (ssl->dtls_rx_msg_list != NULL) { + DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); + ssl->dtls_rx_msg_list = NULL; + ssl->dtls_rx_msg_list_sz = 0; + } + XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.peer.sa = NULL; +#ifndef NO_WOLFSSL_SERVER + XFREE(ssl->buffers.dtlsCookieSecret.buffer, ssl->heap, + DYNAMIC_TYPE_COOKIE_PWD); +#endif +#endif /* WOLFSSL_DTLS */ +#ifdef OPENSSL_EXTRA + if (ssl->biord != ssl->biowr) /* only free write if different */ + wolfSSL_BIO_free(ssl->biowr); + wolfSSL_BIO_free(ssl->biord); /* always free read bio */ + ssl->biowr = NULL; + ssl->biord = NULL; +#endif +#ifdef HAVE_LIBZ + FreeStreams(ssl); +#endif +#ifdef HAVE_ECC + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; +#endif +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) ||defined(HAVE_CURVE448) + { + int dtype = 0; + #ifdef HAVE_ECC + dtype = DYNAMIC_TYPE_ECC; + #endif + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent + #ifdef HAVE_ECC + || ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE25519 + #endif /* HAVE_ECC */ + ) + { + dtype = DYNAMIC_TYPE_CURVE25519; + } + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_CURVE448 + if (ssl->peerX448KeyPresent + #ifdef HAVE_ECC + || ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE448 + #endif /* HAVE_ECC */ + ) + { + dtype = DYNAMIC_TYPE_CURVE448; + } + #endif /* HAVE_CURVE448 */ + FreeKey(ssl, dtype, (void**)&ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ +#ifdef HAVE_CURVE25519 + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; +#endif +#ifdef HAVE_ED25519 + FreeKey(ssl, DYNAMIC_TYPE_ED25519, (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + #ifdef HAVE_PK_CALLBACKS + if (ssl->buffers.peerEd25519Key.buffer != NULL) { + XFREE(ssl->buffers.peerEd25519Key.buffer, ssl->heap, + DYNAMIC_TYPE_ED25519); + ssl->buffers.peerEd25519Key.buffer = NULL; + } + #endif +#endif +#ifdef HAVE_CURVE448 + FreeKey(ssl, DYNAMIC_TYPE_CURVE448, (void**)&ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; +#endif +#ifdef HAVE_ED448 + FreeKey(ssl, DYNAMIC_TYPE_ED448, (void**)&ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; + #ifdef HAVE_PK_CALLBACKS + if (ssl->buffers.peerEd448Key.buffer != NULL) { + XFREE(ssl->buffers.peerEd448Key.buffer, ssl->heap, + DYNAMIC_TYPE_ED448); + ssl->buffers.peerEd448Key.buffer = NULL; + } + #endif +#endif +#ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); + #endif /* HAVE_ECC */ + #ifndef NO_RSA + XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA); + #endif /* NO_RSA */ +#endif /* HAVE_PK_CALLBACKS */ +#ifdef HAVE_TLS_EXTENSIONS + TLSX_FreeAll(ssl->extensions, ssl->heap); + +#ifdef HAVE_ALPN + if (ssl->alpn_client_list != NULL) { + XFREE(ssl->alpn_client_list, ssl->heap, DYNAMIC_TYPE_ALPN); + ssl->alpn_client_list = NULL; + } +#endif +#endif /* HAVE_TLS_EXTENSIONS */ +#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) + if (ssl->mnCtx) { + mynewt_ctx_clear(ssl->mnCtx); + ssl->mnCtx = NULL; + } +#endif +#ifdef HAVE_NETX + if (ssl->nxCtx.nxPacket) + nx_packet_release(ssl->nxCtx.nxPacket); +#endif +#ifdef KEEP_PEER_CERT + FreeX509(&ssl->peerCert); +#endif + +#ifdef HAVE_SESSION_TICKET + if (ssl->session.isDynamic) { + XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + ssl->session.ticket = ssl->session.staticTicket; + ssl->session.isDynamic = 0; + ssl->session.ticketLen = 0; + } +#endif +#ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(ssl->extSession); +#endif +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite) { + FreeWriteDup(ssl); + } +#endif +#ifdef OPENSSL_EXTRA + if (ssl->param) { + XFREE(ssl->param, ssl->heap, DYNAMIC_TYPE_OPENSSL); + } +#endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + while (ssl->certReqCtx != NULL) { + CertReqCtx* curr = ssl->certReqCtx; + ssl->certReqCtx = curr->next; + XFREE(curr, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + +#ifdef WOLFSSL_STATIC_MEMORY + /* check if using fixed io buffers and free them */ + if (ssl->heap != NULL) { + #ifdef WOLFSSL_HEAP_TEST + /* avoid dereferencing a test value */ + if (ssl->heap != (void*)WOLFSSL_HEAP_TEST) { + #endif + WOLFSSL_HEAP_HINT* ssl_hint = (WOLFSSL_HEAP_HINT*)ssl->heap; + WOLFSSL_HEAP* ctx_heap; + void* heap = ssl->ctx ? ssl->ctx->heap : ssl->heap; + + ctx_heap = ssl_hint->memory; + if (wc_LockMutex(&(ctx_heap->memory_mutex)) != 0) { + WOLFSSL_MSG("Bad memory_mutex lock"); + } + ctx_heap->curIO--; + if (FreeFixedIO(ctx_heap, &(ssl_hint->outBuf)) != 1) { + WOLFSSL_MSG("Error freeing fixed output buffer"); + } + if (FreeFixedIO(ctx_heap, &(ssl_hint->inBuf)) != 1) { + WOLFSSL_MSG("Error freeing fixed output buffer"); + } + if (ssl_hint->haFlag) { /* check if handshake count has been decreased*/ + ctx_heap->curHa--; + } + wc_UnLockMutex(&(ctx_heap->memory_mutex)); + + /* check if tracking stats */ + if (ctx_heap->flag & WOLFMEM_TRACK_STATS) { + XFREE(ssl_hint->stats, heap, DYNAMIC_TYPE_SSL); + } + XFREE(ssl->heap, heap, DYNAMIC_TYPE_SSL); + #ifdef WOLFSSL_HEAP_TEST + } + #endif + } +#endif /* WOLFSSL_STATIC_MEMORY */ +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + wolfSSL_sk_CIPHER_free(ssl->supportedCiphers); + wolfSSL_sk_X509_free(ssl->peerCertChain); +#endif +} + +/* Free any handshake resources no longer needed */ +void FreeHandshakeResources(WOLFSSL* ssl) +{ + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) { + WOLFSSL_MSG("Secure Renegotiation needs to retain handshake resources"); + return; + } +#endif + + /* input buffer */ + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (!ssl->options.tls1_3) +#endif + { + #ifndef OPENSSL_ALL + /* free suites unless using compatibility layer */ + FreeSuites(ssl); + #endif + /* hsHashes */ + FreeHandshakeHashes(ssl); + } + + /* RNG */ + if (ssl->options.tls1_1 == 0 +#ifndef WOLFSSL_AEAD_ONLY + || ssl->specs.cipher_type == stream +#endif +#if defined(WOLFSSL_TLS13) + #if !defined(WOLFSSL_POST_HANDSHAKE_AUTH) + || ssl->options.tls1_3 + #elif !defined(HAVE_SESSION_TICKET) + || (ssl->options.tls1_3 && ssl->options.side == WOLFSSL_SERVER_END) + #endif +#endif + ) { + if (ssl->options.weOwnRng) { + wc_FreeRng(ssl->rng); + XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); + ssl->rng = NULL; + ssl->options.weOwnRng = 0; + } + } + +#ifdef WOLFSSL_DTLS + /* DTLS_POOL */ + if (ssl->options.dtls) { + DtlsMsgPoolReset(ssl); + DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); + ssl->dtls_rx_msg_list = NULL; + ssl->dtls_rx_msg_list_sz = 0; + } +#endif + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \ + defined(HAVE_SESSION_TICKET) + if (!ssl->options.tls1_3) +#endif + /* arrays */ + if (ssl->options.saveArrays == 0) + FreeArrays(ssl, 1); + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (!ssl->options.tls1_3 || ssl->options.side == WOLFSSL_CLIENT_END) +#endif + { +#ifndef NO_RSA + /* peerRsaKey */ + FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; +#endif +#ifdef HAVE_ECC + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; +#endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 + FreeKey(ssl, DYNAMIC_TYPE_ED25519, (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + FreeKey(ssl, DYNAMIC_TYPE_ED448, (void**)&ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; +#endif /* HAVE_ED448 */ + } + +#ifdef HAVE_ECC + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; +#endif +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + { + int dtype; + #ifdef HAVE_ECC + dtype = DYNAMIC_TYPE_ECC; + #endif + #ifdef HAVE_CURVE25519 + #ifdef HAVE_ECC + if (ssl->peerX25519KeyPresent || + ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE25519) + #endif /* HAVE_ECC */ + { + dtype = DYNAMIC_TYPE_CURVE25519; + } + #endif /* HAVE_CURVE25519 */ + #ifdef HAVE_CURVE448 + #ifdef HAVE_ECC + if (ssl->peerX448KeyPresent || + ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE448) + #endif /* HAVE_ECC */ + { + dtype = DYNAMIC_TYPE_CURVE448; + } + #endif /* HAVE_CURVE448 */ + FreeKey(ssl, dtype, (void**)&ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ +#ifdef HAVE_CURVE25519 + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; +#endif +#ifdef HAVE_CURVE448 + FreeKey(ssl, DYNAMIC_TYPE_CURVE448, (void**)&ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; +#endif + +#ifndef NO_DH + if (ssl->buffers.serverDH_Priv.buffer) { + ForceZero(ssl->buffers.serverDH_Priv.buffer, + ssl->buffers.serverDH_Priv.length); + } + XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + ssl->buffers.serverDH_Priv.buffer = NULL; + XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ssl->buffers.serverDH_Pub.buffer = NULL; + /* parameters (p,g) may be owned by ctx */ + if (ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ssl->buffers.serverDH_G.buffer = NULL; + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ssl->buffers.serverDH_P.buffer = NULL; + } +#endif /* !NO_DH */ + +#ifndef NO_CERTS + wolfSSL_UnloadCertsKeys(ssl); +#endif +#ifdef HAVE_PK_CALLBACKS +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (!ssl->options.tls1_3 || ssl->options.side == WOLFSSL_CLIENT_END) +#endif + { + #ifdef HAVE_ECC + XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->buffers.peerEccDsaKey.buffer = NULL; + #endif /* HAVE_ECC */ + #ifndef NO_RSA + XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA); + ssl->buffers.peerRsaKey.buffer = NULL; + #endif /* NO_RSA */ + #ifdef HAVE_ED25519 + XFREE(ssl->buffers.peerEd25519Key.buffer, ssl->heap, + DYNAMIC_TYPE_ED25519); + ssl->buffers.peerEd25519Key.buffer = NULL; + #endif + #ifdef HAVE_ED448 + XFREE(ssl->buffers.peerEd448Key.buffer, ssl->heap, DYNAMIC_TYPE_ED448); + ssl->buffers.peerEd448Key.buffer = NULL; + #endif + } +#endif /* HAVE_PK_CALLBACKS */ + +#ifdef HAVE_QSH + QSH_FreeAll(ssl); +#endif + +#ifdef HAVE_SESSION_TICKET + if (ssl->session.isDynamic) { + XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + ssl->session.ticket = ssl->session.staticTicket; + ssl->session.isDynamic = 0; + ssl->session.ticketLen = 0; + } +#endif + +#if defined(HAVE_TLS_EXTENSIONS) && !defined(HAVE_SNI) && \ + !defined(HAVE_ALPN) && !defined(WOLFSSL_POST_HANDSHAKE_AUTH) + /* Some extensions need to be kept for post-handshake querying. */ + TLSX_FreeAll(ssl->extensions, ssl->heap); + ssl->extensions = NULL; +#endif + +#ifdef WOLFSSL_STATIC_MEMORY + /* when done with handshake decrement current handshake count */ + if (ssl->heap != NULL) { + #ifdef WOLFSSL_HEAP_TEST + /* avoid dereferencing a test value */ + if (ssl->heap != (void*)WOLFSSL_HEAP_TEST) { + #endif + WOLFSSL_HEAP_HINT* ssl_hint = (WOLFSSL_HEAP_HINT*)ssl->heap; + WOLFSSL_HEAP* ctx_heap; + + ctx_heap = ssl_hint->memory; + if (wc_LockMutex(&(ctx_heap->memory_mutex)) != 0) { + WOLFSSL_MSG("Bad memory_mutex lock"); + } + ctx_heap->curHa--; + ssl_hint->haFlag = 0; /* set to zero since handshake has been dec */ + wc_UnLockMutex(&(ctx_heap->memory_mutex)); + #ifdef WOLFSSL_HEAP_TEST + } + #endif + } +#endif /* WOLFSSL_STATIC_MEMORY */ +} + + +/* heap argument is the heap hint used when creating SSL */ +void FreeSSL(WOLFSSL* ssl, void* heap) +{ + if (ssl->ctx) { + FreeSSL_Ctx(ssl->ctx); /* will decrement and free underlying CTX if 0 */ + } + SSL_ResourceFree(ssl); + XFREE(ssl, heap, DYNAMIC_TYPE_SSL); + (void)heap; +} + +#if !defined(NO_OLD_TLS) || defined(WOLFSSL_DTLS) || \ + ((defined(HAVE_CHACHA) || defined(HAVE_AESCCM) || defined(HAVE_AESGCM)) \ + && defined(HAVE_AEAD)) + +#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) +static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2]) +{ + if (verify) { + seq[0] = ssl->keys.peer_sequence_number_hi; + seq[1] = ssl->keys.peer_sequence_number_lo++; + if (seq[1] > ssl->keys.peer_sequence_number_lo) { + /* handle rollover */ + ssl->keys.peer_sequence_number_hi++; + } + } + else { + seq[0] = ssl->keys.sequence_number_hi; + seq[1] = ssl->keys.sequence_number_lo++; + if (seq[1] > ssl->keys.sequence_number_lo) { + /* handle rollover */ + ssl->keys.sequence_number_hi++; + } + } +} +#endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 */ + + +#ifdef WOLFSSL_DTLS +static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2]) +{ + if (order == PREV_ORDER) { + /* Previous epoch case */ + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) | + (ssl->options.mcastID << 8) | + (ssl->keys.dtls_prev_sequence_number_hi & 0xFF); + #endif + } + else + seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) | + (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF); + seq[1] = ssl->keys.dtls_prev_sequence_number_lo; + } + else if (order == PEER_ORDER) { + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + seq[0] = ((word32)ssl->keys.curEpoch << 16) | + (ssl->keys.curPeerId << 8) | + (ssl->keys.curSeq_hi & 0xFF); + #endif + } + else + seq[0] = ((word32)ssl->keys.curEpoch << 16) | + (ssl->keys.curSeq_hi & 0xFFFF); + seq[1] = ssl->keys.curSeq_lo; /* explicit from peer */ + } + else { + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + seq[0] = ((word32)ssl->keys.dtls_epoch << 16) | + (ssl->options.mcastID << 8) | + (ssl->keys.dtls_sequence_number_hi & 0xFF); + #endif + } + else + seq[0] = ((word32)ssl->keys.dtls_epoch << 16) | + (ssl->keys.dtls_sequence_number_hi & 0xFFFF); + seq[1] = ssl->keys.dtls_sequence_number_lo; + } +} + +static WC_INLINE void DtlsSEQIncrement(WOLFSSL* ssl, int order) +{ + word32 seq; + + if (order == PREV_ORDER) { + seq = ssl->keys.dtls_prev_sequence_number_lo++; + if (seq > ssl->keys.dtls_prev_sequence_number_lo) { + /* handle rollover */ + ssl->keys.dtls_prev_sequence_number_hi++; + } + } + else if (order == PEER_ORDER) { + seq = ssl->keys.peer_sequence_number_lo++; + if (seq > ssl->keys.peer_sequence_number_lo) { + /* handle rollover */ + ssl->keys.peer_sequence_number_hi++; + } + } + else { + seq = ssl->keys.dtls_sequence_number_lo++; + if (seq > ssl->keys.dtls_sequence_number_lo) { + /* handle rollover */ + ssl->keys.dtls_sequence_number_hi++; + } + } +} +#endif /* WOLFSSL_DTLS */ + +#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) +static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) +{ + word32 seq[2] = {0, 0}; + + if (!ssl->options.dtls) { + GetSEQIncrement(ssl, verifyOrder, seq); + } + else { +#ifdef WOLFSSL_DTLS + DtlsGetSEQ(ssl, verifyOrder, seq); +#endif + } + + c32toa(seq[0], out); + c32toa(seq[1], out + OPAQUE32_LEN); +} +#endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 */ +#endif /* !NO_OLD_TLS || WOLFSSL_DTLS || + * ((HAVE_CHACHA || HAVE_AESCCM || HAVE_AESGCM) && HAVE_AEAD) */ + +#ifdef WOLFSSL_DTLS + +/* functions for managing DTLS datagram reordering */ + +/* Need to allocate space for the handshake message header. The hashing + * routines assume the message pointer is still within the buffer that + * has the headers, and will include those headers in the hash. The store + * routines need to take that into account as well. New will allocate + * extra space for the headers. */ +DtlsMsg* DtlsMsgNew(word32 sz, void* heap) +{ + DtlsMsg* msg; + + (void)heap; + msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); + + if (msg != NULL) { + XMEMSET(msg, 0, sizeof(DtlsMsg)); + msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ, + heap, DYNAMIC_TYPE_DTLS_BUFFER); + if (msg->buf != NULL) { + msg->sz = sz; + msg->type = no_shake; + msg->msg = msg->buf + DTLS_HANDSHAKE_HEADER_SZ; + } + else { + XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); + msg = NULL; + } + } + + return msg; +} + +void DtlsMsgDelete(DtlsMsg* item, void* heap) +{ + (void)heap; + + if (item != NULL) { + DtlsFrag* cur = item->fragList; + while (cur != NULL) { + DtlsFrag* next = cur->next; + XFREE(cur, heap, DYNAMIC_TYPE_DTLS_FRAG); + cur = next; + } + if (item->buf != NULL) + XFREE(item->buf, heap, DYNAMIC_TYPE_DTLS_BUFFER); + XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG); + } +} + + +void DtlsMsgListDelete(DtlsMsg* head, void* heap) +{ + DtlsMsg* next; + while (head) { + next = head->next; + DtlsMsgDelete(head, heap); + head = next; + } +} + + +/* Create a DTLS Fragment from *begin - end, adjust new *begin and bytesLeft */ +static DtlsFrag* CreateFragment(word32* begin, word32 end, const byte* data, + byte* buf, word32* bytesLeft, void* heap) +{ + DtlsFrag* newFrag; + word32 added = end - *begin + 1; + + (void)heap; + newFrag = (DtlsFrag*)XMALLOC(sizeof(DtlsFrag), heap, + DYNAMIC_TYPE_DTLS_FRAG); + if (newFrag != NULL) { + newFrag->next = NULL; + newFrag->begin = *begin; + newFrag->end = end; + + XMEMCPY(buf + *begin, data, added); + *bytesLeft -= added; + *begin = newFrag->end + 1; + } + + return newFrag; +} + + +int DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type, + word32 fragOffset, word32 fragSz, void* heap) +{ + if (msg != NULL && data != NULL && msg->fragSz <= msg->sz && + (fragOffset + fragSz) <= msg->sz) { + DtlsFrag* cur = msg->fragList; + DtlsFrag* prev = cur; + DtlsFrag* newFrag; + word32 bytesLeft = fragSz; /* could be overlapping fragment */ + word32 startOffset = fragOffset; + word32 added; + + msg->seq = seq; + msg->type = type; + + if (fragOffset == 0) { + XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ, + DTLS_HANDSHAKE_HEADER_SZ); + c32to24(msg->sz, msg->msg - DTLS_HANDSHAKE_FRAG_SZ); + } + + /* if no message data, just return */ + if (fragSz == 0) + return 0; + + /* if list is empty add full fragment to front */ + if (cur == NULL) { + newFrag = CreateFragment(&fragOffset, fragOffset + fragSz - 1, data, + msg->msg, &bytesLeft, heap); + if (newFrag == NULL) + return MEMORY_E; + + msg->fragSz = fragSz; + msg->fragList = newFrag; + + return 0; + } + + /* add to front if before current front, up to next->begin */ + if (fragOffset < cur->begin) { + word32 end = fragOffset + fragSz - 1; + + if (end >= cur->begin) + end = cur->begin - 1; + + added = end - fragOffset + 1; + newFrag = CreateFragment(&fragOffset, end, data, msg->msg, + &bytesLeft, heap); + if (newFrag == NULL) + return MEMORY_E; + + msg->fragSz += added; + + newFrag->next = cur; + msg->fragList = newFrag; + } + + /* while we have bytes left, try to find a gap to fill */ + while (bytesLeft > 0) { + /* get previous packet in list */ + while (cur && (fragOffset >= cur->begin)) { + prev = cur; + cur = cur->next; + } + + /* don't add duplicate data */ + if (prev->end >= fragOffset) { + if ( (fragOffset + bytesLeft - 1) <= prev->end) + return 0; + fragOffset = prev->end + 1; + bytesLeft = startOffset + fragSz - fragOffset; + } + + if (cur == NULL) + /* we're at the end */ + added = bytesLeft; + else + /* we're in between two frames */ + added = min(bytesLeft, cur->begin - fragOffset); + + /* data already there */ + if (added == 0) + continue; + + newFrag = CreateFragment(&fragOffset, fragOffset + added - 1, + data + fragOffset - startOffset, + msg->msg, &bytesLeft, heap); + if (newFrag == NULL) + return MEMORY_E; + + msg->fragSz += added; + + newFrag->next = prev->next; + prev->next = newFrag; + } + } + + return 0; +} + + +DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq) +{ + while (head != NULL && head->seq != seq) { + head = head->next; + } + return head; +} + + +void DtlsMsgStore(WOLFSSL* ssl, word32 seq, const byte* data, + word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap) +{ + /* See if seq exists in the list. If it isn't in the list, make + * a new item of size dataSz, copy fragSz bytes from data to msg->msg + * starting at offset fragOffset, and add fragSz to msg->fragSz. If + * the seq is in the list and it isn't full, copy fragSz bytes from + * data to msg->msg starting at offset fragOffset, and add fragSz to + * msg->fragSz. Insertions take into account data already in the list + * in case there are overlaps in the handshake message due to retransmit + * messages. The new item should be inserted into the list in its + * proper position. + * + * 1. Find seq in list, or where seq should go in list. If seq not in + * list, create new item and insert into list. Either case, keep + * pointer to item. + * 2. Copy the data from the message to the stored message where it + * belongs without overlaps. + */ + + DtlsMsg* head = ssl->dtls_rx_msg_list; + + if (head != NULL) { + DtlsMsg* cur = DtlsMsgFind(head, seq); + if (cur == NULL) { + cur = DtlsMsgNew(dataSz, heap); + if (cur != NULL) { + if (DtlsMsgSet(cur, seq, data, type, + fragOffset, fragSz, heap) < 0) { + DtlsMsgDelete(cur, heap); + } + else { + ssl->dtls_rx_msg_list_sz++; + head = DtlsMsgInsert(head, cur); + } + } + } + else { + /* If this fails, the data is just dropped. */ + DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz, heap); + } + } + else { + head = DtlsMsgNew(dataSz, heap); + if (DtlsMsgSet(head, seq, data, type, fragOffset, fragSz, heap) < 0) { + DtlsMsgDelete(head, heap); + head = NULL; + } + else { + ssl->dtls_rx_msg_list_sz++; + } + } + + ssl->dtls_rx_msg_list = head; +} + + +/* DtlsMsgInsert() is an in-order insert. */ +DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item) +{ + if (head == NULL || item->seq < head->seq) { + item->next = head; + head = item; + } + else if (head->next == NULL) { + head->next = item; + } + else { + DtlsMsg* cur = head->next; + DtlsMsg* prev = head; + while (cur) { + if (item->seq < cur->seq) { + item->next = cur; + prev->next = item; + break; + } + prev = cur; + cur = cur->next; + } + if (cur == NULL) { + prev->next = item; + } + } + + return head; +} + + +/* DtlsMsgPoolSave() adds the message to the end of the stored transmit list. */ +int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) +{ + DtlsMsg* item; + int ret = 0; + + WOLFSSL_ENTER("DtlsMsgPoolSave()"); + + if (ssl->dtls_tx_msg_list_sz > DTLS_POOL_SZ) { + WOLFSSL_ERROR(DTLS_POOL_SZ_E); + return DTLS_POOL_SZ_E; + } + + item = DtlsMsgNew(dataSz, ssl->heap); + + if (item != NULL) { + DtlsMsg* cur = ssl->dtls_tx_msg_list; + + XMEMCPY(item->buf, data, dataSz); + item->sz = dataSz; + item->seq = ssl->keys.dtls_epoch; + + if (cur == NULL) + ssl->dtls_tx_msg_list = item; + else { + while (cur->next) + cur = cur->next; + cur->next = item; + } + ssl->dtls_tx_msg_list_sz++; + } + else + ret = MEMORY_E; + + WOLFSSL_LEAVE("DtlsMsgPoolSave()", ret); + return ret; +} + + +/* DtlsMsgPoolTimeout() updates the timeout time. */ +int DtlsMsgPoolTimeout(WOLFSSL* ssl) +{ + int result = -1; + if (ssl->dtls_timeout < ssl->dtls_timeout_max) { + ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; + result = 0; + } + WOLFSSL_LEAVE("DtlsMsgPoolTimeout()", result); + return result; +} + + +/* DtlsMsgPoolReset() deletes the stored transmit list and resets the timeout + * value. */ +void DtlsMsgPoolReset(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("DtlsMsgPoolReset()"); + if (ssl->dtls_tx_msg_list) { + DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); + ssl->dtls_tx_msg_list = NULL; + ssl->dtls_tx_msg = NULL; + ssl->dtls_tx_msg_list_sz = 0; + ssl->dtls_timeout = ssl->dtls_timeout_init; + } +} + + +int VerifyForDtlsMsgPoolSend(WOLFSSL* ssl, byte type, word32 fragOffset) +{ + /** + * only the first message from previous flight should be valid + * to be used for triggering retransmission of whole DtlsMsgPool. + * change cipher suite type is not verified here + */ + return ((fragOffset == 0) && + (((ssl->options.side == WOLFSSL_SERVER_END) && + ((type == client_hello) || + ((ssl->options.verifyPeer) && (type == certificate)) || + ((!ssl->options.verifyPeer) && (type == client_key_exchange)))) || + ((ssl->options.side == WOLFSSL_CLIENT_END) && + (type == server_hello)))); +} + + +/* DtlsMsgPoolSend() will send the stored transmit list. The stored list is + * updated with new sequence numbers, and will be re-encrypted if needed. */ +int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) +{ + int ret = 0; + DtlsMsg* pool; + + WOLFSSL_ENTER("DtlsMsgPoolSend()"); + + pool = ssl->dtls_tx_msg == NULL ? ssl->dtls_tx_msg_list : ssl->dtls_tx_msg; + + if (pool != NULL) { + if ((ssl->options.side == WOLFSSL_SERVER_END && + !(ssl->options.acceptState == SERVER_HELLO_DONE || + ssl->options.acceptState == ACCEPT_FINISHED_DONE || + ssl->options.acceptState == ACCEPT_THIRD_REPLY_DONE)) || + (ssl->options.side == WOLFSSL_CLIENT_END && + !(ssl->options.connectState == CLIENT_HELLO_SENT || + ssl->options.connectState == HELLO_AGAIN_REPLY || + ssl->options.connectState == FINISHED_DONE || + ssl->options.connectState == SECOND_REPLY_DONE))) { + + WOLFSSL_ERROR(DTLS_RETX_OVER_TX); + ssl->error = DTLS_RETX_OVER_TX; + return WOLFSSL_FATAL_ERROR; + } + + while (pool != NULL) { + if (pool->seq == 0) { + DtlsRecordLayerHeader* dtls; + int epochOrder; + + dtls = (DtlsRecordLayerHeader*)pool->buf; + /* If the stored record's epoch is 0, and the currently set + * epoch is 0, use the "current order" sequence number. + * If the stored record's epoch is 0 and the currently set + * epoch is not 0, the stored record is considered a "previous + * order" sequence number. */ + epochOrder = (ssl->keys.dtls_epoch == 0) ? + CUR_ORDER : PREV_ORDER; + + WriteSEQ(ssl, epochOrder, dtls->sequence_number); + DtlsSEQIncrement(ssl, epochOrder); + if ((ret = CheckAvailableSize(ssl, pool->sz)) != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + + XMEMCPY(ssl->buffers.outputBuffer.buffer, + pool->buf, pool->sz); + ssl->buffers.outputBuffer.idx = 0; + ssl->buffers.outputBuffer.length = pool->sz; + } + else if (pool->seq == ssl->keys.dtls_epoch) { + byte* input; + byte* output; + int inputSz, sendSz; + + input = pool->buf; + inputSz = pool->sz; + sendSz = inputSz + MAX_MSG_EXTRA; + + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 0, 0, 0); + if (sendSz < 0) { + WOLFSSL_ERROR(BUILD_MSG_ERROR); + return BUILD_MSG_ERROR; + } + + ssl->buffers.outputBuffer.length += sendSz; + } + + ret = SendBuffered(ssl); + if (ret < 0) { + WOLFSSL_ERROR(ret); + return ret; + } + + /** + * on server side, retransmission is being triggered only by sending + * first message of given flight, in order to trigger client + * to retransmit its whole flight. Sending the whole previous flight + * could lead to retransmission of previous client flight for each + * server message from previous flight. Therefore one message should + * be enough to do the trick. + */ + if (sendOnlyFirstPacket && + ssl->options.side == WOLFSSL_SERVER_END) { + + pool = NULL; + } + else + pool = pool->next; + ssl->dtls_tx_msg = pool; + } + } + + WOLFSSL_LEAVE("DtlsMsgPoolSend()", ret); + return ret; +} + +#endif /* WOLFSSL_DTLS */ + +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + +ProtocolVersion MakeSSLv3(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = SSLv3_MINOR; + + return pv; +} + +#endif /* WOLFSSL_ALLOW_SSLV3 && !NO_OLD_TLS */ + + +#ifdef WOLFSSL_DTLS + +ProtocolVersion MakeDTLSv1(void) +{ + ProtocolVersion pv; + pv.major = DTLS_MAJOR; + pv.minor = DTLS_MINOR; + + return pv; +} + +#ifndef WOLFSSL_NO_TLS12 + +ProtocolVersion MakeDTLSv1_2(void) +{ + ProtocolVersion pv; + pv.major = DTLS_MAJOR; + pv.minor = DTLSv1_2_MINOR; + + return pv; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#endif /* WOLFSSL_DTLS */ + + +#ifndef NO_ASN_TIME +#if defined(USER_TICKS) +#if 0 + word32 LowResTimer(void) + { + /* + write your own clock tick function if don't want time(0) + needs second accuracy but doesn't have to correlated to EPOCH + */ + } +#endif + +#elif defined(TIME_OVERRIDES) + + /* use same asn time overrides unless user wants tick override above */ + + #ifndef HAVE_TIME_T_TYPE + typedef long time_t; + #endif + extern time_t XTIME(time_t * timer); + + word32 LowResTimer(void) + { + return (word32) XTIME(0); + } + +#elif defined(USE_WINDOWS_API) + + word32 LowResTimer(void) + { + static int init = 0; + static LARGE_INTEGER freq; + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (word32)(count.QuadPart / freq.QuadPart); + } + +#elif defined(HAVE_RTP_SYS) + + #include "rtptime.h" + + word32 LowResTimer(void) + { + return (word32)rtp_get_system_sec(); + } + +#elif defined(WOLFSSL_DEOS) + + word32 LowResTimer(void) + { + const uint32_t systemTickTimeInHz = 1000000 / systemTickInMicroseconds(); + uint32_t *systemTickPtr = systemTickPointer(); + + return (word32) *systemTickPtr/systemTickTimeInHz; + } + +#elif defined(MICRIUM) + + word32 LowResTimer(void) + { + OS_TICK ticks = 0; + OS_ERR err; + + ticks = OSTimeGet(&err); + + return (word32) (ticks / OSCfg_TickRate_Hz); + } + + +#elif defined(MICROCHIP_TCPIP_V5) + + word32 LowResTimer(void) + { + return (word32) (TickGet() / TICKS_PER_SECOND); + } + + +#elif defined(MICROCHIP_TCPIP) + + #if defined(MICROCHIP_MPLAB_HARMONY) + + #include + + word32 LowResTimer(void) + { + return (word32) (SYS_TMR_TickCountGet() / + SYS_TMR_TickCounterFrequencyGet()); + } + + #else + + word32 LowResTimer(void) + { + return (word32) (SYS_TICK_Get() / SYS_TICK_TicksPerSecondGet()); + } + + #endif + +#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + + word32 LowResTimer(void) + { + TIME_STRUCT mqxTime; + + _time_get_elapsed(&mqxTime); + + return (word32) mqxTime.SECONDS; + } +#elif defined(FREESCALE_FREE_RTOS) || defined(FREESCALE_KSDK_FREERTOS) + + #include "include/task.h" + + unsigned int LowResTimer(void) + { + return (unsigned int)(((float)xTaskGetTickCount())/configTICK_RATE_HZ); + } + +#elif defined(FREERTOS) + + #include "task.h" + + unsigned int LowResTimer(void) + { + return (unsigned int)(((float)xTaskGetTickCount())/configTICK_RATE_HZ); + } + +#elif defined(FREESCALE_KSDK_BM) + + #include "lwip/sys.h" /* lwIP */ + word32 LowResTimer(void) + { + return sys_now()/1000; + } + +#elif defined(WOLFSSL_TIRTOS) + + word32 LowResTimer(void) + { + return (word32) Seconds_get(); + } +#elif defined(WOLFSSL_XILINX) + #include "xrtcpsu.h" + + word32 LowResTimer(void) + { + XRtcPsu_Config* con; + XRtcPsu rtc; + + con = XRtcPsu_LookupConfig(XPAR_XRTCPSU_0_DEVICE_ID); + if (con != NULL) { + if (XRtcPsu_CfgInitialize(&rtc, con, con->BaseAddr) + == XST_SUCCESS) { + return (word32)XRtcPsu_GetCurrentTime(&rtc); + } + else { + WOLFSSL_MSG("Unable to initialize RTC"); + } + } + + return 0; + } + +#elif defined(WOLFSSL_UTASKER) + + word32 LowResTimer(void) + { + return (word32)(uTaskerSystemTick / TICK_RESOLUTION); + } + +#elif defined(WOLFSSL_NUCLEUS_1_2) + + #define NU_TICKS_PER_SECOND 100 + + word32 LowResTimer(void) + { + /* returns number of 10ms ticks, so 100 ticks/sec */ + return NU_Retrieve_Clock() / NU_TICKS_PER_SECOND; + } +#elif defined(WOLFSSL_APACHE_MYNEWT) + + #include "os/os_time.h" + word32 LowResTimer(void) + { + word32 now; + struct os_timeval tv; + os_gettimeofday(&tv, NULL); + now = (word32)tv.tv_sec; + return now; + } + +#elif defined(WOLFSSL_ZEPHYR) + + word32 LowResTimer(void) + { + return k_uptime_get() / 1000; + } + +#else + /* Posix style time */ + #if !defined(USER_TIME) && !defined(USE_WOLF_TM) + #include + #endif + + word32 LowResTimer(void) + { + return (word32)XTIME(0); + } +#endif +#endif /* !NO_ASN_TIME */ +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) +/* Store the message for use with CertificateVerify using EdDSA. + * + * ssl SSL/TLS object. + * data Message to store. + * sz Size of message to store. + * returns MEMORY_E if not able to reallocate, otherwise 0. + */ +static int EdDSA_Update(WOLFSSL* ssl, const byte* data, int sz) +{ + int ret = 0; + byte* msgs; + + if (ssl->options.cacheMessages) { + msgs = (byte*)XREALLOC(ssl->hsHashes->messages, + ssl->hsHashes->length + sz, + ssl->heap, DYNAMIC_TYPE_HASHES); + if (msgs == NULL) + ret = MEMORY_E; + if (ret == 0) { + ssl->hsHashes->messages = msgs; + XMEMCPY(msgs + ssl->hsHashes->length, data, sz); + ssl->hsHashes->prevLen = ssl->hsHashes->length; + ssl->hsHashes->length += sz; + } + } + + return ret; +} +#endif /* (HAVE_ED25519 || HAVE_ED448) && !WOLFSSL_NO_CLIENT_AUTH */ + +#ifndef NO_CERTS +int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) +{ + int ret = 0; + + (void)output; + (void)sz; + + if (ssl->hsHashes == NULL) + return BAD_FUNC_ARG; + +#ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx); +#endif +#ifndef NO_OLD_TLS + #ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz); + #endif + #ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz); + #endif +#endif /* NO_OLD_TLS */ + + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, output, sz); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA384 + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, output, sz); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA512 + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, output, sz); + if (ret != 0) + return ret; + #endif + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + ret = EdDSA_Update(ssl, output, sz); + if (ret != 0) + return ret; + #endif + } + + return ret; +} +#endif /* NO_CERTS */ + + +/* add output to md5 and sha handshake hashes, exclude record header */ +int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) +{ + int ret = 0; + const byte* adj; + + if (ssl->hsHashes == NULL) + return BAD_FUNC_ARG; + + adj = output + RECORD_HEADER_SZ + ivSz; + sz -= RECORD_HEADER_SZ; + +#ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx); +#endif +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + adj += DTLS_RECORD_EXTRA; + sz -= DTLS_RECORD_EXTRA; + } +#endif +#ifndef NO_OLD_TLS + #ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); + #endif + #ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); + #endif +#endif + + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA384 + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA512 + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz); + if (ret != 0) + return ret; + #endif + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + ret = EdDSA_Update(ssl, adj, sz); + if (ret != 0) + return ret; + #endif + } + + return ret; +} + + +/* add input to md5 and sha handshake hashes, include handshake header */ +int HashInput(WOLFSSL* ssl, const byte* input, int sz) +{ + int ret = 0; + const byte* adj; + + adj = input - HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + + (void)adj; + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + adj -= DTLS_HANDSHAKE_EXTRA; + sz += DTLS_HANDSHAKE_EXTRA; + } +#endif + + if (ssl->hsHashes == NULL) { + return BAD_FUNC_ARG; + } + +#ifndef NO_OLD_TLS + #ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); + #endif + #ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); + #endif +#endif + + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA384 + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA512 + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz); + if (ret != 0) + return ret; + #endif + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + ret = EdDSA_Update(ssl, adj, sz); + if (ret != 0) + return ret; + #endif + } + + return ret; +} + + +/* add record layer header for message */ +static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl) +{ + RecordLayerHeader* rl; + + /* record layer header */ + rl = (RecordLayerHeader*)output; + if (rl == NULL) { + return; + } + rl->type = type; + rl->pvMajor = ssl->version.major; /* type and version same in each */ +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { +#ifdef WOLFSSL_TLS13_DRAFT_18 + rl->pvMinor = TLSv1_MINOR; +#else + rl->pvMinor = TLSv1_2_MINOR; +#endif + } + else +#endif + rl->pvMinor = ssl->version.minor; + +#ifdef WOLFSSL_ALTERNATIVE_DOWNGRADE + if (ssl->options.side == WOLFSSL_CLIENT_END + && ssl->options.connectState == CONNECT_BEGIN + && !ssl->options.resuming) { + rl->pvMinor = ssl->options.downgrade ? ssl->options.minDowngrade + : ssl->version.minor; + } +#endif + + if (!ssl->options.dtls) { + c16toa((word16)length, rl->length); + } + else { +#ifdef WOLFSSL_DTLS + DtlsRecordLayerHeader* dtls; + + /* dtls record layer header extensions */ + dtls = (DtlsRecordLayerHeader*)output; + WriteSEQ(ssl, 0, dtls->sequence_number); + c16toa((word16)length, dtls->length); +#endif + } +} + + +#if !defined(WOLFSSL_NO_TLS12) || (defined(HAVE_SESSION_TICKET) && \ + !defined(NO_WOLFSSL_SERVER)) +/* add handshake header for message */ +static void AddHandShakeHeader(byte* output, word32 length, + word32 fragOffset, word32 fragLength, + byte type, WOLFSSL* ssl) +{ + HandShakeHeader* hs; + (void)fragOffset; + (void)fragLength; + (void)ssl; + + /* handshake header */ + hs = (HandShakeHeader*)output; + if (hs == NULL) + return; + + hs->type = type; + c32to24(length, hs->length); /* type and length same for each */ +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + DtlsHandShakeHeader* dtls; + + /* dtls handshake header extensions */ + dtls = (DtlsHandShakeHeader*)output; + c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq); + c32to24(fragOffset, dtls->fragment_offset); + c32to24(fragLength, dtls->fragment_length); + } +#endif +} + +/* add both headers for handshake message */ +static void AddHeaders(byte* output, word32 length, byte type, WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + lengthAdj += DTLS_HANDSHAKE_EXTRA; + outputAdj += DTLS_RECORD_EXTRA; + } +#endif + + AddRecordHeader(output, length + lengthAdj, handshake, ssl); + AddHandShakeHeader(output + outputAdj, length, 0, length, type, ssl); +} +#endif /* !WOLFSSL_NO_TLS12 || (HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER) */ + + +#ifndef WOLFSSL_NO_TLS12 +#if !defined(NO_CERTS) && (!defined(NO_WOLFSSL_SERVER) || \ + !defined(WOLFSSL_NO_CLIENT_AUTH)) +static void AddFragHeaders(byte* output, word32 fragSz, word32 fragOffset, + word32 length, byte type, WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + (void)fragSz; + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + lengthAdj += DTLS_HANDSHAKE_EXTRA; + outputAdj += DTLS_RECORD_EXTRA; + } +#endif + + AddRecordHeader(output, fragSz + lengthAdj, handshake, ssl); + AddHandShakeHeader(output + outputAdj, length, fragOffset, fragSz, type, ssl); +} +#endif /* NO_CERTS */ +#endif /* !WOLFSSL_NO_TLS12 */ + + +/* return bytes received, -1 on error */ +static int wolfSSLReceive(WOLFSSL* ssl, byte* buf, word32 sz) +{ + int recvd; + + if (ssl->CBIORecv == NULL) { + WOLFSSL_MSG("Your IO Recv callback is null, please set"); + return -1; + } + +retry: + recvd = ssl->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx); + if (recvd < 0) { + switch (recvd) { + case WOLFSSL_CBIO_ERR_GENERAL: /* general/unknown error */ + #if defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD) + if (ssl->biord) { + /* If retry and read flags are set, return WANT_READ */ + if ((ssl->biord->flags & WOLFSSL_BIO_FLAG_READ) && + (ssl->biord->flags & WOLFSSL_BIO_FLAG_RETRY)) { + return WANT_READ; + } + } + #endif + return -1; + + case WOLFSSL_CBIO_ERR_WANT_READ: /* want read, would block */ + return WANT_READ; + + case WOLFSSL_CBIO_ERR_CONN_RST: /* connection reset */ + #ifdef USE_WINDOWS_API + if (ssl->options.dtls) { + goto retry; + } + #endif + ssl->options.connReset = 1; + return -1; + + case WOLFSSL_CBIO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef WOLFSSL_CALLBACKS + if (ssl->toInfoOn) { + struct itimerval timeout; + getitimer(ITIMER_REAL, &timeout); + if (timeout.it_value.tv_sec == 0 && + timeout.it_value.tv_usec == 0) { + XSTRNCPY(ssl->timeoutInfo.timeoutName, + "recv() timeout", MAX_TIMEOUT_NAME_SZ); + ssl->timeoutInfo.timeoutName[ + MAX_TIMEOUT_NAME_SZ] = '\0'; + + WOLFSSL_MSG("Got our timeout"); + return WANT_READ; + } + } + #endif + goto retry; + + case WOLFSSL_CBIO_ERR_CONN_CLOSE: /* peer closed connection */ + ssl->options.isClosed = 1; + return -1; + + case WOLFSSL_CBIO_ERR_TIMEOUT: + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl) && + !ssl->options.handShakeDone && + DtlsMsgPoolTimeout(ssl) == 0 && + DtlsMsgPoolSend(ssl, 0) == 0) { + + /* retry read for DTLS during handshake only */ + goto retry; + } + #endif + return -1; + + default: + WOLFSSL_MSG("Unexpected recv return code"); + return recvd; + } + } + + return recvd; +} + + +/* Switch dynamic output buffer back to static, buffer is assumed clear */ +void ShrinkOutputBuffer(WOLFSSL* ssl) +{ + WOLFSSL_MSG("Shrinking output buffer\n"); + XFREE(ssl->buffers.outputBuffer.buffer - ssl->buffers.outputBuffer.offset, + ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; + ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.outputBuffer.dynamicFlag = 0; + ssl->buffers.outputBuffer.offset = 0; +} + + +/* Switch dynamic input buffer back to static, keep any remaining input */ +/* forced free means cleaning up */ +void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree) +{ + int usedLength = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (!forcedFree && usedLength > STATIC_BUFFER_LEN) + return; + + WOLFSSL_MSG("Shrinking input buffer\n"); + + if (!forcedFree && usedLength > 0) + XMEMCPY(ssl->buffers.inputBuffer.staticBuffer, + ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + usedLength); + + XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, + ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; + ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.inputBuffer.dynamicFlag = 0; + ssl->buffers.inputBuffer.offset = 0; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; +} + +int SendBuffered(WOLFSSL* ssl) +{ + if (ssl->CBIOSend == NULL) { + WOLFSSL_MSG("Your IO Send callback is null, please set"); + return SOCKET_ERROR_E; + } + +#ifdef WOLFSSL_DEBUG_TLS + if (ssl->buffers.outputBuffer.idx == 0) { + WOLFSSL_MSG("Data to send"); + WOLFSSL_BUFFER(ssl->buffers.outputBuffer.buffer, + ssl->buffers.outputBuffer.length); + } +#endif + + while (ssl->buffers.outputBuffer.length > 0) { + int sent = ssl->CBIOSend(ssl, + (char*)ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx, + (int)ssl->buffers.outputBuffer.length, + ssl->IOCB_WriteCtx); + if (sent < 0) { + switch (sent) { + + case WOLFSSL_CBIO_ERR_WANT_WRITE: /* would block */ + return WANT_WRITE; + + case WOLFSSL_CBIO_ERR_CONN_RST: /* connection reset */ + ssl->options.connReset = 1; + break; + + case WOLFSSL_CBIO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef WOLFSSL_CALLBACKS + if (ssl->toInfoOn) { + struct itimerval timeout; + getitimer(ITIMER_REAL, &timeout); + if (timeout.it_value.tv_sec == 0 && + timeout.it_value.tv_usec == 0) { + XSTRNCPY(ssl->timeoutInfo.timeoutName, + "send() timeout", MAX_TIMEOUT_NAME_SZ); + ssl->timeoutInfo.timeoutName[ + MAX_TIMEOUT_NAME_SZ] = '\0'; + + WOLFSSL_MSG("Got our timeout"); + return WANT_WRITE; + } + } + #endif + continue; + + case WOLFSSL_CBIO_ERR_CONN_CLOSE: /* epipe / conn closed */ + ssl->options.connReset = 1; /* treat same as reset */ + break; + + default: + return SOCKET_ERROR_E; + } + + return SOCKET_ERROR_E; + } + + if (sent > (int)ssl->buffers.outputBuffer.length) { + WOLFSSL_MSG("SendBuffered() out of bounds read"); + return SEND_OOB_READ_E; + } + + ssl->buffers.outputBuffer.idx += sent; + ssl->buffers.outputBuffer.length -= sent; + } + + ssl->buffers.outputBuffer.idx = 0; + + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); + + return 0; +} + + +/* Grow the output buffer */ +static WC_INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size) +{ + byte* tmp; +#if WOLFSSL_GENERAL_ALIGNMENT > 0 + byte hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ : + RECORD_HEADER_SZ; + byte align = WOLFSSL_GENERAL_ALIGNMENT; +#else + const byte align = WOLFSSL_GENERAL_ALIGNMENT; +#endif + +#if WOLFSSL_GENERAL_ALIGNMENT > 0 + /* the encrypted data will be offset from the front of the buffer by + the header, if the user wants encrypted alignment they need + to define their alignment requirement */ + + if (align) { + while (align < hdrSz) + align *= 2; + } +#endif + + tmp = (byte*)XMALLOC(size + ssl->buffers.outputBuffer.length + align, + ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + WOLFSSL_MSG("growing output buffer\n"); + + if (tmp == NULL) + return MEMORY_E; + +#if WOLFSSL_GENERAL_ALIGNMENT > 0 + if (align) + tmp += align - hdrSz; +#endif + +#ifdef WOLFSSL_STATIC_MEMORY + /* can be from IO memory pool which does not need copy if same buffer */ + if (ssl->buffers.outputBuffer.length && + tmp == ssl->buffers.outputBuffer.buffer) { + ssl->buffers.outputBuffer.bufferSize = + size + ssl->buffers.outputBuffer.length; + return 0; + } +#endif + + if (ssl->buffers.outputBuffer.length) + XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer, + ssl->buffers.outputBuffer.length); + + if (ssl->buffers.outputBuffer.dynamicFlag) + XFREE(ssl->buffers.outputBuffer.buffer - + ssl->buffers.outputBuffer.offset, ssl->heap, + DYNAMIC_TYPE_OUT_BUFFER); + ssl->buffers.outputBuffer.dynamicFlag = 1; + +#if WOLFSSL_GENERAL_ALIGNMENT > 0 + if (align) + ssl->buffers.outputBuffer.offset = align - hdrSz; + else +#endif + ssl->buffers.outputBuffer.offset = 0; + + ssl->buffers.outputBuffer.buffer = tmp; + ssl->buffers.outputBuffer.bufferSize = size + + ssl->buffers.outputBuffer.length; + return 0; +} + + +/* Grow the input buffer, should only be to read cert or big app data */ +int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength) +{ + byte* tmp; +#if defined(WOLFSSL_DTLS) || WOLFSSL_GENERAL_ALIGNMENT > 0 + byte align = ssl->options.dtls ? WOLFSSL_GENERAL_ALIGNMENT : 0; + byte hdrSz = DTLS_RECORD_HEADER_SZ; +#else + const byte align = WOLFSSL_GENERAL_ALIGNMENT; +#endif + +#if defined(WOLFSSL_DTLS) || WOLFSSL_GENERAL_ALIGNMENT > 0 + /* the encrypted data will be offset from the front of the buffer by + the dtls record header, if the user wants encrypted alignment they need + to define their alignment requirement. in tls we read record header + to get size of record and put actual data back at front, so don't need */ + + if (align) { + while (align < hdrSz) + align *= 2; + } +#endif + + if (usedLength < 0 || size < 0) { + WOLFSSL_MSG("GrowInputBuffer() called with negative number"); + return BAD_FUNC_ARG; + } + + tmp = (byte*)XMALLOC(size + usedLength + align, + ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + WOLFSSL_MSG("growing input buffer\n"); + + if (tmp == NULL) + return MEMORY_E; + +#if defined(WOLFSSL_DTLS) || WOLFSSL_GENERAL_ALIGNMENT > 0 + if (align) + tmp += align - hdrSz; +#endif + +#ifdef WOLFSSL_STATIC_MEMORY + /* can be from IO memory pool which does not need copy if same buffer */ + if (usedLength && tmp == ssl->buffers.inputBuffer.buffer) { + ssl->buffers.inputBuffer.bufferSize = size + usedLength; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + return 0; + } +#endif + + if (usedLength) + XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, usedLength); + + if (ssl->buffers.inputBuffer.dynamicFlag) + XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, + ssl->heap,DYNAMIC_TYPE_IN_BUFFER); + + ssl->buffers.inputBuffer.dynamicFlag = 1; +#if defined(WOLFSSL_DTLS) || WOLFSSL_GENERAL_ALIGNMENT > 0 + if (align) + ssl->buffers.inputBuffer.offset = align - hdrSz; + else +#endif + ssl->buffers.inputBuffer.offset = 0; + + ssl->buffers.inputBuffer.buffer = tmp; + ssl->buffers.inputBuffer.bufferSize = size + usedLength; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + + return 0; +} + + +/* check available size into output buffer, make room if needed */ +int CheckAvailableSize(WOLFSSL *ssl, int size) +{ + if (size < 0) { + WOLFSSL_MSG("CheckAvailableSize() called with negative number"); + return BAD_FUNC_ARG; + } + + if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length + < (word32)size) { + if (GrowOutputBuffer(ssl, size) < 0) + return MEMORY_E; + } + + return 0; +} + + +/* do all verify and sanity checks on record header */ +static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + RecordLayerHeader* rh, word16 *size) +{ + if (!ssl->options.dtls) { +#ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, input + *inOutIdx, RECORD_HEADER_SZ, FUZZ_HEAD, + ssl->fuzzerCtx); +#endif + XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ); + *inOutIdx += RECORD_HEADER_SZ; + ato16(rh->length, size); + } + else { +#ifdef WOLFSSL_DTLS +#ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, input + *inOutIdx, DTLS_RECORD_HEADER_SZ, + FUZZ_HEAD, ssl->fuzzerCtx); +#endif + /* type and version in same sport */ + XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ); + *inOutIdx += ENUM_LEN + VERSION_SZ; + ato16(input + *inOutIdx, &ssl->keys.curEpoch); + *inOutIdx += OPAQUE16_LEN; + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + ssl->keys.curPeerId = input[*inOutIdx]; + ssl->keys.curSeq_hi = input[*inOutIdx+1]; + #endif + } + else + ato16(input + *inOutIdx, &ssl->keys.curSeq_hi); + *inOutIdx += OPAQUE16_LEN; + ato32(input + *inOutIdx, &ssl->keys.curSeq_lo); + *inOutIdx += OPAQUE32_LEN; /* advance past rest of seq */ + ato16(input + *inOutIdx, size); + *inOutIdx += LENGTH_SZ; +#endif + } + +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl) && !DtlsCheckWindow(ssl)) { + WOLFSSL_LEAVE("GetRecordHeader()", SEQUENCE_ERROR); + return SEQUENCE_ERROR; + } +#endif + + /* catch version mismatch */ +#ifndef WOLFSSL_TLS13 + if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor) +#else + if (rh->pvMajor != ssl->version.major || + (rh->pvMinor != ssl->version.minor && +#ifdef WOLFSSL_TLS13_DRAFT_18 + (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR) +#else + (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_2_MINOR) +#endif + )) +#endif + { + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.acceptState < ACCEPT_FIRST_REPLY_DONE) + + WOLFSSL_MSG("Client attempting to connect with different version"); + else if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.downgrade && + ssl->options.connectState < FIRST_REPLY_DONE) + WOLFSSL_MSG("Server attempting to accept with different version"); + else if (ssl->options.dtls && rh->type == handshake) + /* Check the DTLS handshake message RH version later. */ + WOLFSSL_MSG("DTLS handshake, skip RH version number check"); + else { + WOLFSSL_MSG("SSL version error"); + /* send alert per RFC5246 Appendix E. Backward Compatibility */ + if (ssl->options.side == WOLFSSL_CLIENT_END) { +#ifdef WOLFSSL_MYSQL_COMPATIBLE + SendAlert(ssl, alert_fatal, wc_protocol_version); +#else + SendAlert(ssl, alert_fatal, protocol_version); +#endif + } + return VERSION_ERROR; /* only use requested version */ + } + } + + /* record layer length check */ +#ifdef HAVE_MAX_FRAGMENT + if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) { + SendAlert(ssl, alert_fatal, record_overflow); + return LENGTH_ERROR; + } +#else + if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) + return LENGTH_ERROR; +#endif + + /* verify record type here as well */ + switch (rh->type) { + case handshake: + case change_cipher_spec: + case application_data: + case alert: + break; + case no_type: + default: + WOLFSSL_MSG("Unknown Record Type"); + return UNKNOWN_RECORD_TYPE; + } + + /* haven't decrypted this record yet */ + ssl->keys.decryptedCur = 0; + + return 0; +} + +#ifndef WOLFSSL_NO_TLS12 +static int GetHandShakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + byte *type, word32 *size, word32 totalSz) +{ + const byte *ptr = input + *inOutIdx; + (void)ssl; + + *inOutIdx += HANDSHAKE_HEADER_SZ; + if (*inOutIdx > totalSz) + return BUFFER_E; + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} +#endif + +#ifdef WOLFSSL_DTLS +static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, byte *type, word32 *size, + word32 *fragOffset, word32 *fragSz, + word32 totalSz) +{ + word32 idx = *inOutIdx; + + *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; + if (*inOutIdx > totalSz) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; + } + + *type = input[idx++]; + c24to32(input + idx, size); + idx += OPAQUE24_LEN; + + ato16(input + idx, &ssl->keys.dtls_peer_handshake_number); + idx += DTLS_HANDSHAKE_SEQ_SZ; + + c24to32(input + idx, fragOffset); + idx += DTLS_HANDSHAKE_FRAG_SZ; + c24to32(input + idx, fragSz); + + if (ssl->curRL.pvMajor != ssl->version.major || + ssl->curRL.pvMinor != ssl->version.minor) { + + if (*type != client_hello && *type != hello_verify_request) { + WOLFSSL_ERROR(VERSION_ERROR); + return VERSION_ERROR; + } + else { + WOLFSSL_MSG("DTLS Handshake ignoring hello or verify version"); + } + } + return 0; +} +#endif + + +#if !defined(NO_OLD_TLS) || \ + (defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLS_SHA1)) +/* fill with MD5 pad size since biggest required */ +static const byte PAD1[PAD_MD5] = + { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; +static const byte PAD2[PAD_MD5] = + { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; +#endif /* !NO_OLD_TLS || (NO_OLD_TLS && WOLFSSL_ALLOW_TLS_SHA1) */ + +#ifndef NO_OLD_TLS + +/* calculate MD5 hash for finished */ +#ifdef WOLFSSL_TI_HASH +#include +#endif + +static int BuildMD5(WOLFSSL* ssl, Hashes* hashes, const byte* sender) +{ + int ret; + byte md5_result[WC_MD5_DIGEST_SIZE]; +#ifdef WOLFSSL_SMALL_STACK + wc_Md5* md5 = (wc_Md5*)XMALLOC(sizeof(wc_Md5), ssl->heap, DYNAMIC_TYPE_HASHCTX); + if (md5 == NULL) + return MEMORY_E; +#else + wc_Md5 md5[1]; +#endif + + /* make md5 inner */ + ret = wc_Md5Copy(&ssl->hsHashes->hashMd5, md5); + if (ret == 0) + ret = wc_Md5Update(md5, sender, SIZEOF_SENDER); + if (ret == 0) + ret = wc_Md5Update(md5, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_Md5Update(md5, PAD1, PAD_MD5); + if (ret == 0) + ret = wc_Md5Final(md5, md5_result); + + /* make md5 outer */ + if (ret == 0) { + ret = wc_InitMd5_ex(md5, ssl->heap, ssl->devId); + if (ret == 0) { + ret = wc_Md5Update(md5, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_Md5Update(md5, PAD2, PAD_MD5); + if (ret == 0) + ret = wc_Md5Update(md5, md5_result, WC_MD5_DIGEST_SIZE); + if (ret == 0) + ret = wc_Md5Final(md5, hashes->md5); + wc_Md5Free(md5); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(md5, ssl->heap, DYNAMIC_TYPE_HASHCTX); +#endif + + return ret; +} + + +/* calculate SHA hash for finished */ +static int BuildSHA(WOLFSSL* ssl, Hashes* hashes, const byte* sender) +{ + int ret; + byte sha_result[WC_SHA_DIGEST_SIZE]; +#ifdef WOLFSSL_SMALL_STACK + wc_Sha* sha = (wc_Sha*)XMALLOC(sizeof(wc_Sha), ssl->heap, DYNAMIC_TYPE_HASHCTX); + if (sha == NULL) + return MEMORY_E; +#else + wc_Sha sha[1]; +#endif + /* make sha inner */ + ret = wc_ShaCopy(&ssl->hsHashes->hashSha, sha); /* Save current position */ + if (ret == 0) + ret = wc_ShaUpdate(sha, sender, SIZEOF_SENDER); + if (ret == 0) + ret = wc_ShaUpdate(sha, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_ShaUpdate(sha, PAD1, PAD_SHA); + if (ret == 0) + ret = wc_ShaFinal(sha, sha_result); + + /* make sha outer */ + if (ret == 0) { + ret = wc_InitSha_ex(sha, ssl->heap, ssl->devId); + if (ret == 0) { + ret = wc_ShaUpdate(sha, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_ShaUpdate(sha, PAD2, PAD_SHA); + if (ret == 0) + ret = wc_ShaUpdate(sha, sha_result, WC_SHA_DIGEST_SIZE); + if (ret == 0) + ret = wc_ShaFinal(sha, hashes->sha); + wc_ShaFree(sha); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(sha, ssl->heap, DYNAMIC_TYPE_HASHCTX); +#endif + + return ret; +} +#endif + +#ifndef WOLFSSL_NO_TLS12 + +/* Finished doesn't support SHA512, not SHA512 cipher suites yet */ +static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) +{ + int ret = 0; + + if (ssl == NULL) + return BAD_FUNC_ARG; + +#ifndef NO_TLS + if (ssl->options.tls) { + ret = BuildTlsFinished(ssl, hashes, sender); + } +#endif +#ifndef NO_OLD_TLS + if (!ssl->options.tls) { + ret = BuildMD5(ssl, hashes, sender); + if (ret == 0) { + ret = BuildSHA(ssl, hashes, sender); + } + } +#endif + + return ret; +} + +#endif /* WOLFSSL_NO_TLS12 */ + +#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT) + /* cipher requirements */ + enum { + REQUIRES_RSA, + REQUIRES_DHE, + REQUIRES_ECC, + REQUIRES_ECC_STATIC, + REQUIRES_PSK, + REQUIRES_NTRU, + REQUIRES_RSA_SIG, + REQUIRES_AEAD + }; + + + + /* Does this cipher suite (first, second) have the requirement + an ephemeral key exchange will still require the key for signing + the key exchange so ECHDE_RSA requires an rsa key thus rsa_kea */ + static int CipherRequires(byte first, byte second, int requirement) + { + + (void)requirement; + +#ifndef WOLFSSL_NO_TLS12 + +#ifdef HAVE_CHACHA + if (first == CHACHA_BYTE) { + + switch (second) { + case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + + case TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + } + + if (requirement == REQUIRES_AEAD) + return 1; + + } +#endif /* HAVE_CHACHA */ + + /* ECC extensions */ + if (first == ECC_BYTE) { + + switch (second) { +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + #ifndef NO_RSA + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + + #ifndef NO_DES3 + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + #endif /* !NO_DES3 */ + + #ifndef NO_RC4 + case TLS_ECDHE_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + #endif /* !NO_RC4 */ + #endif /* NO_RSA */ + + #ifndef NO_DES3 + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + #endif /* !NO_DES3 */ + #ifndef NO_RC4 + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + #endif /* !NO_RC4 */ + #ifndef NO_RSA + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + #endif /* !NO_RSA */ + + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_ECC) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_ECC) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + +#ifndef NO_RSA + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #ifdef HAVE_AESCCM + case TLS_RSA_WITH_AES_128_CCM_8 : + case TLS_RSA_WITH_AES_256_CCM_8 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + #endif /* HAVE_AESCCM */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ +#endif /* !NO_RSA */ + +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM : + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 : + case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 : + if (requirement == REQUIRES_ECC) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : + if (requirement == REQUIRES_ECC) + return 1; + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + +#ifndef NO_PSK + case TLS_PSK_WITH_AES_128_CCM: + case TLS_PSK_WITH_AES_256_CCM: + case TLS_PSK_WITH_AES_128_CCM_8: + case TLS_PSK_WITH_AES_256_CCM_8: + if (requirement == REQUIRES_PSK) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_DHE_PSK_WITH_AES_128_CCM: + case TLS_DHE_PSK_WITH_AES_256_CCM: + if (requirement == REQUIRES_PSK) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; +#endif /* !NO_PSK */ +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + case TLS_ECDHE_ECDSA_WITH_NULL_SHA : + if (requirement == REQUIRES_ECC) + return 1; + break; + + case TLS_ECDHE_PSK_WITH_NULL_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + break; +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + +#if defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) + case TLS_SHA256_SHA256: + break; + case TLS_SHA384_SHA384: + break; +#endif + + default: + WOLFSSL_MSG("Unsupported cipher suite, CipherRequires ECC"); + return 0; + } /* switch */ + } /* if */ + +#endif /* !WOLFSSL_NO_TLS12 */ + + /* Distinct TLS v1.3 cipher suites with cipher and digest only. */ + if (first == TLS13_BYTE) { + + switch (second) { +#ifdef WOLFSSL_TLS13 + case TLS_AES_128_GCM_SHA256: + case TLS_AES_256_GCM_SHA384: + case TLS_CHACHA20_POLY1305_SHA256: + case TLS_AES_128_CCM_SHA256: + case TLS_AES_128_CCM_8_SHA256: + break; +#endif + + default: + WOLFSSL_MSG("Unsupported cipher suite, CipherRequires " + "TLS v1.3"); + return 0; + } + } + +#ifndef WOLFSSL_NO_TLS12 + + if (first != ECC_BYTE && first != CHACHA_BYTE && + first != TLS13_BYTE) { /* normal suites */ + switch (second) { + +#ifndef NO_RSA + #ifndef NO_RC4 + case SSL_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case SSL_RSA_WITH_RC4_128_MD5 : + if (requirement == REQUIRES_RSA) + return 1; + break; + #endif /* NO_RC4 */ + + case SSL_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + #ifdef HAVE_NTRU + case TLS_NTRU_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + #endif /* HAVE_NTRU */ + + case TLS_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + #ifdef HAVE_NTRU + case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + #endif /* HAVE_NTRU */ + + case TLS_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + #ifdef HAVE_NTRU + case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + #endif /* HAVE_NTRU */ + + case TLS_RSA_WITH_AES_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_NULL_MD5 : + case TLS_RSA_WITH_NULL_SHA : + case TLS_RSA_WITH_NULL_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + #ifdef HAVE_NTRU + case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + #endif /* HAVE_NTRU */ + + #ifdef HAVE_IDEA + case SSL_RSA_WITH_IDEA_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + #endif /* HAVE_IDEA */ +#endif /* !NO_RSA */ + +#ifndef NO_PSK + case TLS_PSK_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_PSK_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_PSK) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_PSK_WITH_AES_128_CBC_SHA256 : + case TLS_PSK_WITH_AES_256_CBC_SHA384 : + case TLS_PSK_WITH_AES_128_CBC_SHA : + case TLS_PSK_WITH_AES_256_CBC_SHA : + case TLS_PSK_WITH_NULL_SHA384 : + case TLS_PSK_WITH_NULL_SHA256 : + case TLS_PSK_WITH_NULL_SHA : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 : + case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_DHE) + return 1; + if (requirement == REQUIRES_PSK) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 : + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 : + case TLS_DHE_PSK_WITH_NULL_SHA384 : + case TLS_DHE_PSK_WITH_NULL_SHA256 : + if (requirement == REQUIRES_DHE) + return 1; + if (requirement == REQUIRES_PSK) + return 1; + break; +#endif /* NO_PSK */ + +#ifndef NO_RSA + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + +#ifndef NO_HC128 + case TLS_RSA_WITH_HC_128_MD5 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_HC_128_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; +#endif /* NO_HC128 */ + +#ifndef NO_RABBIT + case TLS_RSA_WITH_RABBIT_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; +#endif /* !NO_RABBIT */ + + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; + +#ifdef HAVE_CAMELLIA + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA : + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA : + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA : + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA : + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; +#endif /* HAVE_CAMELLIA */ + + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; +#endif +#ifdef HAVE_ANON + case TLS_DH_anon_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_DHE) + return 1; + break; + case TLS_DH_anon_WITH_AES_256_GCM_SHA384: + if (requirement == REQUIRES_DHE) + return 1; + if (requirement == REQUIRES_AEAD) + return 1; + break; +#endif +#ifdef WOLFSSL_MULTICAST + case WDM_WITH_NULL_SHA256 : + break; +#endif + + default: + WOLFSSL_MSG("Unsupported cipher suite, CipherRequires"); + return 0; + } /* switch */ + } /* if ECC / Normal suites else */ + +#endif /* !WOLFSSL_NO_TLS12 */ + + return 0; + } + +#endif /* !NO_WOLFSSL_SERVER && !NO_WOLFSSL_CLIENT */ + + +#ifndef NO_CERTS + + +/* Match names with wildcards, each wildcard can represent a single name + component or fragment but not multiple names, i.e., + *.z.com matches y.z.com but not x.y.z.com + + return 1 on success */ +int MatchDomainName(const char* pattern, int len, const char* str) +{ + int ret = 0; + char p, s; + + if (pattern == NULL || str == NULL || len <= 0) + return 0; + + while (len > 0) { + + p = (char)XTOLOWER((unsigned char)*pattern++); + if (p == '\0') + break; + + if (p == '*') { + while (--len > 0 && + (p = (char)XTOLOWER((unsigned char)*pattern++)) == '*') { + } + + if (len == 0) + p = '\0'; + + while ( (s = (char)XTOLOWER((unsigned char) *str)) != '\0') { + if (s == p) + break; + if (s == '.') + return 0; + str++; + } + } + else { + if (p != (char)XTOLOWER((unsigned char) *str)) + return 0; + } + + + if (len > 0) { + str++; + len--; + } + } + + if (*str == '\0' && len == 0) { + ret = 1; /* success */ + } + + return ret; +} + + +/* try to find an altName match to domain, return 1 on success */ +int CheckAltNames(DecodedCert* dCert, char* domain) +{ + int match = 0; + DNS_entry* altName = NULL; + + WOLFSSL_MSG("Checking AltNames"); + + if (dCert) + altName = dCert->altNames; + + while (altName) { + WOLFSSL_MSG("\tindividual AltName check"); + + if (MatchDomainName(altName->name, altName->len, domain)){ + match = 1; + break; + } + + altName = altName->next; + } + + return match; +} + +#ifdef OPENSSL_EXTRA +/* Check that alternative names, if they exists, match the domain. + * Fail if there are wild patterns and they didn't match. + * Check the common name if no alternative names matched. + * + * dCert Decoded cert to get the alternative names from. + * domain Domain name to compare against. + * checkCN Whether to check the common name. + * returns whether there was a problem in matching. + */ +static int CheckForAltNames(DecodedCert* dCert, char* domain, int* checkCN) +{ + int match; + DNS_entry* altName = NULL; + + WOLFSSL_MSG("Checking AltNames"); + + if (dCert) + altName = dCert->altNames; + + *checkCN = altName == NULL; + match = 0; + while (altName) { + WOLFSSL_MSG("\tindividual AltName check"); + + if (MatchDomainName(altName->name, altName->len, domain)) { + match = 1; + *checkCN = 0; + break; + } + /* No matches and wild pattern match failed. */ + else if (altName->name && altName->len >=1 && + altName->name[0] == '*' && match == 0) { + match = -1; + } + + altName = altName->next; + } + + return match != -1; +} + +/* Check the domain name matches the subject alternative name or the subject + * name. + * + * dcert Decoded certificate. + * domainName The domain name. + * domainNameLen The length of the domain name. + * returns DOMAIN_NAME_MISMATCH when no match found and 0 on success. + */ +int CheckHostName(DecodedCert* dCert, char *domainName, size_t domainNameLen) +{ + int checkCN; + + /* Assume name is NUL terminated. */ + (void)domainNameLen; + + if (CheckForAltNames(dCert, domainName, &checkCN) == 0) { + WOLFSSL_MSG("DomainName match on alt names failed too"); + return DOMAIN_NAME_MISMATCH; + } + if (checkCN == 1) { + if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen, + domainName) == 0) { + WOLFSSL_MSG("DomainName match on common name failed"); + return DOMAIN_NAME_MISMATCH; + } + } + + return 0; +} + +int CheckIPAddr(DecodedCert* dCert, char* ipasc) +{ + WOLFSSL_MSG("Checking IPAddr"); + + return CheckHostName(dCert, ipasc, (size_t)XSTRLEN(ipasc)); +} +#endif + +#ifdef SESSION_CERTS +static void AddSessionCertToChain(WOLFSSL_X509_CHAIN* chain, + byte* certBuf, word32 certSz) +{ + if (chain->count < MAX_CHAIN_DEPTH && + certSz < MAX_X509_SIZE) { + chain->certs[chain->count].length = certSz; + XMEMCPY(chain->certs[chain->count].buffer, certBuf, certSz); + chain->count++; + } + else { + WOLFSSL_MSG("Couldn't store chain cert for session"); + } +} +#endif + +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Copy parts X509 needs from Decoded cert, 0 on success */ +/* The same DecodedCert cannot be copied to WOLFSSL_X509 twice otherwise the + * altNames pointers could be free'd by second x509 still active by first */ +int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) +{ + int ret = 0; + + if (x509 == NULL || dCert == NULL || + dCert->subjectCNLen < 0) + return BAD_FUNC_ARG; + + x509->version = dCert->version + 1; + + XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX); + x509->issuer.name[ASN_NAME_MAX - 1] = '\0'; + x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + if (dCert->issuerName.fullName != NULL) { + XMEMCPY(&x509->issuer.fullName, + &dCert->issuerName, sizeof(DecodedName)); + x509->issuer.fullName.fullName = (char*)XMALLOC( + dCert->issuerName.fullNameLen, x509->heap, + DYNAMIC_TYPE_X509); + if (x509->issuer.fullName.fullName != NULL) + XMEMCPY(x509->issuer.fullName.fullName, + dCert->issuerName.fullName, dCert->issuerName.fullNameLen); + } + x509->issuer.x509 = x509; +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + + XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX); + x509->subject.name[ASN_NAME_MAX - 1] = '\0'; + x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + if (dCert->subjectName.fullName != NULL) { + XMEMCPY(&x509->subject.fullName, + &dCert->subjectName, sizeof(DecodedName)); + x509->subject.fullName.fullName = (char*)XMALLOC( + dCert->subjectName.fullNameLen, x509->heap, DYNAMIC_TYPE_X509); + if (x509->subject.fullName.fullName != NULL) + XMEMCPY(x509->subject.fullName.fullName, + dCert->subjectName.fullName, dCert->subjectName.fullNameLen); + } + x509->subject.x509 = x509; +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + x509->subject.rawLen = min(dCert->subjectRawLen, sizeof(x509->subject.raw)); + XMEMCPY(x509->subject.raw, dCert->subjectRaw, x509->subject.rawLen); +#ifdef WOLFSSL_CERT_EXT + x509->issuer.rawLen = min(dCert->issuerRawLen, sizeof(x509->issuer.raw)); + XMEMCPY(x509->issuer.raw, dCert->issuerRaw, x509->issuer.rawLen); +#endif +#endif + + XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE); + x509->serialSz = dCert->serialSz; + if (dCert->subjectCN && dCert->subjectCNLen < ASN_NAME_MAX) { + XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen); + x509->subjectCN[dCert->subjectCNLen] = '\0'; + } + else + x509->subjectCN[0] = '\0'; + +#ifdef WOLFSSL_SEP + { + int minSz = min(dCert->deviceTypeSz, EXTERNAL_SERIAL_SIZE); + if (minSz > 0) { + x509->deviceTypeSz = minSz; + XMEMCPY(x509->deviceType, dCert->deviceType, minSz); + } + else + x509->deviceTypeSz = 0; + minSz = min(dCert->hwTypeSz, EXTERNAL_SERIAL_SIZE); + if (minSz > 0) { + x509->hwTypeSz = minSz; + XMEMCPY(x509->hwType, dCert->hwType, minSz); + } + else + x509->hwTypeSz = 0; + minSz = min(dCert->hwSerialNumSz, EXTERNAL_SERIAL_SIZE); + if (minSz > 0) { + x509->hwSerialNumSz = minSz; + XMEMCPY(x509->hwSerialNum, dCert->hwSerialNum, minSz); + } + else + x509->hwSerialNumSz = 0; + } +#endif /* WOLFSSL_SEP */ + { + int minSz; + if (dCert->beforeDateLen > 0) { + minSz = min(dCert->beforeDate[1], MAX_DATE_SZ); + x509->notBefore.type = dCert->beforeDate[0]; + x509->notBefore.length = minSz; + XMEMCPY(x509->notBefore.data, &dCert->beforeDate[2], minSz); + } + else + x509->notBefore.length = 0; + if (dCert->afterDateLen > 0) { + minSz = min(dCert->afterDate[1], MAX_DATE_SZ); + x509->notAfter.type = dCert->afterDate[0]; + x509->notAfter.length = minSz; + XMEMCPY(x509->notAfter.data, &dCert->afterDate[2], minSz); + } + else + x509->notAfter.length = 0; + } + + if (dCert->publicKey != NULL && dCert->pubKeySize != 0) { + x509->pubKey.buffer = (byte*)XMALLOC( + dCert->pubKeySize, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (x509->pubKey.buffer != NULL) { + x509->pubKeyOID = dCert->keyOID; + x509->pubKey.length = dCert->pubKeySize; + XMEMCPY(x509->pubKey.buffer, dCert->publicKey, dCert->pubKeySize); + } + else + ret = MEMORY_E; +#if defined(OPENSSL_ALL) + if (ret == 0) { + x509->key.pubKeyOID = dCert->keyOID; + + if (!x509->key.algor) { + x509->key.algor = wolfSSL_X509_ALGOR_new(); + } else { + wolfSSL_ASN1_OBJECT_free(x509->key.algor->algorithm); + } + if (!(x509->key.algor->algorithm = + wolfSSL_OBJ_nid2obj(dCert->keyOID))) { + ret = PUBLIC_KEY_E; + } + + wolfSSL_EVP_PKEY_free(x509->key.pkey); + if (!(x509->key.pkey = wolfSSL_d2i_PUBKEY(NULL, + &dCert->publicKey, + dCert->pubKeySize))) { + ret = PUBLIC_KEY_E; + } + } +#endif + } + + if (dCert->signature != NULL && dCert->sigLength != 0 && + dCert->sigLength <= MAX_ENCODED_SIG_SZ) { + x509->sig.buffer = (byte*)XMALLOC( + dCert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE); + if (x509->sig.buffer == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(x509->sig.buffer, dCert->signature, dCert->sigLength); + x509->sig.length = dCert->sigLength; + x509->sigOID = dCert->signatureOID; + } +#if defined(OPENSSL_ALL) + wolfSSL_ASN1_OBJECT_free(x509->algor.algorithm); + if (!(x509->algor.algorithm = + wolfSSL_OBJ_nid2obj(dCert->signatureOID))) { + ret = PUBLIC_KEY_E; + } +#endif + } + + /* store cert for potential retrieval */ + if (AllocDer(&x509->derCert, dCert->maxIdx, CERT_TYPE, x509->heap) == 0) { + XMEMCPY(x509->derCert->buffer, dCert->source, dCert->maxIdx); + } + else { + ret = MEMORY_E; + } + + x509->altNames = dCert->altNames; + dCert->weOwnAltNames = 0; + x509->altNamesNext = x509->altNames; /* index hint */ + +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + !defined(IGNORE_NAME_CONSTRAINTS) + /* add copies of alternate emails from dCert to X509 */ + if (dCert->altEmailNames != NULL) { + DNS_entry* cur = dCert->altEmailNames; + + while (cur != NULL) { + if (cur->type == ASN_RFC822_TYPE) { + DNS_entry* dnsEntry; + int strLen = cur->len; + + dnsEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), x509->heap, + DYNAMIC_TYPE_ALTNAME); + if (dnsEntry == NULL) { + WOLFSSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + + dnsEntry->type = ASN_RFC822_TYPE; + dnsEntry->name = (char*)XMALLOC(strLen + 1, x509->heap, + DYNAMIC_TYPE_ALTNAME); + if (dnsEntry->name == NULL) { + WOLFSSL_MSG("\tOut of Memory"); + XFREE(dnsEntry, x509->heap, DYNAMIC_TYPE_ALTNAME); + return MEMORY_E; + } + dnsEntry->len = strLen; + XMEMCPY(dnsEntry->name, cur->name, strLen); + dnsEntry->name[strLen] = '\0'; + + dnsEntry->next = x509->altNames; + x509->altNames = dnsEntry; + } + cur = cur->next; + } + } +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + + x509->isCa = dCert->isCA; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + x509->pathLength = dCert->pathLength; + x509->keyUsage = dCert->extKeyUsage; + + x509->CRLdistSet = dCert->extCRLdistSet; + x509->CRLdistCrit = dCert->extCRLdistCrit; + x509->CRLInfo = dCert->extCrlInfo; + x509->CRLInfoSz = dCert->extCrlInfoSz; + x509->authInfoSet = dCert->extAuthInfoSet; + x509->authInfoCrit = dCert->extAuthInfoCrit; + if (dCert->extAuthInfo != NULL && dCert->extAuthInfoSz > 0) { + x509->authInfo = (byte*)XMALLOC(dCert->extAuthInfoSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->authInfo != NULL) { + XMEMCPY(x509->authInfo, dCert->extAuthInfo, dCert->extAuthInfoSz); + x509->authInfoSz = dCert->extAuthInfoSz; + } + else { + ret = MEMORY_E; + } + } + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + if (dCert->extAuthInfoCaIssuer != NULL && dCert->extAuthInfoCaIssuerSz > 0) { + x509->authInfoCaIssuer = (byte*)XMALLOC(dCert->extAuthInfoCaIssuerSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->authInfoCaIssuer != NULL) { + XMEMCPY(x509->authInfoCaIssuer, dCert->extAuthInfoCaIssuer, dCert->extAuthInfoCaIssuerSz); + x509->authInfoCaIssuerSz = dCert->extAuthInfoCaIssuerSz; + } + else { + ret = MEMORY_E; + } + } + #endif + x509->basicConstSet = dCert->extBasicConstSet; + x509->basicConstCrit = dCert->extBasicConstCrit; + x509->basicConstPlSet = dCert->pathLengthSet; + x509->subjAltNameSet = dCert->extSubjAltNameSet; + x509->subjAltNameCrit = dCert->extSubjAltNameCrit; + x509->authKeyIdSet = dCert->extAuthKeyIdSet; + x509->authKeyIdCrit = dCert->extAuthKeyIdCrit; + if (dCert->extAuthKeyIdSrc != NULL && dCert->extAuthKeyIdSz != 0) { + x509->authKeyId = (byte*)XMALLOC(dCert->extAuthKeyIdSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->authKeyId != NULL) { + XMEMCPY(x509->authKeyId, + dCert->extAuthKeyIdSrc, dCert->extAuthKeyIdSz); + x509->authKeyIdSz = dCert->extAuthKeyIdSz; + } + else + ret = MEMORY_E; + } + x509->subjKeyIdSet = dCert->extSubjKeyIdSet; + x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit; + if (dCert->extSubjKeyIdSrc != NULL && dCert->extSubjKeyIdSz != 0) { + x509->subjKeyId = (byte*)XMALLOC(dCert->extSubjKeyIdSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->subjKeyId != NULL) { + XMEMCPY(x509->subjKeyId, + dCert->extSubjKeyIdSrc, dCert->extSubjKeyIdSz); + x509->subjKeyIdSz = dCert->extSubjKeyIdSz; + } + else + ret = MEMORY_E; + } + x509->keyUsageSet = dCert->extKeyUsageSet; + x509->keyUsageCrit = dCert->extKeyUsageCrit; + if (dCert->extExtKeyUsageSrc != NULL && dCert->extExtKeyUsageSz > 0) { + x509->extKeyUsageSrc = (byte*)XMALLOC(dCert->extExtKeyUsageSz, + x509->heap, DYNAMIC_TYPE_X509_EXT); + if (x509->extKeyUsageSrc != NULL) { + XMEMCPY(x509->extKeyUsageSrc, dCert->extExtKeyUsageSrc, + dCert->extExtKeyUsageSz); + x509->extKeyUsageSz = dCert->extExtKeyUsageSz; + x509->extKeyUsageCrit = dCert->extExtKeyUsageCrit; + x509->extKeyUsageCount = dCert->extExtKeyUsageCount; + } + else { + ret = MEMORY_E; + } + } + #if defined(WOLFSSL_SEP) || defined(WOLFSSL_QT) + x509->certPolicySet = dCert->extCertPolicySet; + x509->certPolicyCrit = dCert->extCertPolicyCrit; + #endif /* WOLFSSL_SEP || WOLFSSL_QT */ + #ifdef WOLFSSL_CERT_EXT + { + int i; + for (i = 0; i < dCert->extCertPoliciesNb && i < MAX_CERTPOL_NB; i++) + XMEMCPY(x509->certPolicies[i], dCert->extCertPolicies[i], + MAX_CERTPOL_SZ); + x509->certPoliciesNb = dCert->extCertPoliciesNb; + } + #endif /* WOLFSSL_CERT_EXT */ +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + x509->pkCurveOID = dCert->pkCurveOID; +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + + return ret; +} + +#endif /* KEEP_PEER_CERT || SESSION_CERTS */ + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + (defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) && !defined(WOLFSSL_NO_TLS12)) +static int ProcessCSR(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 status_length) +{ + int ret = 0; + OcspRequest* request; + + #ifdef WOLFSSL_SMALL_STACK + CertStatus* status; + OcspResponse* response; + #else + CertStatus status[1]; + OcspResponse response[1]; + #endif + + do { + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST + if (ssl->status_request) { + request = (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions); + ssl->status_request = 0; + break; + } + #endif + + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) { + request = (OcspRequest*)TLSX_CSR2_GetRequest(ssl->extensions, + WOLFSSL_CSR2_OCSP, 0); + ssl->status_request_v2 = 0; + break; + } + #endif + + return BUFFER_ERROR; + } while(0); + + if (request == NULL) + return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */ + + #ifdef WOLFSSL_SMALL_STACK + status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap, + DYNAMIC_TYPE_OCSP_STATUS); + response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap, + DYNAMIC_TYPE_OCSP_REQUEST); + + if (status == NULL || response == NULL) { + if (status) + XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS); + if (response) + XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + + return MEMORY_ERROR; + } + #endif + + InitOcspResponse(response, status, input +*inOutIdx, status_length); + + if (OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, 0) != 0) + ret = BAD_CERTIFICATE_STATUS_ERROR; + else if (CompareOcspReqResp(request, response) != 0) + ret = BAD_CERTIFICATE_STATUS_ERROR; + else if (response->responseStatus != OCSP_SUCCESSFUL) + ret = BAD_CERTIFICATE_STATUS_ERROR; + else if (response->status->status == CERT_REVOKED) + ret = OCSP_CERT_REVOKED; + else if (response->status->status != CERT_GOOD) + ret = BAD_CERTIFICATE_STATUS_ERROR; + + *inOutIdx += status_length; + + #ifdef WOLFSSL_SMALL_STACK + XFREE(status, ssl->heap, DYNAMIC_TYPE_OCSP_STATUS); + XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + #endif + + return ret; +} +#endif + + + +#ifdef HAVE_PK_CALLBACKS + +#ifdef HAVE_ECC + static int SigPkCbEccVerify(const unsigned char* sig, unsigned int sigSz, + const unsigned char* hash, unsigned int hashSz, + const unsigned char* keyDer, unsigned int keySz, + int* result, void* ctx) + { + int ret = NOT_COMPILED_IN; + WOLFSSL* ssl = (WOLFSSL*)ctx; + + if (ssl && ssl->ctx->EccVerifyCb) { + ret = ssl->ctx->EccVerifyCb(ssl, sig, sigSz, hash, hashSz, + keyDer, keySz, result, ssl->EccVerifyCtx); + } + return ret; + } +#endif +#ifndef NO_RSA + static int SigPkCbRsaVerify(unsigned char* sig, unsigned int sigSz, + unsigned char** out, const unsigned char* keyDer, unsigned int keySz, + void* ctx) + { + int ret = NOT_COMPILED_IN; + WOLFSSL* ssl = (WOLFSSL*)ctx; + + if (ssl && ssl->ctx->RsaVerifyCb) { + ret = ssl->ctx->RsaVerifyCb(ssl, sig, sigSz, out, keyDer, keySz, + ssl->RsaVerifyCtx); + } + return ret; + } +#endif + +int InitSigPkCb(WOLFSSL* ssl, SignatureCtx* sigCtx) +{ + if (ssl == NULL || sigCtx == NULL) + return BAD_FUNC_ARG; + + /* only setup the verify callback if a PK is set */ +#ifdef HAVE_ECC + if (ssl->ctx->EccVerifyCb) { + sigCtx->pkCbEcc = SigPkCbEccVerify; + sigCtx->pkCtxEcc = ssl; + } +#endif +#ifndef NO_RSA + /* only setup the verify callback if a PK is set */ + if (ssl->ctx->RsaVerifyCb) { + sigCtx->pkCbRsa = SigPkCbRsaVerify; + sigCtx->pkCtxRsa = ssl; + } +#endif + + return 0; +} + +#endif /* HAVE_PK_CALLBACKS */ + + +#if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) +static void DoCertFatalAlert(WOLFSSL* ssl, int ret) +{ + int alertWhy; + if (ssl == NULL || ret == 0) { + return; + } + + /* Determine alert reason */ + alertWhy = bad_certificate; + if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) { + alertWhy = certificate_expired; + } +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD)) + else if (ret == CRL_CERT_REVOKED) { + alertWhy = certificate_revoked; + } +#endif + else if (ret == NO_PEER_CERT) { +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + alertWhy = certificate_required; + } + else +#endif + { + alertWhy = handshake_failure; + } + } + + /* send fatal alert and mark connection closed */ + SendAlert(ssl, alert_fatal, alertWhy); /* try to send */ + ssl->options.isClosed = 1; +} + +/* WOLFSSL_ALWAYS_VERIFY_CB: Use verify callback for success or failure cases */ +/* WOLFSSL_VERIFY_CB_ALL_CERTS: Issue callback for all intermediate certificates */ + +/* Callback is issued for certificate presented in TLS Certificate (11) packet. + * The intermediates are done first then peer leaf cert last. Use the + * store->error_depth member to determine index (0=peer, >1 intermediates) + */ + +int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int ret, + ProcPeerCertArgs* args) +{ + int verify_ok = 0, use_cb = 0; + void *heap = (ssl != NULL) ? ssl->heap : cm->heap; + + /* Determine if verify was okay */ + if (ret == 0) { + verify_ok = 1; + } + + /* Determine if verify callback should be used */ + if (ret != 0) { + if ((ssl != NULL) && (!ssl->options.verifyNone)) { + use_cb = 1; /* always report errors */ + } + } +#ifdef WOLFSSL_ALWAYS_VERIFY_CB + /* always use verify callback on peer leaf cert */ + if (args->certIdx == 0) { + use_cb = 1; + } +#endif +#ifdef WOLFSSL_VERIFY_CB_ALL_CERTS + /* perform verify callback on other intermediate certs (not just peer) */ + if (args->certIdx > 0) { + use_cb = 1; + } +#endif +#if defined(OPENSSL_EXTRA) + /* perform domain name check on the peer certificate */ + if (args->dCertInit && args->dCert && (ssl != NULL) && + ssl->param && ssl->param->hostName[0]) { + /* If altNames names is present, then subject common name is ignored */ + if (args->dCert->altNames != NULL) { + if (CheckAltNames(args->dCert, ssl->param->hostName) == 0 ) { + if (ret == 0) { + ret = DOMAIN_NAME_MISMATCH; + } + } + } + else { + if (args->dCert->subjectCN) { + if (MatchDomainName(args->dCert->subjectCN, + args->dCert->subjectCNLen, + ssl->param->hostName) == 0) { + if (ret == 0) { + ret = DOMAIN_NAME_MISMATCH; + } + } + } + } + } + + /* perform IP address check on the peer certificate */ + if ((args->dCertInit != 0) && (args->dCert != NULL) && (ssl != NULL) && + (ssl->param != NULL) && (XSTRLEN(ssl->param->ipasc) > 0)) { + if (CheckIPAddr(args->dCert, ssl->param->ipasc) != 0) { + if (ret == 0) { + ret = IPADDR_MISMATCH; + } + } + } +#endif + /* if verify callback has been set */ + if ((use_cb && (ssl != NULL) && ((ssl->verifyCallback != NULL) + #ifdef OPENSSL_ALL + || (ssl->ctx->verifyCertCb != NULL) + #endif + )) + #ifndef NO_WOLFSSL_CM_VERIFY + || (cm->verifyCallback != NULL) + #endif + ) { + int verifyFail = 0; + #ifdef WOLFSSL_SMALL_STACK + WOLFSSL_X509_STORE_CTX* store; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + WOLFSSL_X509* x509; + #endif + char* domain = NULL; + #else + WOLFSSL_X509_STORE_CTX store[1]; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + WOLFSSL_X509 x509[1]; + #endif + char domain[ASN_NAME_MAX]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + store = (WOLFSSL_X509_STORE_CTX*)XMALLOC( + sizeof(WOLFSSL_X509_STORE_CTX), heap, DYNAMIC_TYPE_X509_STORE); + if (store == NULL) { + return MEMORY_E; + } + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, + DYNAMIC_TYPE_X509); + if (x509 == NULL) { + XFREE(store, heap, DYNAMIC_TYPE_X509); + return MEMORY_E; + } + #endif + domain = (char*)XMALLOC(ASN_NAME_MAX, heap, DYNAMIC_TYPE_STRING); + if (domain == NULL) { + XFREE(store, heap, DYNAMIC_TYPE_X509); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + XFREE(x509, heap, DYNAMIC_TYPE_X509); + #endif + return MEMORY_E; + } + #endif /* WOLFSSL_SMALL_STACK */ + + XMEMSET(store, 0, sizeof(WOLFSSL_X509_STORE_CTX)); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + XMEMSET(x509, 0, sizeof(WOLFSSL_X509)); + #endif + domain[0] = '\0'; + + /* build subject CN as string to return in store */ + if (args->dCertInit && args->dCert && args->dCert->subjectCN) { + int subjectCNLen = args->dCert->subjectCNLen; + if (subjectCNLen > ASN_NAME_MAX-1) + subjectCNLen = ASN_NAME_MAX-1; + if (subjectCNLen > 0) { + XMEMCPY(domain, args->dCert->subjectCN, subjectCNLen); + domain[subjectCNLen] = '\0'; + } + } + + store->error = ret; + store->error_depth = args->certIdx; + store->discardSessionCerts = 0; + store->domain = domain; + store->userCtx = (ssl != NULL) ? ssl->verifyCbCtx : cm; + store->certs = args->certs; + store->totalCerts = args->totalCerts; + #if defined(HAVE_EX_DATA) || defined(FORTRESS) + if (wolfSSL_CRYPTO_set_ex_data(&store->ex_data, 0, ssl) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to store ssl context in WOLFSSL_X509_STORE_CTX"); + } + #endif + + if (ssl != NULL) { + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if (ssl->ctx->x509_store_pt != NULL) { + store->store = ssl->ctx->x509_store_pt; + } + else { + store->store = &ssl->ctx->x509_store; + } + #if defined(OPENSSL_EXTRA) + store->depth = args->count; + store->param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC( + sizeof(WOLFSSL_X509_VERIFY_PARAM), + heap, DYNAMIC_TYPE_OPENSSL); + if (store->param == NULL) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(domain, heap, DYNAMIC_TYPE_STRING); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + XFREE(x509, heap, DYNAMIC_TYPE_X509); + #endif + XFREE(store, heap, DYNAMIC_TYPE_X509_STORE); + #endif + return MEMORY_E; + } + XMEMSET(store->param, 0, sizeof(WOLFSSL_X509_VERIFY_PARAM)); + /* Overwrite with non-default param values in SSL */ + if (ssl->param) { + if (ssl->param->check_time) + store->param->check_time = ssl->param->check_time; + + if (ssl->param->flags) + store->param->flags = ssl->param->flags; + + if (ssl->param->hostName[0]) + XMEMCPY(store->param->hostName, ssl->param->hostName, + WOLFSSL_HOST_NAME_MAX); + + } + #endif /* defined(OPENSSL_EXTRA) */ + #endif /* defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)*/ + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + #ifdef KEEP_PEER_CERT + if (args->certIdx == 0) { + store->current_cert = &ssl->peerCert; /* use existing X509 */ + } + else + #endif + { + InitX509(x509, 0, heap); + if (CopyDecodedToX509(x509, args->dCert) == 0) { + store->current_cert = x509; + } + else { + FreeX509(x509); + } + } + #endif + #ifdef SESSION_CERTS + store->sesChain = &ssl->session.chain; + #endif + } + #ifndef NO_WOLFSSL_CM_VERIFY + /* non-zero return code indicates failure override */ + if ((cm != NULL) && (cm->verifyCallback != NULL)) { + store->userCtx = cm; + if (cm->verifyCallback(verify_ok, store)) { + if (ret != 0) { + WOLFSSL_MSG("Verify CM callback overriding error!"); + ret = 0; + } + } + else { + verifyFail = 1; + } + } + #endif + + if (ssl != NULL) { + #ifdef OPENSSL_ALL + /* non-zero return code indicates failure override */ + if (ssl->ctx->verifyCertCb) { + if (ssl->ctx->verifyCertCb(store, ssl->ctx->verifyCertCbArg)) { + if (ret != 0) { + WOLFSSL_MSG("Verify Cert callback overriding error!"); + ret = 0; + } + } + else { + verifyFail = 1; + } + } + #endif + + /* non-zero return code indicates failure override */ + if (ssl->verifyCallback) { + if (ssl->verifyCallback(verify_ok, store)) { + if (ret != 0) { + WOLFSSL_MSG("Verify callback overriding error!"); + ret = 0; + } + } + else { + verifyFail = 1; + } + } + } + + if (verifyFail) { + /* induce error if one not present */ + if (ret == 0) { + ret = VERIFY_CERT_ERROR; + } + + /* mark as verify error */ + args->verifyErr = 1; + } + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + if (args->certIdx > 0) + FreeX509(x509); + #endif + #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + wolfSSL_sk_X509_free(store->chain); + store->chain = NULL; + #endif + #ifdef SESSION_CERTS + if ((ssl != NULL) && (store->discardSessionCerts)) { + WOLFSSL_MSG("Verify callback requested discard sess certs"); + ssl->session.chain.count = 0; + #ifdef WOLFSSL_ALT_CERT_CHAINS + ssl->session.altChain.count = 0; + #endif + } + #endif /* SESSION_CERTS */ +#ifdef OPENSSL_EXTRA + if ((ssl != NULL) && (store->param)) { + XFREE(store->param, heap, DYNAMIC_TYPE_OPENSSL); + } +#endif + #ifdef WOLFSSL_SMALL_STACK + XFREE(domain, heap, DYNAMIC_TYPE_STRING); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + XFREE(x509, heap, DYNAMIC_TYPE_X509); + #endif + XFREE(store, heap, DYNAMIC_TYPE_X509_STORE); + #endif + } + + (void)heap; + + return ret; +} + +static void FreeProcPeerCertArgs(WOLFSSL* ssl, void* pArgs) +{ + ProcPeerCertArgs* args = (ProcPeerCertArgs*)pArgs; + + (void)ssl; + + if (args->certs) { + XFREE(args->certs, ssl->heap, DYNAMIC_TYPE_DER); + args->certs = NULL; + } +#ifdef WOLFSSL_TLS13 + if (args->exts) { + XFREE(args->exts, ssl->heap, DYNAMIC_TYPE_CERT_EXT); + args->exts = NULL; + } +#endif + if (args->dCert) { + if (args->dCertInit) { + FreeDecodedCert(args->dCert); + args->dCertInit = 0; + } + XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT); + args->dCert = NULL; + } +} + +static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args, + int certType, int verify, byte** pSubjectHash, int* pAlreadySigner) +{ + int ret = 0; + buffer* cert; + byte* subjectHash = NULL; + int alreadySigner = 0; +#ifdef WOLFSSL_SMALL_CERT_VERIFY + int sigRet = 0; +#endif + + if (ssl == NULL || args == NULL) + return BAD_FUNC_ARG; + + /* check to make sure certificate index is valid */ + if (args->certIdx > args->count) + return BUFFER_E; + + /* check if returning from non-blocking OCSP */ + /* skip this section because cert is already initialized and parsed */ +#ifdef WOLFSSL_NONBLOCK_OCSP + if (args->lastErr == OCSP_WANT_READ) { + args->lastErr = 0; /* clear error */ + return 0; + } +#endif + +#ifdef WOLFSSL_TRUST_PEER_CERT + /* we have trusted peer */ + if (args->haveTrustPeer) { + return 0; + } +#endif + + /* get certificate buffer */ + cert = &args->certs[args->certIdx]; + +#ifdef WOLFSSL_SMALL_CERT_VERIFY + if (verify == VERIFY) { + /* for small cert verify, release decoded cert during signature check to + reduce peak memory usage */ + if (args->dCert != NULL) { + if (args->dCertInit) { + FreeDecodedCert(args->dCert); + args->dCertInit = 0; + } + XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT); + args->dCert = NULL; + } + + /* perform cert parsing and signature check */ + sigRet = CheckCertSignature(cert->buffer, cert->length, + ssl->heap, ssl->ctx->cm); + /* fail on errors here after the ParseCertRelative call, so dCert is populated */ + + /* verify name only in ParseCertRelative below, signature check done */ + verify = VERIFY_NAME; + } +#endif /* WOLFSSL_SMALL_CERT_VERIFY */ + + /* make sure the decoded cert structure is allocated and initialized */ + if (!args->dCertInit + #ifdef WOLFSSL_SMALL_CERT_VERIFY + || args->dCert == NULL + #endif + ) { + #ifdef WOLFSSL_SMALL_CERT_VERIFY + if (args->dCert == NULL) { + args->dCert = (DecodedCert*)XMALLOC( + sizeof(DecodedCert), ssl->heap, + DYNAMIC_TYPE_DCERT); + if (args->dCert == NULL) { + return MEMORY_E; + } + } + #endif + + InitDecodedCert(args->dCert, cert->buffer, cert->length, ssl->heap); + + args->dCertInit = 1; + args->dCert->sigCtx.devId = ssl->devId; + #ifdef WOLFSSL_ASYNC_CRYPT + args->dCert->sigCtx.asyncCtx = ssl; + #endif + + #ifdef HAVE_PK_CALLBACKS + /* setup the PK callback context */ + ret = InitSigPkCb(ssl, &args->dCert->sigCtx); + if (ret != 0) + return ret; + #endif + } + + /* Parse Certificate */ + ret = ParseCertRelative(args->dCert, certType, verify, ssl->ctx->cm); + /* perform below checks for date failure cases */ + if (ret == 0 || ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E) { + /* get subject and determine if already loaded */ + #ifndef NO_SKID + if (args->dCert->extAuthKeyIdSet) + subjectHash = args->dCert->extSubjKeyId; + else + #endif + subjectHash = args->dCert->subjectHash; + alreadySigner = AlreadySigner(ssl->ctx->cm, subjectHash); + } + +#ifdef WOLFSSL_SMALL_CERT_VERIFY + /* get signature check failures from above */ + if (ret == 0) + ret = sigRet; +#endif + + if (pSubjectHash) + *pSubjectHash = subjectHash; + if (pAlreadySigner) + *pAlreadySigner = alreadySigner; + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, + args->dCert->sigCtx.asyncDev); + } +#endif + + return ret; +} + +/* Check key sizes for certs. Is redundant check since + ProcessBuffer also performs this check. */ +static int ProcessPeerCertCheckKey(WOLFSSL* ssl, ProcPeerCertArgs* args) +{ + int ret = 0; + + if (ssl->options.verifyNone) { + return ret; + } + + switch (args->dCert->keyOID) { + #ifndef NO_RSA + case RSAk: + if (ssl->options.minRsaKeySz < 0 || + args->dCert->pubKeySize < + (word16)ssl->options.minRsaKeySz) { + WOLFSSL_MSG( + "RSA key size in cert chain error"); + ret = RSA_KEY_SIZE_E; + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (ssl->options.minEccKeySz < 0 || + args->dCert->pubKeySize < + (word16)ssl->options.minEccKeySz) { + WOLFSSL_MSG( + "ECC key size in cert chain error"); + ret = ECC_KEY_SIZE_E; + } + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (ssl->options.minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)ssl->options.minEccKeySz) { + WOLFSSL_MSG( + "ECC key size in cert chain error"); + ret = ECC_KEY_SIZE_E; + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + if (ssl->options.minEccKeySz < 0 || + ED448_KEY_SIZE < (word16)ssl->options.minEccKeySz) { + WOLFSSL_MSG( + "ECC key size in cert chain error"); + ret = ECC_KEY_SIZE_E; + } + break; + #endif /* HAVE_ED448 */ + default: + WOLFSSL_MSG("Key size not checked"); + /* key not being checked for size if not in + switch */ + break; + } + + return ret; +} + +int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + ProcPeerCertArgs* args = (ProcPeerCertArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#elif defined(WOLFSSL_NONBLOCK_OCSP) + ProcPeerCertArgs* args = ssl->nonblockarg; +#elif defined(WOLFSSL_SMALL_STACK) + ProcPeerCertArgs* args = NULL; +#else + ProcPeerCertArgs args[1]; +#endif + byte* subjectHash = NULL; + int alreadySigner = 0; + + WOLFSSL_ENTER("ProcessPeerCerts"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_ppc; + } + else +#elif defined(WOLFSSL_NONBLOCK_OCSP) + if (args == NULL) { + args = (ProcPeerCertArgs*)XMALLOC( + sizeof(ProcPeerCertArgs), ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (args == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } + } + if (ssl->nonblockarg == NULL) /* new args */ +#elif defined(WOLFSSL_SMALL_STACK) + args = (ProcPeerCertArgs*)XMALLOC( + sizeof(ProcPeerCertArgs), ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (args == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(ProcPeerCertArgs)); + args->idx = *inOutIdx; + args->begin = *inOutIdx; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeProcPeerCertArgs; + #elif defined(WOLFSSL_NONBLOCK_OCSP) + ssl->nonblockarg = args; + #endif + } + + switch (ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + word32 listSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "Certificate"); + if (ssl->toInfoOn) + AddLateName("Certificate", &ssl->timeoutInfo); + #endif + + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + byte ctxSz; + + /* Certificate Request Context */ + if ((args->idx - args->begin) + OPAQUE8_LEN > totalSz) + ERROR_OUT(BUFFER_ERROR, exit_ppc); + ctxSz = *(input + args->idx); + args->idx++; + if ((args->idx - args->begin) + ctxSz > totalSz) + ERROR_OUT(BUFFER_ERROR, exit_ppc); + #ifndef NO_WOLFSSL_CLIENT + /* Must be empty when received from server. */ + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ctxSz != 0) { + ERROR_OUT(INVALID_CERT_CTX_E, exit_ppc); + } + } + #endif + #ifndef NO_WOLFSSL_SERVER + /* Must contain value sent in request. */ + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.handShakeState != HANDSHAKE_DONE && + ctxSz != 0) { + ERROR_OUT(INVALID_CERT_CTX_E, exit_ppc); + } + else if (ssl->options.handShakeState == HANDSHAKE_DONE) { + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + CertReqCtx* curr = ssl->certReqCtx; + CertReqCtx* prev = NULL; + while (curr != NULL) { + if ((ctxSz == curr->len) && + XMEMCMP(&curr->ctx, input + args->idx, ctxSz) + == 0) { + if (prev != NULL) + prev->next = curr->next; + else + ssl->certReqCtx = curr->next; + XFREE(curr, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + break; + } + prev = curr; + curr = curr->next; + } + if (curr == NULL) + #endif + ERROR_OUT(INVALID_CERT_CTX_E, exit_ppc); + } + } + #endif + args->idx += ctxSz; + + #ifdef OPENSSL_EXTRA + /* allocate buffer for cert extensions */ + args->exts = (buffer*)XMALLOC(sizeof(buffer) * + (ssl->verifyDepth + 1), ssl->heap, DYNAMIC_TYPE_CERT_EXT); + if (args->exts == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } + #else + /* allocate buffer for cert extensions */ + args->exts = (buffer*)XMALLOC(sizeof(buffer) * MAX_CHAIN_DEPTH, + ssl->heap, DYNAMIC_TYPE_CERT_EXT); + if (args->exts == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } + #endif + } + #endif + + /* allocate buffer for certs */ + #ifdef OPENSSL_EXTRA + args->certs = (buffer*)XMALLOC(sizeof(buffer) * + (ssl->verifyDepth + 1), ssl->heap, DYNAMIC_TYPE_DER); + if (args->certs == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } + XMEMSET(args->certs, 0, sizeof(buffer) * (ssl->verifyDepth + 1)); + #else + args->certs = (buffer*)XMALLOC(sizeof(buffer) * MAX_CHAIN_DEPTH, + ssl->heap, DYNAMIC_TYPE_DER); + if (args->certs == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } + XMEMSET(args->certs, 0, sizeof(buffer) * MAX_CHAIN_DEPTH); + #endif /* OPENSSL_EXTRA */ + + /* Certificate List */ + if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + c24to32(input + args->idx, &listSz); + args->idx += OPAQUE24_LEN; + if (listSz > MAX_CERTIFICATE_SZ) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + if ((args->idx - args->begin) + listSz != totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + + WOLFSSL_MSG("Loading peer's cert chain"); + /* first put cert chain into buffer so can verify top down + we're sent bottom up */ + while (listSz) { + word32 certSz; + + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + if (args->totalCerts > ssl->verifyDepth) { + ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG; + ERROR_OUT(MAX_CHAIN_ERROR, exit_ppc); + } + #else + if (args->totalCerts >= ssl->verifyDepth || + args->totalCerts >= MAX_CHAIN_DEPTH) { + ERROR_OUT(MAX_CHAIN_ERROR, exit_ppc); + } + #endif + + if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + + c24to32(input + args->idx, &certSz); + args->idx += OPAQUE24_LEN; + + if ((args->idx - args->begin) + certSz > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + + args->certs[args->totalCerts].length = certSz; + args->certs[args->totalCerts].buffer = input + args->idx; + + #ifdef SESSION_CERTS + AddSessionCertToChain(&ssl->session.chain, + input + args->idx, certSz); + #endif /* SESSION_CERTS */ + + args->idx += certSz; + listSz -= certSz + CERT_HEADER_SZ; + + #ifdef WOLFSSL_TLS13 + /* Extensions */ + if (ssl->options.tls1_3) { + word16 extSz; + + if ((args->idx - args->begin) + OPAQUE16_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + ato16(input + args->idx, &extSz); + args->idx += OPAQUE16_LEN; + if ((args->idx - args->begin) + extSz > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_ppc); + } + /* Store extension data info for later processing. */ + args->exts[args->totalCerts].length = extSz; + args->exts[args->totalCerts].buffer = input + args->idx; + args->idx += extSz; + listSz -= extSz + OPAQUE16_LEN; + ret = TLSX_Parse(ssl, args->exts[args->totalCerts].buffer, + args->exts[args->totalCerts].length, certificate, NULL); + if (ret < 0) { + ERROR_OUT(ret, exit_ppc); + } + } + #endif + + args->totalCerts++; + WOLFSSL_MSG("\tPut another cert into chain"); + } /* while (listSz) */ + + args->count = args->totalCerts; + args->certIdx = 0; /* select peer cert (first one) */ + + if (args->count == 0 && ssl->options.mutualAuth && + ssl->options.side == WOLFSSL_SERVER_END) { + ret = NO_PEER_CERT; + DoCertFatalAlert(ssl, ret); + } + + args->dCertInit = 0; + #ifndef WOLFSSL_SMALL_CERT_VERIFY + args->dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap, + DYNAMIC_TYPE_DCERT); + if (args->dCert == NULL) { + ERROR_OUT(MEMORY_E, exit_ppc); + } + XMEMSET(args->dCert, 0, sizeof(DecodedCert)); + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + if (args->count > 0) { + + /* check for trusted peer and get untrustedDepth */ + #if defined(WOLFSSL_TRUST_PEER_CERT) || defined(OPENSSL_EXTRA) + if (args->certIdx == 0) { + #ifdef WOLFSSL_TRUST_PEER_CERT + TrustedPeerCert* tp; + int matchType = WC_MATCH_NAME; + #endif + + ret = ProcessPeerCertParse(ssl, args, CERT_TYPE, NO_VERIFY, + &subjectHash, &alreadySigner); + if (ret != 0) + goto exit_ppc; + + #ifdef OPENSSL_EXTRA + /* Determine untrusted depth */ + if (!alreadySigner && (!args->dCert || + !args->dCertInit || !args->dCert->selfSigned)) { + args->untrustedDepth = 1; + } + #endif + + #ifdef WOLFSSL_TRUST_PEER_CERT + #ifndef NO_SKID + if (args->dCert->extAuthKeyIdSet) + matchType = WC_MATCH_SKID; + #endif + tp = GetTrustedPeer(ssl->ctx->cm, subjectHash, matchType); + WOLFSSL_MSG("Checking for trusted peer cert"); + + if (tp && MatchTrustedPeer(tp, args->dCert)) { + WOLFSSL_MSG("Found matching trusted peer cert"); + args->haveTrustPeer = 1; + } + else if (tp == NULL) { + /* no trusted peer cert */ + WOLFSSL_MSG("No matching trusted peer cert. Checking CAs"); + } + else { + WOLFSSL_MSG("Trusted peer cert did not match!"); + } + if (!args->haveTrustPeer) + #endif + { + /* free cert if not trusted peer */ + FreeDecodedCert(args->dCert); + args->dCertInit = 0; + } + } + #endif /* WOLFSSL_TRUST_PEER_CERT || OPENSSL_EXTRA */ + + /* check certificate up to peer's first */ + /* do not verify chain if trusted peer cert found */ + while (args->count > 1 + #ifdef WOLFSSL_TRUST_PEER_CERT + && !args->haveTrustPeer + #endif /* WOLFSSL_TRUST_PEER_CERT */ + ) { + int skipAddCA = 0; + + /* select last certificate */ + args->certIdx = args->count - 1; + + ret = ProcessPeerCertParse(ssl, args, CERT_TYPE, + !ssl->options.verifyNone ? VERIFY : NO_VERIFY, + &subjectHash, &alreadySigner); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + goto exit_ppc; + #endif + if (ret == 0) { + ret = ProcessPeerCertCheckKey(ssl, args); + } + + if (ret == 0 && args->dCert->isCA == 0) { + WOLFSSL_MSG("Chain cert is not a CA, not adding as one"); + } + else if (ret == 0 && ssl->options.verifyNone) { + WOLFSSL_MSG("Chain cert not verified by option, " + "not adding as CA"); + } + else if (ret == 0) { + #ifdef OPENSSL_EXTRA + if (args->certIdx > args->untrustedDepth) { + args->untrustedDepth = (char)args->certIdx + 1; + } + #endif + + if (alreadySigner) { + WOLFSSL_MSG("Verified CA from chain and already had it"); + } + } + else { + WOLFSSL_MSG("Failed to verify CA from chain"); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = X509_V_ERR_INVALID_CA; + #endif + } + + #if defined(HAVE_OCSP) || defined(HAVE_CRL) + if (ret == 0) { + int doCrlLookup = 1; + #ifdef HAVE_OCSP + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) { + ret = TLSX_CSR2_InitRequests(ssl->extensions, + args->dCert, 0, ssl->heap); + } + else /* skips OCSP and force CRL check */ + #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + if (ssl->ctx->cm->ocspEnabled && + ssl->ctx->cm->ocspCheckAll) { + WOLFSSL_MSG("Doing Non Leaf OCSP check"); + ret = CheckCertOCSP_ex(ssl->ctx->cm->ocsp, + args->dCert, NULL, ssl); + #ifdef WOLFSSL_NONBLOCK_OCSP + if (ret == OCSP_WANT_READ) { + args->lastErr = ret; + goto exit_ppc; + } + #endif + doCrlLookup = (ret == OCSP_CERT_UNKNOWN); + if (ret != 0) { + doCrlLookup = 0; + WOLFSSL_MSG("\tOCSP Lookup not ok"); + } + } + #endif /* HAVE_OCSP */ + + #ifdef HAVE_CRL + if (ret == 0 && doCrlLookup && + ssl->ctx->cm->crlEnabled && + ssl->ctx->cm->crlCheckAll) { + WOLFSSL_MSG("Doing Non Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, args->dCert); + #ifdef WOLFSSL_NONBLOCK_OCSP + if (ret == OCSP_WANT_READ) { + args->lastErr = ret; + goto exit_ppc; + } + #endif + if (ret != 0) { + WOLFSSL_MSG("\tCRL check not ok"); + } + } + #endif /* HAVE_CRL */ + (void)doCrlLookup; + } + #endif /* HAVE_OCSP || HAVE_CRL */ + + /* Do verify callback */ + ret = DoVerifyCallback(ssl->ctx->cm, ssl, ret, args); + + #ifdef WOLFSSL_ALT_CERT_CHAINS + /* For alternate cert chain, its okay for a CA cert to fail + with ASN_NO_SIGNER_E here. The "alternate" certificate + chain mode only requires that the peer certificate + validate to a trusted CA */ + if (ret != 0 && args->dCert->isCA) { + if (ret == ASN_NO_SIGNER_E) { + if (!ssl->options.usingAltCertChain) { + WOLFSSL_MSG("Trying alternate cert chain"); + ssl->options.usingAltCertChain = 1; + } + + ret = 0; /* clear error and continue */ + } + + /* do not add to certificate manager */ + skipAddCA = 1; + } + #endif /* WOLFSSL_ALT_CERT_CHAINS */ + + /* If valid CA then add to Certificate Manager */ + if (ret == 0 && args->dCert->isCA && + !ssl->options.verifyNone && !skipAddCA) { + buffer* cert = &args->certs[args->certIdx]; + + /* Is valid CA */ + #if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS) + /* if using alternate chain, store the cert used */ + if (ssl->options.usingAltCertChain) { + AddSessionCertToChain(&ssl->session.altChain, + cert->buffer, cert->length); + } + #endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */ + if (!alreadySigner) { + DerBuffer* add = NULL; + ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap); + if (ret < 0) + goto exit_ppc; + + XMEMCPY(add->buffer, cert->buffer, cert->length); + + /* CA already verified above in ParseCertRelative */ + WOLFSSL_MSG("Adding CA from chain"); + ret = AddCA(ssl->ctx->cm, &add, WOLFSSL_CHAIN_CA, + NO_VERIFY); + if (ret == WOLFSSL_SUCCESS) { + ret = 0; + } + } + } + + /* Handle error codes */ + if (ret != 0) { + if (!ssl->options.verifyNone) { + DoCertFatalAlert(ssl, ret); + } + ssl->error = ret; /* Report SSL error */ + + if (args->lastErr == 0) { + args->lastErr = ret; /* save error from last time */ + ret = 0; /* reset error */ + } + } + + FreeDecodedCert(args->dCert); + args->dCertInit = 0; + args->count--; + } /* while (count > 0 && !args->haveTrustPeer) */ + } /* if (count > 0) */ + + /* Check for error */ + if (ret != 0) { + goto exit_ppc; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + /* peer's, may not have one if blank client cert sent by TLSv1.2 */ + if (args->count > 0) { + WOLFSSL_MSG("Verifying Peer's cert"); + + /* select peer cert (first one) */ + args->certIdx = 0; + + ret = ProcessPeerCertParse(ssl, args, CERT_TYPE, + !ssl->options.verifyNone ? VERIFY : NO_VERIFY, + &subjectHash, &alreadySigner); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + goto exit_ppc; + #endif + if (ret == 0) { + WOLFSSL_MSG("Verified Peer's cert"); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = X509_V_OK; + #endif + #if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS) + /* if using alternate chain, store the cert used */ + if (ssl->options.usingAltCertChain) { + buffer* cert = &args->certs[args->certIdx]; + AddSessionCertToChain(&ssl->session.altChain, + cert->buffer, cert->length); + } + #endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */ + + /* check if fatal error */ + if (args->verifyErr) { + args->fatal = 1; + if (ret == 0) { + ret = args->lastErr; + } + } + else { + args->fatal = 0; + } + } + else if (ret == ASN_PARSE_E || ret == BUFFER_E) { + WOLFSSL_MSG("Got Peer cert ASN PARSE or BUFFER ERROR"); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + SendAlert(ssl, alert_fatal, bad_certificate); + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + args->fatal = 1; + } + else { + WOLFSSL_MSG("Failed to verify Peer's cert"); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; + #endif + if (ssl->verifyCallback) { + WOLFSSL_MSG( + "\tCallback override available, will continue"); + /* check if fatal error */ + args->fatal = (args->verifyErr) ? 1 : 0; + } + else { + WOLFSSL_MSG("\tNo callback override available, fatal"); + args->fatal = 1; + #ifdef OPENSSL_EXTRA + SendAlert(ssl, alert_fatal, bad_certificate); + #endif + } + } + + #ifdef HAVE_SECURE_RENEGOTIATION + if (args->fatal == 0 && !IsAtLeastTLSv1_3(ssl->version) + && ssl->secure_renegotiation + && ssl->secure_renegotiation->enabled) { + + if (IsEncryptionOn(ssl, 0)) { + /* compare against previous time */ + if (ssl->secure_renegotiation->subject_hash_set) { + if (XMEMCMP(args->dCert->subjectHash, + ssl->secure_renegotiation->subject_hash, + KEYID_SIZE) != 0) { + WOLFSSL_MSG( + "Peer sent different cert during scr, fatal"); + args->fatal = 1; + ret = SCR_DIFFERENT_CERT_E; + } + } + } + + /* cache peer's hash */ + if (args->fatal == 0) { + XMEMCPY(ssl->secure_renegotiation->subject_hash, + args->dCert->subjectHash, KEYID_SIZE); + ssl->secure_renegotiation->subject_hash_set = 1; + } + } + #endif /* HAVE_SECURE_RENEGOTIATION */ + } /* if (count > 0) */ + + /* Check for error */ + if (args->fatal && ret != 0) { + goto exit_ppc; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + if (args->count > 0) { + #if defined(HAVE_OCSP) || defined(HAVE_CRL) + if (args->fatal == 0) { + int doLookup = 1; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST + if (ssl->status_request) { + args->fatal = TLSX_CSR_InitRequest(ssl->extensions, + args->dCert, ssl->heap); + doLookup = 0; + #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) + if (ssl->options.tls1_3) { + TLSX* ext = TLSX_Find(ssl->extensions, + TLSX_STATUS_REQUEST); + if (ext != NULL) { + word32 idx = 0; + CertificateStatusRequest* csr = + (CertificateStatusRequest*)ext->data; + ret = ProcessCSR(ssl, csr->response.buffer, + &idx, csr->response.length); + if (ret < 0) + goto exit_ppc; + } + } + #endif + } + #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) { + args->fatal = TLSX_CSR2_InitRequests(ssl->extensions, + args->dCert, 1, ssl->heap); + doLookup = 0; + } + #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + } + + #ifdef HAVE_OCSP + if (doLookup && ssl->ctx->cm->ocspEnabled) { + WOLFSSL_MSG("Doing Leaf OCSP check"); + ret = CheckCertOCSP_ex(ssl->ctx->cm->ocsp, + args->dCert, NULL, ssl); + #ifdef WOLFSSL_NONBLOCK_OCSP + if (ret == OCSP_WANT_READ) { + goto exit_ppc; + } + #endif + doLookup = (ret == OCSP_CERT_UNKNOWN); + if (ret != 0) { + WOLFSSL_MSG("\tOCSP Lookup not ok"); + args->fatal = 0; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + } + } + #endif /* HAVE_OCSP */ + + #ifdef HAVE_CRL + if (doLookup && ssl->ctx->cm->crlEnabled) { + WOLFSSL_MSG("Doing Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, args->dCert); + #ifdef WOLFSSL_NONBLOCK_OCSP + if (ret == OCSP_WANT_READ) { + goto exit_ppc; + } + #endif + if (ret != 0) { + WOLFSSL_MSG("\tCRL check not ok"); + args->fatal = 0; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + } + } + #endif /* HAVE_CRL */ + (void)doLookup; + } + #endif /* HAVE_OCSP || HAVE_CRL */ + + #ifdef KEEP_PEER_CERT + if (args->fatal == 0) { + int copyRet = 0; + + #ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->enabled) { + /* free old peer cert */ + FreeX509(&ssl->peerCert); + } + #endif + + /* set X509 format for peer cert */ + copyRet = CopyDecodedToX509(&ssl->peerCert, args->dCert); + if (copyRet == MEMORY_E) { + args->fatal = 1; + } + } + #endif /* KEEP_PEER_CERT */ + + #ifndef IGNORE_KEY_EXTENSIONS + #if defined(OPENSSL_EXTRA) + /* when compatibility layer is turned on and no verify is + * set then ignore the certificate key extension */ + if (args->dCert->extKeyUsageSet && + args->dCert->extKeyUsageCrit == 0 && + ssl->options.verifyNone) { + WOLFSSL_MSG("Not verifying certificate key usage"); + } + else + #endif + if (args->dCert->extKeyUsageSet) { + if ((ssl->specs.kea == rsa_kea) && + (ssl->options.side == WOLFSSL_CLIENT_END) && + (args->dCert->extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) { + ret = KEYUSE_ENCIPHER_E; + } + if ((ssl->specs.sig_algo == rsa_sa_algo || + (ssl->specs.sig_algo == ecc_dsa_sa_algo && + !ssl->specs.static_ecdh)) && + (args->dCert->extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { + WOLFSSL_MSG("KeyUse Digital Sig not set"); + ret = KEYUSE_SIGNATURE_E; + } + } + + #if defined(OPENSSL_EXTRA) + /* when compatibility layer is turned on and no verify is + * set then ignore the certificate key extension */ + if (args->dCert->extExtKeyUsageSet && + args->dCert->extExtKeyUsageCrit == 0 && + ssl->options.verifyNone) { + WOLFSSL_MSG("Not verifying certificate ext key usage"); + } + else + #endif + if (args->dCert->extExtKeyUsageSet) { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if ((args->dCert->extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { + WOLFSSL_MSG("ExtKeyUse Server Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + else { + if ((args->dCert->extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { + WOLFSSL_MSG("ExtKeyUse Client Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + } + #endif /* IGNORE_KEY_EXTENSIONS */ + + if (args->fatal) { + ssl->error = ret; + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + SendAlert(ssl, alert_fatal, bad_certificate); + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + goto exit_ppc; + } + + ssl->options.havePeerCert = 1; + + if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) { + #ifndef WOLFSSL_ALLOW_NO_CN_IN_SAN + /* Per RFC 5280 section 4.2.1.6, "Whenever such identities + * are to be bound into a certificate, the subject + * alternative name extension MUST be used." */ + if (args->dCert->altNames) { + if (CheckAltNames(args->dCert, + (char*)ssl->buffers.domainName.buffer) == 0 ) { + WOLFSSL_MSG("DomainName match on alt names failed"); + /* try to get peer key still */ + ret = DOMAIN_NAME_MISMATCH; + } + } + else { + if (MatchDomainName( + args->dCert->subjectCN, + args->dCert->subjectCNLen, + (char*)ssl->buffers.domainName.buffer) == 0) { + WOLFSSL_MSG("DomainName match on common name failed"); + ret = DOMAIN_NAME_MISMATCH; + } + } + #else /* WOLFSSL_ALL_NO_CN_IN_SAN */ + /* Old behavior. */ + if (MatchDomainName(args->dCert->subjectCN, + args->dCert->subjectCNLen, + (char*)ssl->buffers.domainName.buffer) == 0) { + WOLFSSL_MSG("DomainName match on common name failed"); + if (CheckAltNames(args->dCert, + (char*)ssl->buffers.domainName.buffer) == 0 ) { + WOLFSSL_MSG( + "DomainName match on alt names failed too"); + /* try to get peer key still */ + ret = DOMAIN_NAME_MISMATCH; + } + } + #endif /* WOLFSSL_ALL_NO_CN_IN_SAN */ + } + + /* decode peer key */ + switch (args->dCert->keyOID) { + #ifndef NO_RSA + case RSAk: + { + word32 keyIdx = 0; + int keyRet = 0; + + if (ssl->peerRsaKey == NULL) { + keyRet = AllocKey(ssl, DYNAMIC_TYPE_RSA, + (void**)&ssl->peerRsaKey); + } else if (ssl->peerRsaKeyPresent) { + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_RSA, + ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; + } + + if (keyRet != 0 || wc_RsaPublicKeyDecode( + args->dCert->publicKey, &keyIdx, ssl->peerRsaKey, + args->dCert->pubKeySize) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerRsaKeyPresent = 1; + #ifdef WOLFSSL_RENESAS_TSIP_TLS + /* copy encrypted tsip key index into ssl object */ + if (args->dCert->tsip_encRsaKeyIdx) { + if (!ssl->peerTsipEncRsaKeyIndex) { + ssl->peerTsipEncRsaKeyIndex = (byte*)XMALLOC( + TSIP_TLS_ENCPUBKEY_SZ_BY_CERTVRFY, + ssl->heap, DYNAMIC_TYPE_RSA); + if (!ssl->peerTsipEncRsaKeyIndex) { + args->lastErr = MEMORY_E; + goto exit_ppc; + } + } + + XMEMCPY(ssl->peerTsipEncRsaKeyIndex, + args->dCert->tsip_encRsaKeyIdx, + TSIP_TLS_ENCPUBKEY_SZ_BY_CERTVRFY); + } + #endif + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + #ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->buffers.peerRsaKey.buffer) { + XFREE(ssl->buffers.peerRsaKey.buffer, + ssl->heap, DYNAMIC_TYPE_RSA); + ssl->buffers.peerRsaKey.buffer = NULL; + } + #endif + + + ssl->buffers.peerRsaKey.buffer = + (byte*)XMALLOC(args->dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_RSA); + if (ssl->buffers.peerRsaKey.buffer == NULL) { + ret = MEMORY_ERROR; + } + else { + XMEMCPY(ssl->buffers.peerRsaKey.buffer, + args->dCert->publicKey, + args->dCert->pubKeySize); + ssl->buffers.peerRsaKey.length = + args->dCert->pubKeySize; + } + #endif /* NO_RSA */ + #endif /* HAVE_PK_CALLBACKS */ + } + + /* check size of peer RSA key */ + if (ret == 0 && ssl->peerRsaKeyPresent && + !ssl->options.verifyNone && + wc_RsaEncryptSize(ssl->peerRsaKey) + < ssl->options.minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Peer RSA key is too small"); + } + break; + } + #endif /* NO_RSA */ + #ifdef HAVE_NTRU + case NTRUk: + { + if (args->dCert->pubKeySize > sizeof(ssl->peerNtruKey)) { + ret = PEER_KEY_ERROR; + } + else { + XMEMCPY(ssl->peerNtruKey, args->dCert->publicKey, + args->dCert->pubKeySize); + ssl->peerNtruKeyLen = + (word16)args->dCert->pubKeySize; + ssl->peerNtruKeyPresent = 1; + } + break; + } + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ECDSAk: + { + int keyRet = 0; + word32 idx = 0; + + if (ssl->peerEccDsaKey == NULL) { + /* alloc/init on demand */ + keyRet = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccDsaKey); + } else if (ssl->peerEccDsaKeyPresent) { + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + + if (keyRet != 0 || + wc_EccPublicKeyDecode(args->dCert->publicKey, &idx, + ssl->peerEccDsaKey, + args->dCert->pubKeySize) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerEccDsaKeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEccDsaKey.buffer = + (byte*)XMALLOC(args->dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_ECC); + if (ssl->buffers.peerEccDsaKey.buffer == NULL) { + ERROR_OUT(MEMORY_ERROR, exit_ppc); + } + else { + XMEMCPY(ssl->buffers.peerEccDsaKey.buffer, + args->dCert->publicKey, + args->dCert->pubKeySize); + ssl->buffers.peerEccDsaKey.length = + args->dCert->pubKeySize; + } + #endif /* HAVE_PK_CALLBACKS */ + } + + /* check size of peer ECC key */ + if (ret == 0 && ssl->peerEccDsaKeyPresent && + !ssl->options.verifyNone && + wc_ecc_size(ssl->peerEccDsaKey) + < ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Peer ECC key is too small"); + } + break; + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + { + int keyRet = 0; + if (ssl->peerEd25519Key == NULL) { + /* alloc/init on demand */ + keyRet = AllocKey(ssl, DYNAMIC_TYPE_ED25519, + (void**)&ssl->peerEd25519Key); + } else if (ssl->peerEd25519KeyPresent) { + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_ED25519, + ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + } + + if (keyRet != 0 || + wc_ed25519_import_public(args->dCert->publicKey, + args->dCert->pubKeySize, + ssl->peerEd25519Key) + != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerEd25519KeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEd25519Key.buffer = + (byte*)XMALLOC(args->dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_ED25519); + if (ssl->buffers.peerEd25519Key.buffer == NULL) { + ERROR_OUT(MEMORY_ERROR, exit_ppc); + } + else { + XMEMCPY(ssl->buffers.peerEd25519Key.buffer, + args->dCert->publicKey, + args->dCert->pubKeySize); + ssl->buffers.peerEd25519Key.length = + args->dCert->pubKeySize; + } + #endif /*HAVE_PK_CALLBACKS */ + } + + /* check size of peer ECC key */ + if (ret == 0 && ssl->peerEd25519KeyPresent && + !ssl->options.verifyNone && + ED25519_KEY_SIZE < ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Peer ECC key is too small"); + } + break; + } + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + { + int keyRet = 0; + if (ssl->peerEd448Key == NULL) { + /* alloc/init on demand */ + keyRet = AllocKey(ssl, DYNAMIC_TYPE_ED448, + (void**)&ssl->peerEd448Key); + } else if (ssl->peerEd448KeyPresent) { + keyRet = ReuseKey(ssl, DYNAMIC_TYPE_ED448, + ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; + } + + if (keyRet != 0 || + wc_ed448_import_public(args->dCert->publicKey, + args->dCert->pubKeySize, + ssl->peerEd448Key) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerEd448KeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEd448Key.buffer = + (byte*)XMALLOC(args->dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_ED448); + if (ssl->buffers.peerEd448Key.buffer == NULL) { + ERROR_OUT(MEMORY_ERROR, exit_ppc); + } + else { + XMEMCPY(ssl->buffers.peerEd448Key.buffer, + args->dCert->publicKey, + args->dCert->pubKeySize); + ssl->buffers.peerEd448Key.length = + args->dCert->pubKeySize; + } + #endif /*HAVE_PK_CALLBACKS */ + } + + /* check size of peer ECC key */ + if (ret == 0 && ssl->peerEd448KeyPresent && + !ssl->options.verifyNone && + ED448_KEY_SIZE < ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Peer ECC key is too small"); + } + break; + } + #endif /* HAVE_ED448 */ + default: + break; + } + + /* args->dCert free'd in function cleanup after callback */ + } /* if (count > 0) */ + + /* Check for error */ + if (args->fatal && ret != 0) { + goto exit_ppc; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + /* load last error */ + if (args->lastErr != 0 && ret == 0) { + ret = args->lastErr; + } + + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + if (args->untrustedDepth > ssl->options.verifyDepth) { + ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG; + ret = MAX_CHAIN_ERROR; + } + #endif + + /* Do verify callback */ + ret = DoVerifyCallback(ssl->ctx->cm, ssl, ret, args); + + if (ssl->options.verifyNone && + (ret == CRL_MISSING || ret == CRL_CERT_REVOKED)) { + WOLFSSL_MSG("Ignoring CRL problem based on verify setting"); + ret = ssl->error = 0; + } + + if (ret != 0) { + if (!ssl->options.verifyNone) { + DoCertFatalAlert(ssl, ret); + } + ssl->error = ret; /* Report SSL error */ + } + + if (ret == 0 && ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.serverState = SERVER_CERT_COMPLETE; + } + + if (IsEncryptionOn(ssl, 0)) { + args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + args->idx += MacSize(ssl); + #endif + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + /* Set final index */ + *inOutIdx = args->idx; + + break; + } + default: + ret = INPUT_CASE_ERROR; + break; + } /* switch(ssl->options.asyncState) */ + +exit_ppc: + + WOLFSSL_LEAVE("ProcessPeerCerts", ret); + + +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP) + if (ret == WC_PENDING_E || ret == OCSP_WANT_READ) { + /* Mark message as not received so it can process again */ + ssl->msgsReceived.got_certificate = 0; + + return ret; + } +#endif /* WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP */ + + FreeProcPeerCertArgs(ssl, args); + +#if defined(WOLFSSL_ASYNC_CRYPT) +#elif defined(WOLFSSL_NONBLOCK_OCSP) + XFREE(args, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + ssl->nonblockarg = NULL; +#elif defined(WOLFSSL_SMALL_STACK) + XFREE(args, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + FreeKeyExchange(ssl); + + return ret; +} +#endif + +#ifndef WOLFSSL_NO_TLS12 +#if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) + +/* handle processing of certificate (11) */ +static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 size) +{ + int ret; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_DO); + WOLFSSL_ENTER("DoCertificate"); + +#ifdef SESSION_CERTS + /* Reset the session cert chain count in case the session resume failed. */ + ssl->session.chain.count = 0; + #ifdef WOLFSSL_ALT_CERT_CHAINS + ssl->session.altChain.count = 0; + #endif +#endif /* SESSION_CERTS */ + + ret = ProcessPeerCerts(ssl, input, inOutIdx, size); +#ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_ERROR || ret == ASN_PARSE_E) + SendAlert(ssl, alert_fatal, decode_error); +#endif + +#ifdef OPENSSL_EXTRA + ssl->options.serverState = SERVER_CERT_COMPLETE; +#endif + + WOLFSSL_LEAVE("DoCertificate", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_DO); + + return ret; +} + +/* handle processing of certificate_status (22) */ +static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 size) +{ + int ret = 0; + byte status_type; + word32 status_length; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_STATUS_DO); + WOLFSSL_ENTER("DoCertificateStatus"); + + if (size < ENUM_LEN + OPAQUE24_LEN) + return BUFFER_ERROR; + + status_type = input[(*inOutIdx)++]; + + c24to32(input + *inOutIdx, &status_length); + *inOutIdx += OPAQUE24_LEN; + + if (size != ENUM_LEN + OPAQUE24_LEN + status_length) + return BUFFER_ERROR; + + switch (status_type) { + + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + + /* WOLFSSL_CSR_OCSP overlaps with WOLFSSL_CSR2_OCSP */ + case WOLFSSL_CSR2_OCSP: + ret = ProcessCSR(ssl, input, inOutIdx, status_length); + break; + + #endif + + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + + case WOLFSSL_CSR2_OCSP_MULTI: { + OcspRequest* request; + word32 list_length = status_length; + byte idx = 0; + + #ifdef WOLFSSL_SMALL_STACK + CertStatus* status; + OcspResponse* response; + #else + CertStatus status[1]; + OcspResponse response[1]; + #endif + + do { + if (ssl->status_request_v2) { + ssl->status_request_v2 = 0; + break; + } + + return BUFFER_ERROR; + } while(0); + + #ifdef WOLFSSL_SMALL_STACK + status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap, + DYNAMIC_TYPE_OCSP_STATUS); + response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap, + DYNAMIC_TYPE_OCSP_REQUEST); + + if (status == NULL || response == NULL) { + if (status) + XFREE(status, ssl->heap, DYNAMIC_TYPE_OCSP_STATUS); + if (response) + XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + + return MEMORY_ERROR; + } + #endif + + while (list_length && ret == 0) { + if (OPAQUE24_LEN > list_length) { + ret = BUFFER_ERROR; + break; + } + + c24to32(input + *inOutIdx, &status_length); + *inOutIdx += OPAQUE24_LEN; + list_length -= OPAQUE24_LEN; + + if (status_length > list_length) { + ret = BUFFER_ERROR; + break; + } + + if (status_length) { + InitOcspResponse(response, status, input +*inOutIdx, + status_length); + + if ((OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, + 0) != 0) + || (response->responseStatus != OCSP_SUCCESSFUL) + || (response->status->status != CERT_GOOD)) + ret = BAD_CERTIFICATE_STATUS_ERROR; + + while (ret == 0) { + request = (OcspRequest*)TLSX_CSR2_GetRequest( + ssl->extensions, status_type, idx++); + + if (request == NULL) + ret = BAD_CERTIFICATE_STATUS_ERROR; + else if (CompareOcspReqResp(request, response) == 0) + break; + else if (idx == 1) /* server cert must be OK */ + ret = BAD_CERTIFICATE_STATUS_ERROR; + } + + *inOutIdx += status_length; + list_length -= status_length; + } + } + + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + ssl->status_request_v2 = 0; + #endif + + #ifdef WOLFSSL_SMALL_STACK + XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS); + XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + #endif + + } + break; + + #endif + + default: + ret = BUFFER_ERROR; + } + + if (ret != 0) + SendAlert(ssl, alert_fatal, bad_certificate_status_response); + + if (IsEncryptionOn(ssl, 0)) { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > size) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + if (*inOutIdx + ssl->keys.padSz > size) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz; + } + } + + WOLFSSL_LEAVE("DoCertificateStatus", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_STATUS_DO); + + return ret; +} + +#endif + +#endif /* !WOLFSSL_NO_TLS12 */ + +#endif /* !NO_CERTS */ + +#ifndef WOLFSSL_NO_TLS12 + +static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz) +{ + (void)input; + + WOLFSSL_START(WC_FUNC_HELLO_REQUEST_DO); + WOLFSSL_ENTER("DoHelloRequest"); + + if (size) /* must be 0 */ + return BUFFER_ERROR; + + if (IsEncryptionOn(ssl, 0)) { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + /* access beyond input + size should be checked against totalSz */ + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; + + *inOutIdx += ssl->keys.padSz; + } + } + + if (ssl->options.side == WOLFSSL_SERVER_END) { + SendAlert(ssl, alert_fatal, unexpected_message); /* try */ + return FATAL_ERROR; + } +#ifdef HAVE_SECURE_RENEGOTIATION + else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) { + ssl->secure_renegotiation->startScr = 1; + WOLFSSL_LEAVE("DoHelloRequest", 0); + WOLFSSL_END(WC_FUNC_HELLO_REQUEST_DO); + return 0; + } +#endif + else { + return SendAlert(ssl, alert_warning, no_renegotiation); + } +} + + +int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, + word32 totalSz, int sniff) +{ + word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ); + + WOLFSSL_START(WC_FUNC_FINISHED_DO); + WOLFSSL_ENTER("DoFinished"); + + if (finishedSz != size) + return BUFFER_ERROR; + + /* check against totalSz */ + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + if (*inOutIdx + size + ssl->keys.padSz + MacSize(ssl) > totalSz) + return BUFFER_E; + } + else + #endif + { + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return BUFFER_E; + } + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); + #endif + + if (sniff == NO_SNIFF) { + if (XMEMCMP(input + *inOutIdx, &ssl->hsHashes->verifyHashes,size) != 0){ + WOLFSSL_MSG("Verify finished error on hashes"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, decrypt_error); + #endif + return VERIFY_FINISHED_ERROR; + } + } + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation) { + /* save peer's state */ + if (ssl->options.side == WOLFSSL_CLIENT_END) + XMEMCPY(ssl->secure_renegotiation->server_verify_data, + input + *inOutIdx, TLS_FINISHED_SZ); + else + XMEMCPY(ssl->secure_renegotiation->client_verify_data, + input + *inOutIdx, TLS_FINISHED_SZ); + ssl->secure_renegotiation->verifySet = 1; + } +#endif + + /* force input exhaustion at ProcessReply consuming padSz */ + *inOutIdx += size + ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + *inOutIdx += MacSize(ssl); +#endif + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; +#ifdef OPENSSL_EXTRA + ssl->cbmode = SSL_CB_MODE_WRITE; + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; +#endif + if (!ssl->options.resuming) { +#ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS); + } +#endif + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } + else { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; +#ifdef OPENSSL_EXTRA + ssl->cbmode = SSL_CB_MODE_READ; + ssl->options.serverState = SERVER_FINISHED_COMPLETE; +#endif + if (ssl->options.resuming) { +#ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_ACCEPT_LOOP, SSL_SUCCESS); + } +#endif + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + DtlsMsgPoolReset(ssl); + } +#endif + + WOLFSSL_LEAVE("DoFinished", 0); + WOLFSSL_END(WC_FUNC_FINISHED_DO); + + return 0; +} + + +/* Make sure no duplicates, no fast forward, or other problems; 0 on success */ +static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) +{ + /* verify not a duplicate, mark received, check state */ + switch (type) { + +#ifndef NO_WOLFSSL_CLIENT + case hello_request: + if (ssl->msgsReceived.got_hello_request) { + WOLFSSL_MSG("Duplicate HelloRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_hello_request = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_SERVER + case client_hello: + if (ssl->msgsReceived.got_client_hello) { + WOLFSSL_MSG("Duplicate ClientHello received"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, unexpected_message); + #endif + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_client_hello = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case server_hello: + if (ssl->msgsReceived.got_server_hello) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case hello_verify_request: + if (ssl->msgsReceived.got_hello_verify_request) { + WOLFSSL_MSG("Duplicate HelloVerifyRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_hello_verify_request = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case session_ticket: + if (ssl->msgsReceived.got_session_ticket) { + WOLFSSL_MSG("Duplicate SessionTicket received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_session_ticket = 1; + + break; +#endif + + case certificate: + if (ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("Duplicate Certificate received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate = 1; + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if ( ssl->msgsReceived.got_server_hello == 0) { + WOLFSSL_MSG("No ServerHello before Cert"); + return OUT_OF_ORDER_E; + } + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if ( ssl->msgsReceived.got_client_hello == 0) { + WOLFSSL_MSG("No ClientHello before Cert"); + return OUT_OF_ORDER_E; + } + } +#endif + break; + +#ifndef NO_WOLFSSL_CLIENT + case certificate_status: + if (ssl->msgsReceived.got_certificate_status) { + WOLFSSL_MSG("Duplicate CertificateSatatus received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate_status = 1; + + if (ssl->msgsReceived.got_certificate == 0) { + WOLFSSL_MSG("No Certificate before CertificateStatus"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_server_key_exchange != 0) { + WOLFSSL_MSG("CertificateStatus after ServerKeyExchange"); + return OUT_OF_ORDER_E; + } + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case server_key_exchange: + if (ssl->msgsReceived.got_server_key_exchange) { + WOLFSSL_MSG("Duplicate ServerKeyExchange received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_key_exchange = 1; + + if (ssl->msgsReceived.got_server_hello == 0) { + WOLFSSL_MSG("No ServerHello before ServerKeyExchange"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_certificate_status == 0) { +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + if (ssl->status_request) { + int ret; + + WOLFSSL_MSG("No CertificateStatus before ServerKeyExchange"); + if ((ret = TLSX_CSR_ForceRequest(ssl)) != 0) + return ret; + } +#endif +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) { + int ret; + + WOLFSSL_MSG("No CertificateStatus before ServerKeyExchange"); + if ((ret = TLSX_CSR2_ForceRequest(ssl)) != 0) + return ret; + } +#endif + } + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case certificate_request: + if (ssl->msgsReceived.got_certificate_request) { + WOLFSSL_MSG("Duplicate CertificateRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate_request = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case server_hello_done: + if (ssl->msgsReceived.got_server_hello_done) { + WOLFSSL_MSG("Duplicate ServerHelloDone received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello_done = 1; + + if (ssl->msgsReceived.got_certificate == 0) { + if (ssl->specs.kea == psk_kea || + ssl->specs.kea == dhe_psk_kea || + ssl->specs.kea == ecdhe_psk_kea || + ssl->options.usingAnon_cipher) { + WOLFSSL_MSG("No Cert required"); + } else { + WOLFSSL_MSG("No Certificate before ServerHelloDone"); + return OUT_OF_ORDER_E; + } + } + if (ssl->msgsReceived.got_server_key_exchange == 0) { + int pskNoServerHint = 0; /* not required in this case */ + + #ifndef NO_PSK + if (ssl->specs.kea == psk_kea && + ssl->arrays != NULL && + ssl->arrays->server_hint[0] == 0) + pskNoServerHint = 1; + #endif + if (ssl->specs.static_ecdh == 1 || + ssl->specs.kea == rsa_kea || + ssl->specs.kea == ntru_kea || + pskNoServerHint) { + WOLFSSL_MSG("No KeyExchange required"); + } else { + WOLFSSL_MSG("No ServerKeyExchange before ServerDone"); + return OUT_OF_ORDER_E; + } + } + break; +#endif + +#ifndef NO_WOLFSSL_SERVER + case certificate_verify: + if (ssl->msgsReceived.got_certificate_verify) { + WOLFSSL_MSG("Duplicate CertificateVerify received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate_verify = 1; + + if ( ssl->msgsReceived.got_certificate == 0) { + WOLFSSL_MSG("No Cert before CertVerify"); + return OUT_OF_ORDER_E; + } + break; +#endif + +#ifndef NO_WOLFSSL_SERVER + case client_key_exchange: + if (ssl->msgsReceived.got_client_key_exchange) { + WOLFSSL_MSG("Duplicate ClientKeyExchange received"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, unexpected_message); + #endif + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_client_key_exchange = 1; + + if (ssl->msgsReceived.got_client_hello == 0) { + WOLFSSL_MSG("No ClientHello before ClientKeyExchange"); + return OUT_OF_ORDER_E; + } + break; +#endif + + case finished: + if (ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("Duplicate Finished received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_finished = 1; + + if (ssl->msgsReceived.got_change_cipher == 0) { + WOLFSSL_MSG("Finished received before ChangeCipher"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, unexpected_message); + #endif + return NO_CHANGE_CIPHER_E; + } + break; + + case change_cipher_hs: + if (ssl->msgsReceived.got_change_cipher) { + WOLFSSL_MSG("Duplicate ChangeCipher received"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, unexpected_message); + #endif + return DUPLICATE_MSG_E; + } + /* DTLS is going to ignore the CCS message if the client key + * exchange message wasn't received yet. */ + if (!ssl->options.dtls) + ssl->msgsReceived.got_change_cipher = 1; + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->options.resuming) { + if (ssl->msgsReceived.got_server_hello_done == 0) { + WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); + return OUT_OF_ORDER_E; + } + } + else { + if (ssl->msgsReceived.got_server_hello == 0) { + WOLFSSL_MSG("No ServerHello before ChangeCipher on Resume"); + return OUT_OF_ORDER_E; + } + } + #ifdef HAVE_SESSION_TICKET + if (ssl->expect_session_ticket) { + WOLFSSL_MSG("Expected session ticket missing"); + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + return OUT_OF_ORDER_E; + #endif + return SESSION_TICKET_EXPECT_E; + } + #endif + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (!ssl->options.resuming && + ssl->msgsReceived.got_client_key_exchange == 0) { + WOLFSSL_MSG("No ClientKeyExchange before ChangeCipher"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, unexpected_message); + #endif + return OUT_OF_ORDER_E; + } + #ifndef NO_CERTS + if (ssl->options.verifyPeer && + ssl->options.havePeerCert) { + + if (!ssl->options.havePeerVerify) { + WOLFSSL_MSG("client didn't send cert verify"); + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + return OUT_OF_ORDER_E; + #endif + return NO_PEER_VERIFY; + } + } + #endif + } +#endif + if (ssl->options.dtls) + ssl->msgsReceived.got_change_cipher = 1; + break; + + default: + WOLFSSL_MSG("Unknown message type"); + return SANITY_MSG_E; + } + + return 0; +} + + +static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, + byte type, word32 size, word32 totalSz) +{ + int ret = 0; + word32 expectedIdx; + + WOLFSSL_ENTER("DoHandShakeMsgType"); + +#ifdef WOLFSSL_TLS13 + if (type == hello_retry_request) { + return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } +#endif + + /* make sure can read the message */ + if (*inOutIdx + size > totalSz) { + WOLFSSL_MSG("Incomplete Data"); + return INCOMPLETE_DATA; + } + + expectedIdx = *inOutIdx + size + + (ssl->keys.encryptionOn ? ssl->keys.padSz : 0); +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead && ssl->keys.encryptionOn) + expectedIdx += MacSize(ssl); +#endif + +#if !defined(WOLFSSL_NO_SERVER) && \ + defined(HAVE_SECURE_RENEGOTIATION) && \ + defined(HAVE_SERVER_RENEGOTIATION_INFO) + if (ssl->options.handShakeDone && type == client_hello && + ssl->secure_renegotiation && + ssl->secure_renegotiation->enabled) + { + WOLFSSL_MSG("Reset handshake state"); + XMEMSET(&ssl->msgsReceived, 0, sizeof(MsgsReceived)); + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; + ssl->options.handShakeState = NULL_STATE; + ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; + + ret = InitHandshakeHashes(ssl); + if (ret != 0) + return ret; + } +#endif + + /* sanity check msg received */ + if ( (ret = SanityCheckMsgReceived(ssl, type)) != 0) { + WOLFSSL_MSG("Sanity Check on handshake message type received failed"); + return ret; + } + +#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + /* add name later, add on record and handshake header part back on */ + if (ssl->toInfoOn) { + int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + AddPacketInfo(ssl, 0, handshake, input + *inOutIdx - add, + size + add, READ_PROTO, ssl->heap); + #ifdef WOLFSSL_CALLBACKS + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + #endif + } +#endif + + if (ssl->options.handShakeState == HANDSHAKE_DONE && type != hello_request){ + WOLFSSL_MSG("HandShake message after handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls == 0 && + ssl->options.serverState == NULL_STATE && type != server_hello) { + WOLFSSL_MSG("First server message not server hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls && + type == server_hello_done && + ssl->options.serverState < SERVER_HELLO_COMPLETE) { + WOLFSSL_MSG("Server hello done received before server hello in DTLS"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.clientState == NULL_STATE && type != client_hello) { + WOLFSSL_MSG("First client message not client hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + /* above checks handshake state */ + /* hello_request not hashed */ + /* Also, skip hashing the client_hello message here for DTLS. It will be + * hashed later if the DTLS cookie is correct. */ + if (type != hello_request && + !(IsDtlsNotSctpMode(ssl) && type == client_hello) + #ifdef WOLFSSL_ASYNC_CRYPT + && ssl->error != WC_PENDING_E + #endif + #ifdef WOLFSSL_NONBLOCK_OCSP + && ssl->error != OCSP_WANT_READ + #endif + ) { + ret = HashInput(ssl, input + *inOutIdx, size); + if (ret != 0) { + WOLFSSL_MSG("Incomplete handshake hashes"); + return ret; + } + } + +#ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL){ + ssl->cbmode = SSL_CB_MODE_READ; + ssl->cbtype = type; + ssl->CBIS(ssl, SSL_CB_ACCEPT_LOOP, SSL_SUCCESS); + } +#endif + + switch (type) { + + case hello_request: + WOLFSSL_MSG("processing hello request"); + ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz); + break; + +#ifndef NO_WOLFSSL_CLIENT + case hello_verify_request: + WOLFSSL_MSG("processing hello verify request"); + ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size); + break; + + case server_hello: + WOLFSSL_MSG("processing server hello"); + ret = DoServerHello(ssl, input, inOutIdx, size); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) || + IsAtLeastTLSv1_3(ssl->version)) { + + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP) + if (ret != WC_PENDING_E && ret != OCSP_WANT_READ) + #endif + { + ssl->options.cacheMessages = 0; + if (ssl->hsHashes->messages != NULL) { + XFREE(ssl->hsHashes->messages, ssl->heap, + DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } + } + } + #endif + break; + +#ifndef NO_CERTS + case certificate_request: + WOLFSSL_MSG("processing certificate request"); + ret = DoCertificateRequest(ssl, input, inOutIdx, size); + break; +#endif + + case server_key_exchange: + WOLFSSL_MSG("processing server key exchange"); + ret = DoServerKeyExchange(ssl, input, inOutIdx, size); + break; + +#ifdef HAVE_SESSION_TICKET + case session_ticket: + WOLFSSL_MSG("processing session ticket"); + ret = DoSessionTicket(ssl, input, inOutIdx, size); + break; +#endif /* HAVE_SESSION_TICKET */ +#endif + +#if !defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \ + !defined(WOLFSSL_NO_CLIENT_AUTH)) + case certificate: + WOLFSSL_MSG("processing certificate"); + ret = DoCertificate(ssl, input, inOutIdx, size); + break; + + case certificate_status: + WOLFSSL_MSG("processing certificate status"); + ret = DoCertificateStatus(ssl, input, inOutIdx, size); + break; +#endif + + case server_hello_done: + WOLFSSL_MSG("processing server hello done"); + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "ServerHelloDone"); + if (ssl->toInfoOn) + AddLateName("ServerHelloDone", &ssl->timeoutInfo); + #endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + if (IsEncryptionOn(ssl, 0)) { + *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + *inOutIdx += MacSize(ssl); + #endif + } + if (ssl->options.resuming) { + WOLFSSL_MSG("Not resuming as thought"); + ssl->options.resuming = 0; + } + break; + + case finished: + WOLFSSL_MSG("processing finished"); + ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); + break; + +#ifndef NO_WOLFSSL_SERVER + case client_hello: + WOLFSSL_MSG("processing client hello"); + ret = DoClientHello(ssl, input, inOutIdx, size); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + if (ssl->options.resuming || !ssl->options.verifyPeer || \ + !IsAtLeastTLSv1_2(ssl) || IsAtLeastTLSv1_3(ssl->version)) { + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP) + if (ret != WC_PENDING_E && ret != OCSP_WANT_READ) + #endif + { + ssl->options.cacheMessages = 0; + if (ssl->hsHashes->messages != NULL) { + XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } + } + } + #endif + if (IsEncryptionOn(ssl, 0)) { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + /* access beyond input + size should be checked against totalSz + */ + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; + + *inOutIdx += ssl->keys.padSz; + } + } + break; + + case client_key_exchange: + WOLFSSL_MSG("processing client key exchange"); + ret = DoClientKeyExchange(ssl, input, inOutIdx, size); + break; + +#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448)) && !defined(WOLFSSL_NO_CLIENT_AUTH) + case certificate_verify: + WOLFSSL_MSG("processing certificate verify"); + ret = DoCertificateVerify(ssl, input, inOutIdx, size); + break; +#endif /* (!NO_RSA || ECC || ED25519 || ED448) && !WOLFSSL_NO_CLIENT_AUTH */ + +#endif /* !NO_WOLFSSL_SERVER */ + + default: + WOLFSSL_MSG("Unknown handshake message type"); + ret = UNKNOWN_HANDSHAKE_TYPE; + break; + } + if (ret == 0 && expectedIdx != *inOutIdx) { + WOLFSSL_MSG("Extra data in handshake message"); + if (!ssl->options.dtls) + SendAlert(ssl, alert_fatal, decode_error); + ret = DECODE_E; + } + + if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP) + /* do not shrink input for async or non-block */ + && ssl->error != WC_PENDING_E && ssl->error != OCSP_WANT_READ + #endif + ) { + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + } + +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP) + /* if async, offset index so this msg will be processed again */ + if ((ret == WC_PENDING_E || ret == OCSP_WANT_READ) && *inOutIdx > 0) { + *inOutIdx -= HANDSHAKE_HEADER_SZ; + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + *inOutIdx -= DTLS_HANDSHAKE_EXTRA; + } + #endif + } + + /* make sure async error is cleared */ + if (ret == 0 && (ssl->error == WC_PENDING_E || ssl->error == OCSP_WANT_READ)) { + ssl->error = 0; + } +#endif /* WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP */ + + WOLFSSL_LEAVE("DoHandShakeMsgType()", ret); + return ret; +} + + +static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret = 0; + word32 inputLength; + + WOLFSSL_ENTER("DoHandShakeMsg()"); + + if (ssl->arrays == NULL) { + byte type; + word32 size; + + if (GetHandShakeHeader(ssl,input,inOutIdx,&type, &size, totalSz) != 0) + return PARSE_ERROR; + + ssl->options.handShakeState = type; + + return DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + } + + inputLength = ssl->buffers.inputBuffer.length - *inOutIdx; + + /* If there is a pending fragmented handshake message, + * pending message size will be non-zero. */ + if (ssl->arrays->pendingMsgSz == 0) { + byte type; + word32 size; + + if (GetHandShakeHeader(ssl,input, inOutIdx, &type, &size, totalSz) != 0) + return PARSE_ERROR; + + /* Cap the maximum size of a handshake message to something reasonable. + * By default is the maximum size of a certificate message assuming + * nine 2048-bit RSA certificates in the chain. */ + if (size > MAX_HANDSHAKE_SZ) { + WOLFSSL_MSG("Handshake message too large"); + return HANDSHAKE_SIZE_ERROR; + } + + /* size is the size of the certificate message payload */ + if (inputLength - HANDSHAKE_HEADER_SZ < size) { + ssl->arrays->pendingMsgType = type; + ssl->arrays->pendingMsgSz = size + HANDSHAKE_HEADER_SZ; + ssl->arrays->pendingMsg = (byte*)XMALLOC(size + HANDSHAKE_HEADER_SZ, + ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays->pendingMsg == NULL) + return MEMORY_E; + XMEMCPY(ssl->arrays->pendingMsg, + input + *inOutIdx - HANDSHAKE_HEADER_SZ, + inputLength); + ssl->arrays->pendingMsgOffset = inputLength; + *inOutIdx += inputLength - HANDSHAKE_HEADER_SZ; + return 0; + } + + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + } + else { + word32 pendSz = + ssl->arrays->pendingMsgSz - ssl->arrays->pendingMsgOffset; + + /* Catch the case where there may be the remainder of a fragmented + * handshake message and the next handshake message in the same + * record. */ + if (inputLength > pendSz) + inputLength = pendSz; + + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, + input + *inOutIdx, inputLength); + ssl->arrays->pendingMsgOffset += inputLength; + *inOutIdx += inputLength; + + if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz) + { + word32 idx = HANDSHAKE_HEADER_SZ; + ret = DoHandShakeMsgType(ssl, + ssl->arrays->pendingMsg, + &idx, ssl->arrays->pendingMsgType, + ssl->arrays->pendingMsgSz - idx, + ssl->arrays->pendingMsgSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + /* setup to process fragment again */ + ssl->arrays->pendingMsgOffset -= inputLength; + *inOutIdx -= inputLength; + } + else + #endif + { + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + ssl->arrays->pendingMsgSz = 0; + } + } + } + + WOLFSSL_LEAVE("DoHandShakeMsg()", ret); + return ret; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef WOLFSSL_DTLS + +static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl) +{ + word32* window; + word16 cur_hi, next_hi; + word32 cur_lo, next_lo, diff; + int curLT; + WOLFSSL_DTLS_PEERSEQ* peerSeq = NULL; + + if (!ssl->options.haveMcast) + peerSeq = ssl->keys.peerSeq; + else { +#ifdef WOLFSSL_MULTICAST + WOLFSSL_DTLS_PEERSEQ* p; + int i; + + for (i = 0, p = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, p++) { + + if (p->peerId == ssl->keys.curPeerId) { + peerSeq = p; + break; + } + } +#endif + } + + if (peerSeq == NULL) { + WOLFSSL_MSG("Could not find peer sequence"); + return 0; + } + + if (ssl->keys.curEpoch == peerSeq->nextEpoch) { + next_hi = peerSeq->nextSeq_hi; + next_lo = peerSeq->nextSeq_lo; + window = peerSeq->window; + } + else if (ssl->keys.curEpoch == peerSeq->nextEpoch - 1) { + next_hi = peerSeq->prevSeq_hi; + next_lo = peerSeq->prevSeq_lo; + window = peerSeq->prevWindow; + } + else { + return 0; + } + + cur_hi = ssl->keys.curSeq_hi; + cur_lo = ssl->keys.curSeq_lo; + + /* If the difference between next and cur is > 2^32, way outside window. */ + if ((cur_hi > next_hi + 1) || (next_hi > cur_hi + 1)) { + WOLFSSL_MSG("Current record from way too far in the future."); + return 0; + } + + if (cur_hi == next_hi) { + curLT = cur_lo < next_lo; + diff = curLT ? next_lo - cur_lo : cur_lo - next_lo; + } + else { + curLT = cur_hi < next_hi; + diff = curLT ? cur_lo - next_lo : next_lo - cur_lo; + } + + /* Check to see that the next value is greater than the number of messages + * trackable in the window, and that the difference between the next + * expected sequence number and the received sequence number is inside the + * window. */ + if ((next_hi || next_lo > DTLS_SEQ_BITS) && + curLT && (diff > DTLS_SEQ_BITS)) { + + WOLFSSL_MSG("Current record sequence number from the past."); + return 0; + } +#ifndef WOLFSSL_DTLS_ALLOW_FUTURE + else if (!curLT && (diff > DTLS_SEQ_BITS)) { + WOLFSSL_MSG("Rejecting message too far into the future."); + return 0; + } +#endif + else if (curLT) { + word32 idx = diff / DTLS_WORD_BITS; + word32 newDiff = diff % DTLS_WORD_BITS; + + /* verify idx is valid for window array */ + if (idx >= WOLFSSL_DTLS_WINDOW_WORDS) { + WOLFSSL_MSG("Invalid DTLS windows index"); + return 0; + } + + if (window[idx] & (1 << newDiff)) { + WOLFSSL_MSG("Current record sequence number already received."); + return 0; + } + } + + return 1; +} + + +#ifdef WOLFSSL_MULTICAST +static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 max) +{ + word32 newCur = 0; + + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < max) + newCur = max; + + return newCur; +} +#endif /* WOLFSSL_MULTICAST */ + + +static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl) +{ + word32* window; + word32* next_lo; + word16* next_hi; + int curLT; + word32 cur_lo, diff; + word16 cur_hi; + WOLFSSL_DTLS_PEERSEQ* peerSeq = ssl->keys.peerSeq; + + cur_hi = ssl->keys.curSeq_hi; + cur_lo = ssl->keys.curSeq_lo; + +#ifdef WOLFSSL_MULTICAST + if (ssl->options.haveMcast) { + WOLFSSL_DTLS_PEERSEQ* p; + int i; + + peerSeq = NULL; + for (i = 0, p = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, p++) { + + if (p->peerId == ssl->keys.curPeerId) { + peerSeq = p; + break; + } + } + + if (peerSeq == NULL) { + WOLFSSL_MSG("Couldn't find that peer ID to update window."); + return 0; + } + + if (p->highwaterMark && cur_lo >= p->highwaterMark) { + int cbError = 0; + + if (ssl->ctx->mcastHwCb) + cbError = ssl->ctx->mcastHwCb(p->peerId, + ssl->ctx->mcastMaxSeq, + cur_lo, ssl->mcastHwCbCtx); + if (cbError) { + WOLFSSL_MSG("Multicast highwater callback returned an error."); + return MCAST_HIGHWATER_CB_E; + } + + p->highwaterMark = UpdateHighwaterMark(cur_lo, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + } +#endif + + if (ssl->keys.curEpoch == peerSeq->nextEpoch) { + next_hi = &peerSeq->nextSeq_hi; + next_lo = &peerSeq->nextSeq_lo; + window = peerSeq->window; + } + else { + next_hi = &peerSeq->prevSeq_hi; + next_lo = &peerSeq->prevSeq_lo; + window = peerSeq->prevWindow; + } + + if (cur_hi == *next_hi) { + curLT = cur_lo < *next_lo; + diff = curLT ? *next_lo - cur_lo : cur_lo - *next_lo; + } + else { + curLT = cur_hi < *next_hi; + diff = curLT ? cur_lo - *next_lo : *next_lo - cur_lo; + } + + if (curLT) { + word32 idx = diff / DTLS_WORD_BITS; + word32 newDiff = diff % DTLS_WORD_BITS; + + if (idx < WOLFSSL_DTLS_WINDOW_WORDS) + window[idx] |= (1 << newDiff); + } + else { + if (diff >= DTLS_SEQ_BITS) + XMEMSET(window, 0, DTLS_SEQ_SZ); + else { + word32 idx, newDiff, temp, i; + word32 oldWindow[WOLFSSL_DTLS_WINDOW_WORDS]; + + temp = 0; + diff++; + idx = diff / DTLS_WORD_BITS; + newDiff = diff % DTLS_WORD_BITS; + + XMEMCPY(oldWindow, window, sizeof(oldWindow)); + + for (i = 0; i < WOLFSSL_DTLS_WINDOW_WORDS; i++) { + if (i < idx) + window[i] = 0; + else { + temp |= (oldWindow[i-idx] << newDiff); + window[i] = temp; + temp = oldWindow[i-idx] >> (DTLS_WORD_BITS - newDiff - 1); + } + } + } + window[0] |= 1; + *next_lo = cur_lo + 1; + if (*next_lo < cur_lo) + (*next_hi)++; + } + + return 1; +} + + +static int DtlsMsgDrain(WOLFSSL* ssl) +{ + DtlsMsg* item = ssl->dtls_rx_msg_list; + int ret = 0; + + WOLFSSL_ENTER("DtlsMsgDrain()"); + + /* While there is an item in the store list, and it is the expected + * message, and it is complete, and there hasn't been an error in the + * last message... */ + while (item != NULL && + ssl->keys.dtls_expected_peer_handshake_number == item->seq && + item->fragSz == item->sz && + ret == 0) { + word32 idx = 0; + ssl->keys.dtls_expected_peer_handshake_number++; + ret = DoHandShakeMsgType(ssl, item->msg, + &idx, item->type, item->sz, item->sz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ssl->keys.dtls_expected_peer_handshake_number--; + break; + } + #endif + ssl->dtls_rx_msg_list = item->next; + DtlsMsgDelete(item, ssl->heap); + item = ssl->dtls_rx_msg_list; + ssl->dtls_rx_msg_list_sz--; + } + + WOLFSSL_LEAVE("DtlsMsgDrain()", ret); + return ret; +} + + +static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + byte type; + word32 size; + word32 fragOffset, fragSz; + int ret = 0; + + WOLFSSL_ENTER("DoDtlsHandShakeMsg()"); + + /* process any pending DTLS messages - this flow can happen with async */ + if (ssl->dtls_rx_msg_list != NULL) { + ret = DtlsMsgDrain(ssl); + if (ret != 0) + return ret; + + /* if done processing fragment exit with success */ + if (totalSz == *inOutIdx) + return ret; + } + + /* parse header */ + if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, + &size, &fragOffset, &fragSz, totalSz) != 0) { + WOLFSSL_ERROR(PARSE_ERROR); + return PARSE_ERROR; + } + + /* Cap the maximum size of a handshake message to something reasonable. + * By default is the maximum size of a certificate message assuming + * nine 2048-bit RSA certificates in the chain. */ + if (size > MAX_HANDSHAKE_SZ) { + WOLFSSL_MSG("Handshake message too large"); + return HANDSHAKE_SIZE_ERROR; + } + + /* check that we have complete fragment */ + if (*inOutIdx + fragSz > totalSz) { + WOLFSSL_ERROR(INCOMPLETE_DATA); + return INCOMPLETE_DATA; + } + + /* Check the handshake sequence number first. If out of order, + * add the current message to the list. If the message is in order, + * but it is a fragment, add the current message to the list, then + * check the head of the list to see if it is complete, if so, pop + * it out as the current message. If the message is complete and in + * order, process it. Check the head of the list to see if it is in + * order, if so, process it. (Repeat until list exhausted.) If the + * head is out of order, return for more processing. + */ + if (ssl->keys.dtls_peer_handshake_number > + ssl->keys.dtls_expected_peer_handshake_number) { + /* Current message is out of order. It will get stored in the list. + * Storing also takes care of defragmentation. If the messages is a + * client hello, we need to process this out of order; the server + * is not supposed to keep state, but the second client hello will + * have a different handshake sequence number than is expected, and + * the server shouldn't be expecting any particular handshake sequence + * number. (If the cookie changes multiple times in quick succession, + * the client could be sending multiple new client hello messages + * with newer and newer cookies.) */ + if (type != client_hello) { + if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) { + DtlsMsgStore(ssl, ssl->keys.dtls_peer_handshake_number, + input + *inOutIdx, size, type, + fragOffset, fragSz, ssl->heap); + } + *inOutIdx += fragSz; + ret = 0; + } + else { + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + if (ret == 0) { + ssl->keys.dtls_expected_peer_handshake_number = + ssl->keys.dtls_peer_handshake_number + 1; + } + } + } + else if (ssl->keys.dtls_peer_handshake_number < + ssl->keys.dtls_expected_peer_handshake_number) { + /* Already saw this message and processed it. It can be ignored. */ + *inOutIdx += fragSz; + if(type == finished ) { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; + } + *inOutIdx += ssl->keys.padSz; + } + } + if (IsDtlsNotSctpMode(ssl) && + VerifyForDtlsMsgPoolSend(ssl, type, fragOffset)) { + + ret = DtlsMsgPoolSend(ssl, 0); + } + } + else if (fragSz < size) { + /* Since this branch is in order, but fragmented, dtls_rx_msg_list will + * be pointing to the message with this fragment in it. Check it to see + * if it is completed. */ + if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) { + DtlsMsgStore(ssl, ssl->keys.dtls_peer_handshake_number, + input + *inOutIdx, size, type, + fragOffset, fragSz, ssl->heap); + } + *inOutIdx += fragSz; + ret = 0; + if (ssl->dtls_rx_msg_list != NULL && + ssl->dtls_rx_msg_list->fragSz >= ssl->dtls_rx_msg_list->sz) + ret = DtlsMsgDrain(ssl); + } + else { + /* This branch is in order next, and a complete message. */ + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + if (ret == 0) { + if (type != client_hello || !IsDtlsNotSctpMode(ssl)) + ssl->keys.dtls_expected_peer_handshake_number++; + if (ssl->dtls_rx_msg_list != NULL) { + ret = DtlsMsgDrain(ssl); + } + } + } + + WOLFSSL_LEAVE("DoDtlsHandShakeMsg()", ret); + return ret; +} +#endif + +#ifndef WOLFSSL_NO_TLS12 + +#ifdef HAVE_AEAD + +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + (((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) || \ + (defined(HAVE_POLY1305) && defined(HAVE_CHACHA))) +static WC_INLINE void AeadIncrementExpIV(WOLFSSL* ssl) +{ + int i; + for (i = AEAD_MAX_EXP_SZ-1; i >= 0; i--) { + if (++ssl->keys.aead_exp_IV[i]) return; + } +} +#endif + + +#if defined(HAVE_POLY1305) && defined(HAVE_CHACHA) +/* Used for the older version of creating AEAD tags with Poly1305 */ +static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out, + byte* cipher, word16 sz, byte* tag) +{ + int ret = 0; + int msglen = (sz - ssl->specs.aead_mac_size); + word32 keySz = 32; + byte padding[8]; /* used to temporarily store lengths */ + +#ifdef CHACHA_AEAD_TEST + printf("Using old version of poly1305 input.\n"); +#endif + + if (msglen < 0) + return INPUT_CASE_ERROR; + + if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0) + return ret; + + if ((ret = wc_Poly1305Update(ssl->auth.poly1305, additional, + AEAD_AUTH_DATA_SZ)) != 0) + return ret; + + /* length of additional input plus padding */ + XMEMSET(padding, 0, sizeof(padding)); + padding[0] = AEAD_AUTH_DATA_SZ; + if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, + sizeof(padding))) != 0) + return ret; + + + /* add cipher info and then its length */ + XMEMSET(padding, 0, sizeof(padding)); + if ((ret = wc_Poly1305Update(ssl->auth.poly1305, out, msglen)) != 0) + return ret; + + /* 32 bit size of cipher to 64 bit endian */ + padding[0] = msglen & 0xff; + padding[1] = (msglen >> 8) & 0xff; + padding[2] = ((word32)msglen >> 16) & 0xff; + padding[3] = ((word32)msglen >> 24) & 0xff; + if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding))) + != 0) + return ret; + + /* generate tag */ + if ((ret = wc_Poly1305Final(ssl->auth.poly1305, tag)) != 0) + return ret; + + return ret; +} + + +/* When the flag oldPoly is not set this follows RFC7905. When oldPoly is set + * the implementation follows an older draft for creating the nonce and MAC. + * The flag oldPoly gets set automatically depending on what cipher suite was + * negotiated in the handshake. This is able to be done because the IDs for the + * cipher suites was updated in RFC7905 giving unique values for the older + * draft in comparison to the more recent RFC. + * + * ssl WOLFSSL structure to get cipher and TLS state from + * out output buffer to hold encrypted data + * input data to encrypt + * sz size of input + * + * Return 0 on success negative values in error case + */ +static int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, + word16 sz) +{ + const byte* additionalSrc = input - RECORD_HEADER_SZ; + int ret = 0; + word32 msgLen = (sz - ssl->specs.aead_mac_size); + byte tag[POLY1305_AUTH_SZ]; + byte add[AEAD_AUTH_DATA_SZ]; + byte nonce[CHACHA20_NONCE_SZ]; + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */ + #ifdef CHACHA_AEAD_TEST + int i; + #endif + + XMEMSET(tag, 0, sizeof(tag)); + XMEMSET(nonce, 0, sizeof(nonce)); + XMEMSET(poly, 0, sizeof(poly)); + XMEMSET(add, 0, sizeof(add)); + + /* opaque SEQ number stored for AD */ + WriteSEQ(ssl, CUR_ORDER, add); + + if (ssl->options.oldPoly != 0) { + /* get nonce. SEQ should not be incremented again here */ + XMEMCPY(nonce + CHACHA20_OLD_OFFSET, add, OPAQUE32_LEN * 2); + } + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + additionalSrc -= DTLS_HANDSHAKE_EXTRA; + } + #endif + + /* add TLS message size to additional data */ + add[AEAD_AUTH_DATA_SZ - 2] = (msgLen >> 8) & 0xff; + add[AEAD_AUTH_DATA_SZ - 1] = msgLen & 0xff; + + XMEMCPY(add + AEAD_TYPE_OFFSET, additionalSrc, 3); + + #ifdef CHACHA_AEAD_TEST + printf("Encrypt Additional : "); + for (i = 0; i < AEAD_AUTH_DATA_SZ; i++) { + printf("%02x", add[i]); + } + printf("\n\n"); + printf("input before encryption :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", input[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + if (ssl->options.oldPoly == 0) { + /* nonce is formed by 4 0x00 byte padded to the left followed by 8 byte + * record sequence number XORed with client_write_IV/server_write_IV */ + XMEMCPY(nonce, ssl->keys.aead_enc_imp_IV, CHACHA20_IMP_IV_SZ); + nonce[4] ^= add[0]; + nonce[5] ^= add[1]; + nonce[6] ^= add[2]; + nonce[7] ^= add[3]; + nonce[8] ^= add[4]; + nonce[9] ^= add[5]; + nonce[10] ^= add[6]; + nonce[11] ^= add[7]; + } + + /* set the nonce for chacha and get poly1305 key */ + if ((ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0)) != 0) { + ForceZero(nonce, CHACHA20_NONCE_SZ); + return ret; + } + + /* create Poly1305 key using chacha20 keystream */ + if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, poly, + poly, sizeof(poly))) != 0) { + ForceZero(nonce, CHACHA20_NONCE_SZ); + return ret; + } + + /* set the counter after getting poly1305 key */ + if ((ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 1)) != 0) { + ForceZero(nonce, CHACHA20_NONCE_SZ); + return ret; + } + ForceZero(nonce, CHACHA20_NONCE_SZ); /* done with nonce, clear it */ + + /* encrypt the plain text */ + if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, out, + input, msgLen)) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + + /* get the poly1305 tag using either old padding scheme or more recent */ + if (ssl->options.oldPoly != 0) { + if ((ret = Poly1305TagOld(ssl, add, (const byte* )out, + poly, sz, tag)) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + } + else { + if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, + sizeof(poly))) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, + sizeof(add), out, msgLen, tag, sizeof(tag))) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + } + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + + /* append tag to ciphertext */ + XMEMCPY(out + msgLen, tag, sizeof(tag)); + + AeadIncrementExpIV(ssl); + + #ifdef CHACHA_AEAD_TEST + printf("mac tag :\n"); + for (i = 0; i < 16; i++) { + printf("%02x", tag[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n\noutput after encrypt :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", out[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + return ret; +} + + +/* When the flag oldPoly is not set this follows RFC7905. When oldPoly is set + * the implementation follows an older draft for creating the nonce and MAC. + * The flag oldPoly gets set automatically depending on what cipher suite was + * negotiated in the handshake. This is able to be done because the IDs for the + * cipher suites was updated in RFC7905 giving unique values for the older + * draft in comparison to the more recent RFC. + * + * ssl WOLFSSL structure to get cipher and TLS state from + * plain output buffer to hold decrypted data + * input data to decrypt + * sz size of input + * + * Return 0 on success negative values in error case + */ +static int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, + word16 sz) +{ + byte add[AEAD_AUTH_DATA_SZ]; + byte nonce[CHACHA20_NONCE_SZ]; + byte tag[POLY1305_AUTH_SZ]; + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ + int ret = 0; + int msgLen = (sz - ssl->specs.aead_mac_size); + + #ifdef CHACHA_AEAD_TEST + int i; + printf("input before decrypt :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", input[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + XMEMSET(tag, 0, sizeof(tag)); + XMEMSET(poly, 0, sizeof(poly)); + XMEMSET(nonce, 0, sizeof(nonce)); + XMEMSET(add, 0, sizeof(add)); + + /* sequence number field is 64-bits */ + WriteSEQ(ssl, PEER_ORDER, add); + + if (ssl->options.oldPoly != 0) { + /* get nonce, SEQ should not be incremented again here */ + XMEMCPY(nonce + CHACHA20_OLD_OFFSET, add, OPAQUE32_LEN * 2); + } + + /* get AD info */ + /* Store the type, version. */ + add[AEAD_TYPE_OFFSET] = ssl->curRL.type; + add[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; + add[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + + /* add TLS message size to additional data */ + add[AEAD_AUTH_DATA_SZ - 2] = (msgLen >> 8) & 0xff; + add[AEAD_AUTH_DATA_SZ - 1] = msgLen & 0xff; + + #ifdef CHACHA_AEAD_TEST + printf("Decrypt Additional : "); + for (i = 0; i < AEAD_AUTH_DATA_SZ; i++) { + printf("%02x", add[i]); + } + printf("\n\n"); + #endif + + if (ssl->options.oldPoly == 0) { + /* nonce is formed by 4 0x00 byte padded to the left followed by 8 byte + * record sequence number XORed with client_write_IV/server_write_IV */ + XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, CHACHA20_IMP_IV_SZ); + nonce[4] ^= add[0]; + nonce[5] ^= add[1]; + nonce[6] ^= add[2]; + nonce[7] ^= add[3]; + nonce[8] ^= add[4]; + nonce[9] ^= add[5]; + nonce[10] ^= add[6]; + nonce[11] ^= add[7]; + } + + /* set nonce and get poly1305 key */ + if ((ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0)) != 0) { + ForceZero(nonce, CHACHA20_NONCE_SZ); + return ret; + } + + /* use chacha20 keystream to get poly1305 key for tag */ + if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, poly, + poly, sizeof(poly))) != 0) { + ForceZero(nonce, CHACHA20_NONCE_SZ); + return ret; + } + + /* set counter after getting poly1305 key */ + if ((ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 1)) != 0) { + ForceZero(nonce, CHACHA20_NONCE_SZ); + return ret; + } + ForceZero(nonce, CHACHA20_NONCE_SZ); /* done with nonce, clear it */ + + /* get the tag using Poly1305 */ + if (ssl->options.oldPoly != 0) { + if ((ret = Poly1305TagOld(ssl, add, input, poly, sz, tag)) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + } + else { + if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, + sizeof(poly))) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, + sizeof(add), (byte*)input, msgLen, tag, sizeof(tag))) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + } + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + + /* check tag sent along with packet */ + if (ConstantCompare(input + msgLen, tag, ssl->specs.aead_mac_size) != 0) { + WOLFSSL_MSG("MAC did not match"); + if (!ssl->options.dtls) + SendAlert(ssl, alert_fatal, bad_record_mac); + return VERIFY_MAC_ERROR; + } + + /* if the tag was good decrypt message */ + if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, plain, + input, msgLen)) != 0) + return ret; + + #ifdef CHACHA_AEAD_TEST + printf("plain after decrypt :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", plain[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + return ret; +} +#endif /* HAVE_CHACHA && HAVE_POLY1305 */ +#endif /* HAVE_AEAD */ + + +#if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + +#if !defined(NO_GCM_ENCRYPT_EXTRA) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) +/* The following type is used to share code between AES-GCM and AES-CCM. */ + typedef int (*AesAuthEncryptFunc)(Aes* aes, byte* out, + const byte* in, word32 sz, + byte* iv, word32 ivSz, + byte* authTag, word32 authTagSz, + const byte* authIn, word32 authInSz); + #define AES_AUTH_ENCRYPT_FUNC AesAuthEncryptFunc + #define AES_GCM_ENCRYPT wc_AesGcmEncrypt_ex + #define AES_CCM_ENCRYPT wc_AesCcmEncrypt_ex +#else + #define AES_AUTH_ENCRYPT_FUNC wc_AesAuthEncryptFunc + #define AES_GCM_ENCRYPT wc_AesGcmEncrypt + #define AES_CCM_ENCRYPT wc_AesCcmEncrypt +#endif + +#endif + + +static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, + word16 sz, int asyncOkay) +{ + int ret = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV* asyncDev = NULL; + word32 event_flags = WC_ASYNC_FLAG_CALL_AGAIN; +#else + (void)asyncOkay; +#endif + + (void)out; + (void)input; + (void)sz; + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case wolfssl_rc4: + wc_Arc4Process(ssl->encrypt.arc4, out, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case wolfssl_triple_des: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.des3->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + + ret = wc_Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E && asyncOkay) { + ret = wolfSSL_AsyncPush(ssl, asyncDev); + } + #endif + break; + #endif + + #if defined(BUILD_AES) && defined(HAVE_AES_CBC) + case wolfssl_aes: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.aes->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) { + ret = wc_tsip_AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); + } else + #endif + ret = wc_AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E && asyncOkay) { + ret = wolfSSL_AsyncPush(ssl, asyncDev); + } + #endif + break; + #endif + + #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + case wolfssl_aes_gcm: + case wolfssl_aes_ccm:/* GCM AEAD macros use same size as CCM */ + { + AES_AUTH_ENCRYPT_FUNC aes_auth_fn; + const byte* additionalSrc; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.aes->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + + #if defined(BUILD_AESGCM) && defined(HAVE_AESCCM) + aes_auth_fn = (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) + ? AES_GCM_ENCRYPT : AES_CCM_ENCRYPT; + #elif defined(BUILD_AESGCM) + aes_auth_fn = AES_GCM_ENCRYPT; + #else + aes_auth_fn = AES_CCM_ENCRYPT; + #endif + additionalSrc = input - 5; + + XMEMSET(ssl->encrypt.additional, 0, AEAD_AUTH_DATA_SZ); + + /* sequence number field is 64-bits */ + WriteSEQ(ssl, CUR_ORDER, ssl->encrypt.additional); + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + additionalSrc -= DTLS_HANDSHAKE_EXTRA; + } + #endif + XMEMCPY(ssl->encrypt.additional + AEAD_TYPE_OFFSET, + additionalSrc, 3); + + /* Store the length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, + ssl->encrypt.additional + AEAD_LEN_OFFSET); +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) + XMEMCPY(ssl->encrypt.nonce, + ssl->keys.aead_enc_imp_IV, AESGCM_IMP_IV_SZ); + XMEMCPY(ssl->encrypt.nonce + AESGCM_IMP_IV_SZ, + ssl->keys.aead_exp_IV, AESGCM_EXP_IV_SZ); +#endif + ret = aes_auth_fn(ssl->encrypt.aes, + out + AESGCM_EXP_IV_SZ, input + AESGCM_EXP_IV_SZ, + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, + ssl->encrypt.nonce, AESGCM_NONCE_SZ, + out + sz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, + ssl->encrypt.additional, AEAD_AUTH_DATA_SZ); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E && asyncOkay) { + ret = wolfSSL_AsyncPush(ssl, asyncDev); + } + #endif +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + XMEMCPY(out, + ssl->encrypt.nonce + AESGCM_IMP_IV_SZ, AESGCM_EXP_IV_SZ); +#endif + } + break; + #endif /* BUILD_AESGCM || HAVE_AESCCM */ + + #ifdef HAVE_CAMELLIA + case wolfssl_camellia: + ret = wc_CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case wolfssl_hc128: + ret = wc_Hc128_Process(ssl->encrypt.hc128, out, input, sz); + break; + #endif + + #ifdef BUILD_RABBIT + case wolfssl_rabbit: + ret = wc_RabbitProcess(ssl->encrypt.rabbit, out, input, sz); + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChachaAEADEncrypt(ssl, out, input, sz); + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + if (input != out) { + XMEMMOVE(out, input, sz); + } + break; + #endif + + #ifdef HAVE_IDEA + case wolfssl_idea: + ret = wc_IdeaCbcEncrypt(ssl->encrypt.idea, out, input, sz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Encrypt programming error"); + ret = ENCRYPT_ERROR; + } + +#ifdef WOLFSSL_ASYNC_CRYPT + /* if async is not okay, then block */ + if (ret == WC_PENDING_E && !asyncOkay) { + ret = wc_AsyncWait(ret, asyncDev, event_flags); + } +#endif + + return ret; +} + +static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz, + int asyncOkay) +{ + int ret = 0; + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ssl->error == WC_PENDING_E) { + ssl->error = 0; /* clear async */ + } +#endif + + switch (ssl->encrypt.state) { + case CIPHER_STATE_BEGIN: + { + if (ssl->encrypt.setup == 0) { + WOLFSSL_MSG("Encrypt ciphers not setup"); + return ENCRYPT_ERROR; + } + + #ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, input, sz, FUZZ_ENCRYPT, ssl->fuzzerCtx); + #endif + + #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + /* make sure AES GCM/CCM memory is allocated */ + /* free for these happens in FreeCiphers */ + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm || + ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) { + /* make sure auth iv and auth are allocated */ + if (ssl->encrypt.additional == NULL) + ssl->encrypt.additional = (byte*)XMALLOC(AEAD_AUTH_DATA_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->encrypt.nonce == NULL) + ssl->encrypt.nonce = (byte*)XMALLOC(AESGCM_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->encrypt.additional == NULL || + ssl->encrypt.nonce == NULL) { + return MEMORY_E; + } + } + #endif /* BUILD_AESGCM || HAVE_AESCCM */ + + /* Advance state and proceed */ + ssl->encrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + ret = EncryptDo(ssl, out, input, sz, asyncOkay); + + /* Advance state */ + ssl->encrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* If pending, then leave and return will resume below */ + if (ret == WC_PENDING_E) { + return ret; + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm || + ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) + { + /* finalize authentication cipher */ +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) + AeadIncrementExpIV(ssl); +#endif + if (ssl->encrypt.nonce) + ForceZero(ssl->encrypt.nonce, AESGCM_NONCE_SZ); + } + #endif /* BUILD_AESGCM || HAVE_AESCCM */ + break; + } + } + + /* Reset state */ + ssl->encrypt.state = CIPHER_STATE_BEGIN; + + return ret; +} + + +static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, + word16 sz) +{ + int ret = 0; + + (void)plain; + (void)input; + (void)sz; + + switch (ssl->specs.bulk_cipher_algorithm) + { + #ifdef BUILD_ARC4 + case wolfssl_rc4: + wc_Arc4Process(ssl->decrypt.arc4, plain, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case wolfssl_triple_des: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.des3->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + + ret = wc_Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &ssl->decrypt.des3->asyncDev); + } + #endif + break; + #endif + + #if defined(BUILD_AES) && defined(HAVE_AES_CBC) + case wolfssl_aes: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) { + ret = wc_tsip_AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); + } else + #endif + ret = wc_AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &ssl->decrypt.aes->asyncDev); + } + #endif + break; + #endif + + #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + case wolfssl_aes_gcm: + case wolfssl_aes_ccm: /* GCM AEAD macros use same size as CCM */ + { + wc_AesAuthDecryptFunc aes_auth_fn; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + + #if defined(BUILD_AESGCM) && defined(HAVE_AESCCM) + aes_auth_fn = (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) + ? wc_AesGcmDecrypt : wc_AesCcmDecrypt; + #elif defined(BUILD_AESGCM) + aes_auth_fn = wc_AesGcmDecrypt; + #else + aes_auth_fn = wc_AesCcmDecrypt; + #endif + + XMEMSET(ssl->decrypt.additional, 0, AEAD_AUTH_DATA_SZ); + + /* sequence number field is 64-bits */ + WriteSEQ(ssl, PEER_ORDER, ssl->decrypt.additional); + + ssl->decrypt.additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; + ssl->decrypt.additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; + ssl->decrypt.additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + + c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, + ssl->decrypt.additional + AEAD_LEN_OFFSET); + XMEMCPY(ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV, + AESGCM_IMP_IV_SZ); + XMEMCPY(ssl->decrypt.nonce + AESGCM_IMP_IV_SZ, input, + AESGCM_EXP_IV_SZ); + if ((ret = aes_auth_fn(ssl->decrypt.aes, + plain + AESGCM_EXP_IV_SZ, + input + AESGCM_EXP_IV_SZ, + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, + ssl->decrypt.nonce, AESGCM_NONCE_SZ, + input + sz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, + ssl->decrypt.additional, AEAD_AUTH_DATA_SZ)) < 0) { + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &ssl->decrypt.aes->asyncDev); + } + #endif + } + } + break; + #endif /* BUILD_AESGCM || HAVE_AESCCM */ + + #ifdef HAVE_CAMELLIA + case wolfssl_camellia: + ret = wc_CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case wolfssl_hc128: + ret = wc_Hc128_Process(ssl->decrypt.hc128, plain, input, sz); + break; + #endif + + #ifdef BUILD_RABBIT + case wolfssl_rabbit: + ret = wc_RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChachaAEADDecrypt(ssl, plain, input, sz); + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + if (input != plain) { + XMEMMOVE(plain, input, sz); + } + break; + #endif + + #ifdef HAVE_IDEA + case wolfssl_idea: + ret = wc_IdeaCbcDecrypt(ssl->decrypt.idea, plain, input, sz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Decrypt programming error"); + ret = DECRYPT_ERROR; + } + + return ret; +} + +static WC_INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input, + word16 sz) +{ + int ret = 0; + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->decrypt.state); + if (ret != WC_NOT_PENDING_E) { + /* check for still pending */ + if (ret == WC_PENDING_E) + return ret; + + ssl->error = 0; /* clear async */ + + /* let failures through so CIPHER_STATE_END logic is run */ + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->decrypt.state = CIPHER_STATE_BEGIN; + } + + switch (ssl->decrypt.state) { + case CIPHER_STATE_BEGIN: + { + if (ssl->decrypt.setup == 0) { + WOLFSSL_MSG("Decrypt ciphers not setup"); + return DECRYPT_ERROR; + } + + #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + /* make sure AES GCM/CCM memory is allocated */ + /* free for these happens in FreeCiphers */ + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm || + ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) { + /* make sure auth iv and auth are allocated */ + if (ssl->decrypt.additional == NULL) + ssl->decrypt.additional = (byte*)XMALLOC(AEAD_AUTH_DATA_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->decrypt.nonce == NULL) + ssl->decrypt.nonce = (byte*)XMALLOC(AESGCM_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->decrypt.additional == NULL || + ssl->decrypt.nonce == NULL) { + return MEMORY_E; + } + } + #endif /* BUILD_AESGCM || HAVE_AESCCM */ + + /* Advance state and proceed */ + ssl->decrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + case CIPHER_STATE_DO: + { + ret = DecryptDo(ssl, plain, input, sz); + + /* Advance state */ + ssl->decrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* If pending, leave and return below */ + if (ret == WC_PENDING_E) { + return ret; + } + #endif + } + FALL_THROUGH; + case CIPHER_STATE_END: + { + #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + /* make sure AES GCM/CCM nonce is cleared */ + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm || + ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) { + if (ssl->decrypt.nonce) + ForceZero(ssl->decrypt.nonce, AESGCM_NONCE_SZ); + + if (ret < 0) + ret = VERIFY_MAC_ERROR; + } + #endif /* BUILD_AESGCM || HAVE_AESCCM */ + break; + } + } + + /* Reset state */ + ssl->decrypt.state = CIPHER_STATE_BEGIN; + + /* handle mac error case */ + if (ret == VERIFY_MAC_ERROR) { + if (!ssl->options.dtls) + SendAlert(ssl, alert_fatal, bad_record_mac); + + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ + } + + return ret; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +/* Check conditions for a cipher to have an explicit IV. + * + * ssl The SSL/TLS object. + * returns 1 if the cipher in use has an explicit IV and 0 otherwise. + */ +static WC_INLINE int CipherHasExpIV(WOLFSSL *ssl) +{ +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return 0; +#endif + return (ssl->specs.cipher_type == aead) && + (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha); +} + +/* check cipher text size for sanity */ +static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz) +{ +#ifdef HAVE_TRUNCATED_HMAC + word32 minLength = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 minLength = ssl->specs.hash_size; /* covers stream */ +#endif + +#ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) { +#ifdef HAVE_ENCRYPT_THEN_MAC + if (ssl->options.startedETMRead) { + if ((encryptSz - MacSize(ssl)) % ssl->specs.block_size) { + WOLFSSL_MSG("Block ciphertext not block size"); + return SANITY_CIPHER_E; + } + } + else +#endif + if (encryptSz % ssl->specs.block_size) { + WOLFSSL_MSG("Block ciphertext not block size"); + return SANITY_CIPHER_E; + } + + minLength++; /* pad byte */ + + if (ssl->specs.block_size > minLength) + minLength = ssl->specs.block_size; + + if (ssl->options.tls1_1) + minLength += ssl->specs.block_size; /* explicit IV */ + } + else +#endif + if (ssl->specs.cipher_type == aead) { + minLength = ssl->specs.aead_mac_size; /* authTag size */ + if (CipherHasExpIV(ssl)) + minLength += AESGCM_EXP_IV_SZ; /* explicit IV */ + } + + if (encryptSz < minLength) { + WOLFSSL_MSG("Ciphertext not minimum size"); + return SANITY_CIPHER_E; + } + + return 0; +} + + +#ifndef WOLFSSL_AEAD_ONLY +/* check all length bytes for the pad value, return 0 on success */ +static int PadCheck(const byte* a, byte pad, int length) +{ + int i; + int compareSum = 0; + + for (i = 0; i < length; i++) { + compareSum |= a[i] ^ pad; + } + + return compareSum; +} + + +/* Mask the padding bytes with the expected values. + * Constant time implementation - does maximum pad size possible. + * + * data Message data. + * sz Size of the message including MAC and padding and padding length. + * macSz Size of the MAC. + * returns 0 on success, otherwise failure. + */ +static byte MaskPadding(const byte* data, int sz, int macSz) +{ + int i; + int checkSz = sz - 1; + byte paddingSz = data[sz - 1]; + byte mask; + byte good = ctMaskGT(paddingSz, sz - 1 - macSz); + + if (checkSz > TLS_MAX_PAD_SZ) + checkSz = TLS_MAX_PAD_SZ; + + for (i = 0; i < checkSz; i++) { + mask = ctMaskLTE(i, paddingSz); + good |= mask & (data[sz - 1 - i] ^ paddingSz); + } + + return good; +} + +/* Mask the MAC in the message with the MAC calculated. + * Constant time implementation - starts looking for MAC where maximum padding + * size has it. + * + * data Message data. + * sz Size of the message including MAC and padding and padding length. + * macSz Size of the MAC data. + * expMac Expected MAC value. + * returns 0 on success, otherwise failure. + */ +static byte MaskMac(const byte* data, int sz, int macSz, byte* expMac) +{ + int i, j; + unsigned char mac[WC_MAX_DIGEST_SIZE]; + int scanStart = sz - 1 - TLS_MAX_PAD_SZ - macSz; + int macEnd = sz - 1 - data[sz - 1]; + int macStart = macEnd - macSz; + int r = 0; + unsigned char started, notEnded; + unsigned char good = 0; + + scanStart &= ctMaskIntGTE(scanStart, 0); + macStart &= ctMaskIntGTE(macStart, 0); + + /* Div on Intel has different speeds depending on value. + * Use a bitwise AND or mod a specific value (converted to mul). */ + if ((macSz & (macSz - 1)) == 0) + r = (macSz - (scanStart - macStart)) & (macSz - 1); +#ifndef NO_SHA + else if (macSz == WC_SHA_DIGEST_SIZE) + r = (macSz - (scanStart - macStart)) % WC_SHA_DIGEST_SIZE; +#endif +#ifdef WOLFSSL_SHA384 + else if (macSz == WC_SHA384_DIGEST_SIZE) + r = (macSz - (scanStart - macStart)) % WC_SHA384_DIGEST_SIZE; +#endif + + XMEMSET(mac, 0, macSz); + for (i = scanStart; i < sz; i += macSz) { + for (j = 0; j < macSz && j + i < sz; j++) { + started = ctMaskGTE(i + j, macStart); + notEnded = ctMaskLT(i + j, macEnd); + mac[j] |= started & notEnded & data[i + j]; + } + } + + if ((macSz & (macSz - 1)) == 0) { + for (i = 0; i < macSz; i++) + good |= expMac[i] ^ mac[(i + r) & (macSz - 1)]; + } +#ifndef NO_SHA + else if (macSz == WC_SHA_DIGEST_SIZE) { + for (i = 0; i < macSz; i++) + good |= expMac[i] ^ mac[(i + r) % WC_SHA_DIGEST_SIZE]; + } +#endif +#ifdef WOLFSSL_SHA384 + else if (macSz == WC_SHA384_DIGEST_SIZE) { + for (i = 0; i < macSz; i++) + good |= expMac[i] ^ mac[(i + r) % WC_SHA384_DIGEST_SIZE]; + } +#endif + + return good; +} + +/* timing resistant pad/verify check, return 0 on success */ +int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int macSz, + int pLen, int content) +{ + byte verify[WC_MAX_DIGEST_SIZE]; + byte good; + int ret = 0; + + good = MaskPadding(input, pLen, macSz); + /* 4th argument has potential to underflow, ssl->hmac function should + * either increment the size by (macSz + padLen + 1) before use or check on + * the size to make sure is valid. */ + ret = ssl->hmac(ssl, verify, input, pLen - macSz - padLen - 1, padLen, + content, 1); + good |= MaskMac(input, pLen, ssl->specs.hash_size, verify); + + /* Non-zero on failure. */ + good = (byte)~(word32)good; + good &= good >> 4; + good &= good >> 2; + good &= good >> 1; + /* Make ret negative on masking failure. */ + ret -= 1 - good; + + /* Treat any failure as verify MAC error. */ + if (ret != 0) + ret = VERIFY_MAC_ERROR; + + return ret; +} +#endif + + +int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) +{ + word32 msgSz = ssl->keys.encryptSz; + word32 idx = *inOutIdx; + int dataSz; + int ivExtra = 0; + byte* rawData = input + idx; /* keep current for hmac */ +#ifdef HAVE_LIBZ + byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->options.tls1_3 && ssl->options.handShakeDone == 0) { + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->earlyData != no_early_data && + ssl->options.clientState < CLIENT_FINISHED_COMPLETE) { + ssl->earlyDataSz += ssl->curSize; + if (ssl->earlyDataSz <= ssl->options.maxEarlyDataSz) { + WOLFSSL_MSG("Ignoring EarlyData!"); + *inOutIdx = ssl->buffers.inputBuffer.length; + return 0; + } + WOLFSSL_MSG("Too much EarlyData!"); + } + } +#endif + if (ssl->options.handShakeDone == 0) { + WOLFSSL_MSG("Received App data before a handshake completed"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + +#ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) { + if (ssl->options.tls1_1) + ivExtra = ssl->specs.block_size; + } + else +#endif + if (ssl->specs.cipher_type == aead) { + if (CipherHasExpIV(ssl)) + ivExtra = AESGCM_EXP_IV_SZ; + } + + dataSz = msgSz - ivExtra - ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + dataSz -= MacSize(ssl); +#endif + if (dataSz < 0) { + WOLFSSL_MSG("App data buffer error, malicious input?"); + SendAlert(ssl, alert_fatal, unexpected_message); + return BUFFER_ERROR; + } +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData > early_data_ext) { + if (ssl->earlyDataSz + dataSz > ssl->options.maxEarlyDataSz) { + SendAlert(ssl, alert_fatal, unexpected_message); + return WOLFSSL_FATAL_ERROR; + } + ssl->earlyDataSz += dataSz; + } +#endif + + /* read data */ + if (dataSz) { + int rawSz = dataSz; /* keep raw size for idx adjustment */ + +#ifdef HAVE_LIBZ + if (ssl->options.usingCompression) { + dataSz = myDeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp)); + if (dataSz < 0) return dataSz; + } +#endif + idx += rawSz; + + ssl->buffers.clearOutputBuffer.buffer = rawData; + ssl->buffers.clearOutputBuffer.length = dataSz; + } + + idx += ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + idx += MacSize(ssl); +#endif + +#ifdef HAVE_LIBZ + /* decompress could be bigger, overwrite after verify */ + if (ssl->options.usingCompression) + XMEMMOVE(rawData, decomp, dataSz); +#endif + + *inOutIdx = idx; + return 0; +} + + +/* process alert, return level */ +static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type, + word32 totalSz) +{ + byte level; + byte code; + word32 dataSz = totalSz - *inOutIdx; + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "Alert"); + if (ssl->toInfoOn) + /* add record header back on to info + alert bytes level/code */ + AddPacketInfo(ssl, "Alert", alert, input + *inOutIdx - + RECORD_HEADER_SZ, RECORD_HEADER_SZ + ALERT_SIZE, + READ_PROTO, ssl->heap); + #endif + + if (IsEncryptionOn(ssl, 0)) { + dataSz -= ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + dataSz -= MacSize(ssl); + #endif + } + + /* make sure can read the message */ + if (dataSz != ALERT_SIZE) { +#ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, unexpected_message); +#endif + return BUFFER_E; + } + + level = input[(*inOutIdx)++]; + code = input[(*inOutIdx)++]; + ssl->alert_history.last_rx.code = code; + ssl->alert_history.last_rx.level = level; + *type = code; + if (level == alert_fatal) { + ssl->options.isClosed = 1; /* Don't send close_notify */ + } + + if (++ssl->options.alertCount >= WOLFSSL_ALERT_COUNT_MAX) { + WOLFSSL_MSG("Alert count exceeded"); +#ifdef WOLFSSL_EXTRA_ALERTS + if (level != alert_warning || code != close_notify) + SendAlert(ssl, alert_fatal, unexpected_message); +#endif + return ALERT_COUNT_E; + } + + WOLFSSL_MSG("Got alert"); + if (*type == close_notify) { + WOLFSSL_MSG("\tclose notify"); + ssl->options.closeNotify = 1; + } +#ifdef WOLFSSL_TLS13 + if (*type == decode_error) { + WOLFSSL_MSG("\tdecode error"); + } + if (*type == illegal_parameter) { + WOLFSSL_MSG("\tillegal parameter"); + } +#endif + WOLFSSL_ERROR(*type); + if (IsEncryptionOn(ssl, 0)) { + *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + *inOutIdx += MacSize(ssl); + #endif + } + + return level; +} + +static int GetInputData(WOLFSSL *ssl, word32 size) +{ + int in; + int inSz; + int maxLength; + int usedLength; + int dtlsExtra = 0; + + + /* check max input length */ + usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx; + maxLength = ssl->buffers.inputBuffer.bufferSize - usedLength; + inSz = (int)(size - usedLength); /* from last partial read */ + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + if (size < ssl->dtls_expected_rx) + dtlsExtra = (int)(ssl->dtls_expected_rx - size); + inSz = ssl->dtls_expected_rx; + } +#endif + + /* check that no lengths or size values are negative */ + if (usedLength < 0 || maxLength < 0 || inSz <= 0) { + return BUFFER_ERROR; + } + + if (inSz > maxLength) { + if (GrowInputBuffer(ssl, size + dtlsExtra, usedLength) < 0) + return MEMORY_E; + } + + /* Put buffer data at start if not there */ + if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0) + XMEMMOVE(ssl->buffers.inputBuffer.buffer, + ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + usedLength); + + /* remove processed data */ + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + + /* read data from network */ + do { + in = wolfSSLReceive(ssl, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.length, + inSz); + if (in == WANT_READ) + return WANT_READ; + + if (in < 0) + return SOCKET_ERROR_E; + + if (in > inSz) + return RECV_OVERFLOW_E; + + ssl->buffers.inputBuffer.length += in; + inSz -= in; + + } while (ssl->buffers.inputBuffer.length < size); + +#ifdef WOLFSSL_DEBUG_TLS + if (ssl->buffers.inputBuffer.idx == 0) { + WOLFSSL_MSG("Data received"); + WOLFSSL_BUFFER(ssl->buffers.inputBuffer.buffer, + ssl->buffers.inputBuffer.length); + } +#endif + + return 0; +} + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +static WC_INLINE int VerifyMacEnc(WOLFSSL* ssl, const byte* input, word32 msgSz, + int content) +{ + int ret; +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 digestSz = ssl->specs.hash_size; +#endif + byte verify[WC_MAX_DIGEST_SIZE]; + + WOLFSSL_MSG("Verify MAC of Encrypted Data"); + + if (msgSz < digestSz) { + return VERIFY_MAC_ERROR; + } + + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1); + ret |= ConstantCompare(verify, input + msgSz - digestSz, digestSz); + if (ret != 0) { + return VERIFY_MAC_ERROR; + } + + return 0; +} +#endif + +static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, + int content, word32* padSz) +{ +#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) + int ivExtra = 0; + int ret; + word32 pad = 0; + word32 padByte = 0; +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 digestSz = ssl->specs.hash_size; +#endif + byte verify[WC_MAX_DIGEST_SIZE]; + + + if (ssl->specs.cipher_type == block) { + if (ssl->options.tls1_1) + ivExtra = ssl->specs.block_size; + pad = *(input + msgSz - ivExtra - 1); + padByte = 1; + + if (ssl->options.tls) { + ret = TimingPadVerify(ssl, input, pad, digestSz, msgSz - ivExtra, + content); + if (ret != 0) + return ret; + } + else { /* sslv3, some implementations have bad padding, but don't + * allow bad read */ + int badPadLen = 0; + byte dmy[sizeof(WOLFSSL) >= MAX_PAD_SIZE ? 1 : MAX_PAD_SIZE] = {0}; + byte* dummy = sizeof(dmy) < MAX_PAD_SIZE ? (byte*) ssl : dmy; + + (void)dmy; + + if (pad > (msgSz - digestSz - 1)) { + WOLFSSL_MSG("Plain Len not long enough for pad/mac"); + pad = 0; /* no bad read */ + badPadLen = 1; + } + PadCheck(dummy, (byte)pad, MAX_PAD_SIZE); /* timing only */ + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, pad, + content, 1); + if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1, + digestSz) != 0) + return VERIFY_MAC_ERROR; + if (ret != 0 || badPadLen) + return VERIFY_MAC_ERROR; + } + } + else if (ssl->specs.cipher_type == stream) { + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1); + if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){ + return VERIFY_MAC_ERROR; + } + if (ret != 0) + return VERIFY_MAC_ERROR; + } +#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */ + + if (ssl->specs.cipher_type == aead) { + *padSz = ssl->specs.aead_mac_size; + } +#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) + else { + *padSz = digestSz + pad + padByte; + } +#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */ + + (void)input; + (void)msgSz; + (void)content; + + return 0; +} + + +/* process input requests, return 0 is done, 1 is call again to complete, and + negative number is error */ +int ProcessReply(WOLFSSL* ssl) +{ + int ret = 0, type, readSz; + int atomicUser = 0; + word32 startIdx = 0; +#if defined(WOLFSSL_DTLS) + int used; +#endif + +#ifdef ATOMIC_USER + if (ssl->ctx->DecryptVerifyCb) + atomicUser = 1; +#endif + + if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE + #ifdef WOLFSSL_ASYNC_CRYPT + && ssl->error != WC_PENDING_E + #endif + #ifdef WOLFSSL_NONBLOCK_OCSP + && ssl->error != OCSP_WANT_READ + #endif + ) { + WOLFSSL_MSG("ProcessReply retry in error state, not allowed"); + return ssl->error; + } + + for (;;) { + switch (ssl->options.processReply) { + + /* in the WOLFSSL_SERVER case, get the first byte for detecting + * old client hello */ + case doProcessInit: + + readSz = RECORD_HEADER_SZ; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + readSz = DTLS_RECORD_HEADER_SZ; + #endif + + /* get header or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, readSz)) < 0) + return ret; + } else { + #ifdef WOLFSSL_DTLS + /* read ahead may already have header */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < readSz) { + if ((ret = GetInputData(ssl, readSz)) < 0) + return ret; + } + #endif + } + +#ifdef OLD_HELLO_ALLOWED + + /* see if sending SSLv2 client hello */ + if ( ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.clientState == NULL_STATE && + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx] + != handshake) { + byte b0, b1; + + ssl->options.processReply = runProcessOldClientHello; + + /* sanity checks before getting size at front */ + if (ssl->buffers.inputBuffer.buffer[ + ssl->buffers.inputBuffer.idx + OPAQUE16_LEN] != OLD_HELLO_ID) { + WOLFSSL_MSG("Not a valid old client hello"); + return PARSE_ERROR; + } + + if (ssl->buffers.inputBuffer.buffer[ + ssl->buffers.inputBuffer.idx + OPAQUE24_LEN] != SSLv3_MAJOR && + ssl->buffers.inputBuffer.buffer[ + ssl->buffers.inputBuffer.idx + OPAQUE24_LEN] != DTLS_MAJOR) { + WOLFSSL_MSG("Not a valid version in old client hello"); + return PARSE_ERROR; + } + + /* how many bytes need ProcessOldClientHello */ + b0 = + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; + b1 = + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; + ssl->curSize = (word16)(((b0 & 0x7f) << 8) | b1); + } + else { + ssl->options.processReply = getRecordLayerHeader; + continue; + } + FALL_THROUGH; + + /* in the WOLFSSL_SERVER case, run the old client hello */ + case runProcessOldClientHello: + + /* get sz bytes or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + } else { + #ifdef WOLFSSL_DTLS + /* read ahead may already have */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < ssl->curSize) + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + #endif /* WOLFSSL_DTLS */ + } + + ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx, + ssl->curSize); + if (ret < 0) + return ret; + + else if (ssl->buffers.inputBuffer.idx == + ssl->buffers.inputBuffer.length) { + ssl->options.processReply = doProcessInit; + return 0; + } + +#endif /* OLD_HELLO_ALLOWED */ + FALL_THROUGH; + + /* get the record layer header */ + case getRecordLayerHeader: + + ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + &ssl->curRL, &ssl->curSize); +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls && ret == SEQUENCE_ERROR) { + WOLFSSL_MSG("Silently dropping out of order DTLS message"); + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.length = 0; + ssl->buffers.inputBuffer.idx = 0; +#ifdef WOLFSSL_DTLS_DROP_STATS + ssl->replayDropCount++; +#endif /* WOLFSSL_DTLS_DROP_STATS */ + + if (IsDtlsNotSctpMode(ssl) && ssl->options.dtlsHsRetain) { + ret = DtlsMsgPoolSend(ssl, 0); + if (ret != 0) + return ret; + } + + continue; + } +#endif + if (ret != 0) + return ret; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && IsEncryptionOn(ssl, 0) && + ssl->curRL.type != application_data && + ssl->curRL.type != change_cipher_spec) { + SendAlert(ssl, alert_fatal, unexpected_message); + return PARSE_ERROR; + } +#endif + + ssl->options.processReply = getData; + FALL_THROUGH; + + /* retrieve record layer data */ + case getData: + + /* get sz bytes or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) { +#ifdef WOLFSSL_EXTRA_ALERTS + if (ret != WANT_READ) + SendAlert(ssl, alert_fatal, bad_record_mac); +#endif + return ret; + } + } + else { +#ifdef WOLFSSL_DTLS + /* read ahead may already have */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < ssl->curSize) + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; +#endif + } + + if (IsEncryptionOn(ssl, 0)) { + int tooLong = 0; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + tooLong = ssl->curSize > MAX_TLS13_ENC_SZ; + tooLong |= ssl->curSize - ssl->specs.aead_mac_size > + MAX_TLS13_PLAIN_SZ; + } +#endif +#ifdef WOLFSSL_EXTRA_ALERTS + if (!IsAtLeastTLSv1_3(ssl->version)) + tooLong = ssl->curSize > MAX_TLS_CIPHER_SZ; +#endif + if (tooLong) { + WOLFSSL_MSG("Encrypted data too long"); +#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_EXTRA_ALERTS) + SendAlert(ssl, alert_fatal, record_overflow); +#endif + return BUFFER_ERROR; + } + } + ssl->keys.padSz = 0; + + ssl->options.processReply = verifyEncryptedMessage; + startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */ + FALL_THROUGH; + + /* verify digest of encrypted message */ + case verifyEncryptedMessage: +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 && + !atomicUser && ssl->options.startedETMRead) { + ret = VerifyMacEnc(ssl, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize, ssl->curRL.type); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + return ret; + #endif + if (ret < 0) { + WOLFSSL_MSG("VerifyMacEnc failed"); + WOLFSSL_ERROR(ret); + #ifdef WOLFSSL_DTLS + /* If in DTLS mode, if the decrypt fails for any + * reason, pretend the datagram never happened. */ + if (ssl->options.dtls) { + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ + } + #endif /* WOLFSSL_DTLS */ + #ifdef WOLFSSL_EXTRA_ALERTS + if (!ssl->options.dtls) + SendAlert(ssl, alert_fatal, bad_record_mac); + #endif + return DECRYPT_ERROR; + } + ssl->keys.encryptSz = ssl->curSize; + } +#endif + ssl->options.processReply = decryptMessage; + FALL_THROUGH; + + /* decrypt message */ + case decryptMessage: + +#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18) + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) +#else + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 && + (!IsAtLeastTLSv1_3(ssl->version) || + ssl->curRL.type != change_cipher_spec)) +#endif + { + bufferStatic* in = &ssl->buffers.inputBuffer; + + ret = SanityCheckCipherText(ssl, ssl->curSize); + if (ret < 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, bad_record_mac); + #endif + return ret; + } + + if (atomicUser) { + #ifdef ATOMIC_USER + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + ret = ssl->ctx->VerifyDecryptCb(ssl, + in->buffer + in->idx, in->buffer + in->idx, + ssl->curSize - MacSize(ssl), + ssl->curRL.type, 1, &ssl->keys.padSz, + ssl->DecryptVerifyCtx); + } + else + #endif + { + ret = ssl->ctx->DecryptVerifyCb(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize, ssl->curRL.type, 1, + &ssl->keys.padSz, ssl->DecryptVerifyCtx); + } + #endif /* ATOMIC_USER */ + } + else { + if (!ssl->options.tls1_3) { + #ifndef WOLFSSL_NO_TLS12 + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + ret = Decrypt(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize - digestSz); + ssl->keys.padSz = + in->buffer[in->idx + ssl->curSize - digestSz - 1]; + ssl->keys.padSz += 1; + ssl->keys.decryptedCur = 1; + } + else + #endif + { + ret = Decrypt(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize); + } + #else + ret = DECRYPT_ERROR; + #endif + } + else + { + #ifdef WOLFSSL_TLS13 + #if defined(WOLFSSL_TLS13_DRAFT_18) || \ + defined(WOLFSSL_TLS13_DRAFT_22) || \ + defined(WOLFSSL_TLS13_DRAFT_23) + ret = DecryptTls13(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize, NULL, 0); + #else + ret = DecryptTls13(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize, + (byte*)&ssl->curRL, RECORD_HEADER_SZ); + #endif + #else + ret = DECRYPT_ERROR; + #endif /* WOLFSSL_TLS13 */ + } + } + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + return ret; + #endif + + if (ret >= 0) { + #ifndef WOLFSSL_NO_TLS12 + /* handle success */ + #ifndef WOLFSSL_AEAD_ONLY + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + ssl->buffers.inputBuffer.idx += ssl->specs.block_size; + #endif + /* go past TLSv1.1 IV */ + if (CipherHasExpIV(ssl)) + ssl->buffers.inputBuffer.idx += AESGCM_EXP_IV_SZ; + #endif + } + else { + WOLFSSL_MSG("Decrypt failed"); + WOLFSSL_ERROR(ret); + #ifdef WOLFSSL_EARLY_DATA + if (ssl->options.tls1_3) { + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->earlyData != no_early_data && + ssl->options.clientState < + CLIENT_FINISHED_COMPLETE) { + ssl->earlyDataSz += ssl->curSize; + if (ssl->earlyDataSz <= + ssl->options.maxEarlyDataSz) { + WOLFSSL_MSG("Ignoring EarlyData!"); + if (ssl->keys.peer_sequence_number_lo-- == 0) + ssl->keys.peer_sequence_number_hi--; + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + return 0; + } + WOLFSSL_MSG("Too much EarlyData!"); + } + SendAlert(ssl, alert_fatal, bad_record_mac); + } + #endif + #ifdef WOLFSSL_DTLS + /* If in DTLS mode, if the decrypt fails for any + * reason, pretend the datagram never happened. */ + if (ssl->options.dtls) { + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ + } + #endif /* WOLFSSL_DTLS */ + return DECRYPT_ERROR; + } + } + + ssl->options.processReply = verifyMessage; + FALL_THROUGH; + + /* verify digest of message */ + case verifyMessage: + +#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18) + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) +#else + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 && + (!IsAtLeastTLSv1_3(ssl->version) || + ssl->curRL.type != change_cipher_spec)) +#endif + { + if (!atomicUser +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + && !ssl->options.startedETMRead +#endif + ) { + ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize, ssl->curRL.type, + &ssl->keys.padSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + return ret; + #endif + if (ret < 0) { + WOLFSSL_MSG("VerifyMac failed"); + WOLFSSL_ERROR(ret); + #ifdef WOLFSSL_DTLS + /* If in DTLS mode, if the decrypt fails for any + * reason, pretend the datagram never happened. */ + if (ssl->options.dtls) { + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ + } + #endif /* WOLFSSL_DTLS */ + #ifdef WOLFSSL_EXTRA_ALERTS + if (!ssl->options.dtls) + SendAlert(ssl, alert_fatal, bad_record_mac); + #endif + return DECRYPT_ERROR; + } + } + + ssl->keys.encryptSz = ssl->curSize; + ssl->keys.decryptedCur = 1; +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + word16 i = (word16)(ssl->buffers.inputBuffer.length - + ssl->keys.padSz); + /* Remove padding from end of plain text. */ + for (--i; i > ssl->buffers.inputBuffer.idx; i--) { + if (ssl->buffers.inputBuffer.buffer[i] != 0) + break; + } + /* Get the real content type from the end of the data. */ + ssl->curRL.type = ssl->buffers.inputBuffer.buffer[i]; + ssl->keys.padSz = ssl->buffers.inputBuffer.length - i; + } +#endif + } + + ssl->options.processReply = runProcessingOneMessage; + FALL_THROUGH; + + /* the record layer is here */ + case runProcessingOneMessage: + + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (IsEncryptionOn(ssl, 0) && ssl->options.startedETMRead) { + if (ssl->buffers.inputBuffer.length - ssl->keys.padSz - + ssl->buffers.inputBuffer.idx - + MacSize(ssl) > MAX_PLAINTEXT_SZ) { + WOLFSSL_MSG("Plaintext too long - Encrypt-Then-MAC"); + #if defined(WOLFSSL_EXTRA_ALERTS) + SendAlert(ssl, alert_fatal, record_overflow); + #endif + return BUFFER_ERROR; + } + } + else + #endif + if (ssl->buffers.inputBuffer.length - ssl->keys.padSz - + ssl->buffers.inputBuffer.idx > MAX_PLAINTEXT_SZ) { + WOLFSSL_MSG("Plaintext too long"); +#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_EXTRA_ALERTS) + SendAlert(ssl, alert_fatal, record_overflow); +#endif + return BUFFER_ERROR; + } + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + DtlsUpdateWindow(ssl); + } + #endif /* WOLFSSL_DTLS */ + + WOLFSSL_MSG("received record layer msg"); + + switch (ssl->curRL.type) { + case handshake : + /* debugging in DoHandShakeMsg */ + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + ret = DoDtlsHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); +#endif + } + else if (!IsAtLeastTLSv1_3(ssl->version)) { +#ifndef WOLFSSL_NO_TLS12 + ret = DoHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); +#else + ret = BUFFER_ERROR; +#endif + } + else { +#ifdef WOLFSSL_TLS13 + ret = DoTls13HandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); + #ifdef WOLFSSL_EARLY_DATA + if (ret != 0) + return ret; + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->earlyData > early_data_ext && + ssl->options.handShakeState == HANDSHAKE_DONE) { + ssl->earlyData = no_early_data; + ssl->options.processReply = doProcessInit; + return ZERO_RETURN; + } + #endif +#else + ret = BUFFER_ERROR; +#endif + } + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + break; + + case change_cipher_spec: + WOLFSSL_MSG("got CHANGE CIPHER SPEC"); + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "ChangeCipher"); + /* add record header back on info */ + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "ChangeCipher", + change_cipher_spec, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ, + 1 + RECORD_HEADER_SZ, READ_PROTO, ssl->heap); + #ifdef WOLFSSL_CALLBACKS + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + #endif + } + #endif + +#ifdef WOLFSSL_TLS13 + #ifdef WOLFSSL_TLS13_DRAFT_18 + if (IsAtLeastTLSv1_3(ssl->version)) { + SendAlert(ssl, alert_fatal, illegal_parameter); + return UNKNOWN_RECORD_TYPE; + } + #else + if (IsAtLeastTLSv1_3(ssl->version)) { + word32 i = ssl->buffers.inputBuffer.idx; + if (ssl->options.handShakeState == HANDSHAKE_DONE) { + SendAlert(ssl, alert_fatal, unexpected_message); + return UNKNOWN_RECORD_TYPE; + } + if (ssl->curSize != 1 || + ssl->buffers.inputBuffer.buffer[i] != 1) { + SendAlert(ssl, alert_fatal, illegal_parameter); + return UNKNOWN_RECORD_TYPE; + } + ssl->buffers.inputBuffer.idx++; + break; + } + #endif +#endif + +#ifndef WOLFSSL_NO_TLS12 + ret = SanityCheckMsgReceived(ssl, change_cipher_hs); + if (ret != 0) { + if (!ssl->options.dtls) { + return ret; + } + else { + #ifdef WOLFSSL_DTLS + /* Check for duplicate CCS message in DTLS mode. + * DTLS allows for duplicate messages, and it should be + * skipped. Also skip if out of order. */ + if (ret != DUPLICATE_MSG_E && ret != OUT_OF_ORDER_E) + return ret; + + if (IsDtlsNotSctpMode(ssl)) { + ret = DtlsMsgPoolSend(ssl, 1); + if (ret != 0) + return ret; + } + + if (ssl->curSize != 1) { + WOLFSSL_MSG("Malicious or corrupted" + " duplicate ChangeCipher msg"); + return LENGTH_ERROR; + } + ssl->buffers.inputBuffer.idx++; + break; + #endif /* WOLFSSL_DTLS */ + } + } + + if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) { + ssl->buffers.inputBuffer.idx += ssl->keys.padSz; + ssl->curSize -= (word16) ssl->buffers.inputBuffer.idx; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + ssl->buffers.inputBuffer.idx += digestSz; + ssl->curSize -= digestSz; + } + #endif + } + + if (ssl->curSize != 1) { + WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg"); + return LENGTH_ERROR; + } + + ssl->buffers.inputBuffer.idx++; + ssl->keys.encryptionOn = 1; + + /* setup decrypt keys for following messages */ + /* XXX This might not be what we want to do when + * receiving a CCS with multicast. We update the + * key when the application updates them. */ + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + ssl->options.startedETMRead = ssl->options.encThenMac; + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + WOLFSSL_DTLS_PEERSEQ* peerSeq = ssl->keys.peerSeq; +#ifdef WOLFSSL_MULTICAST + if (ssl->options.haveMcast) { + peerSeq += ssl->keys.curPeerId; + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } +#endif + peerSeq->nextEpoch++; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, + DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); + } + #endif + + #ifdef HAVE_LIBZ + if (ssl->options.usingCompression) + if ( (ret = InitStreams(ssl)) != 0) + return ret; + #endif + ret = BuildFinished(ssl, &ssl->hsHashes->verifyHashes, + ssl->options.side == WOLFSSL_CLIENT_END ? + server : client); + if (ret != 0) + return ret; +#endif /* !WOLFSSL_NO_TLS12 */ + break; + + case application_data: + WOLFSSL_MSG("got app DATA"); + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls && ssl->options.dtlsHsRetain) { + FreeHandshakeResources(ssl); + ssl->options.dtlsHsRetain = 0; + } + #endif + #ifdef WOLFSSL_TLS13 + if (ssl->keys.keyUpdateRespond) { + WOLFSSL_MSG("No KeyUpdate from peer seen"); + return SANITY_MSG_E; + } + #endif + if ((ret = DoApplicationData(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx)) + != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + break; + + case alert: + WOLFSSL_MSG("got ALERT!"); + ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, &type, + ssl->buffers.inputBuffer.length); + if (ret == alert_fatal) + return FATAL_ERROR; + else if (ret < 0) + return ret; + + /* catch warnings that are handled as errors */ + if (type == close_notify) + return ssl->error = ZERO_RETURN; + + if (type == decrypt_error) + return FATAL_ERROR; + break; + + default: + WOLFSSL_ERROR(UNKNOWN_RECORD_TYPE); + return UNKNOWN_RECORD_TYPE; + } + + ssl->options.processReply = doProcessInit; + + /* input exhausted? */ + if (ssl->buffers.inputBuffer.idx >= ssl->buffers.inputBuffer.length) + return 0; + + /* more messages per record */ + else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) { + WOLFSSL_MSG("More messages in record"); + + ssl->options.processReply = runProcessingOneMessage; + + if (IsEncryptionOn(ssl, 0)) { + WOLFSSL_MSG("Bundled encrypted messages, remove middle pad"); + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + if (ssl->buffers.inputBuffer.idx >= + ssl->keys.padSz + digestSz) { + ssl->buffers.inputBuffer.idx -= + ssl->keys.padSz + digestSz; + } + else { + WOLFSSL_MSG("\tmiddle padding error"); + return FATAL_ERROR; + } + } + else + #endif + { + if (ssl->buffers.inputBuffer.idx >= ssl->keys.padSz) { + ssl->buffers.inputBuffer.idx -= ssl->keys.padSz; + } + else { + WOLFSSL_MSG("\tmiddle padding error"); + return FATAL_ERROR; + } + } + } + + continue; + } + /* more records */ + else { + WOLFSSL_MSG("More records in input"); + ssl->options.processReply = doProcessInit; + continue; + } + + default: + WOLFSSL_MSG("Bad process input state, programming error"); + return INPUT_CASE_ERROR; + } + } +} + + +int SendChangeCipher(WOLFSSL* ssl) +{ + byte *output; + int sendSz = RECORD_HEADER_SZ + ENUM_LEN; + int idx = RECORD_HEADER_SZ; + int ret; + + #ifdef OPENSSL_EXTRA + ssl->cbmode = SSL_CB_MODE_WRITE; + if (ssl->options.side == WOLFSSL_SERVER_END){ + ssl->options.serverState = SERVER_CHANGECIPHERSPEC_COMPLETE; + if (ssl->CBIS != NULL) + ssl->CBIS(ssl, SSL_CB_ACCEPT_LOOP, SSL_SUCCESS); + } + else{ + ssl->options.clientState = + CLIENT_CHANGECIPHERSPEC_COMPLETE; + if (ssl->CBIS != NULL) + ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS); + } + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + } + #endif + + /* are we in scr */ + if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) { + sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddRecordHeader(output, 1, change_cipher_spec, ssl); + + output[idx] = 1; /* turn it on */ + + if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) { + byte input[ENUM_LEN]; + int inputSz = ENUM_LEN; + + input[0] = 1; /* turn it on */ + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + change_cipher_spec, 0, 0, 0); + if (sendSz < 0) { + return sendSz; + } + } + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + DtlsSEQIncrement(ssl, CUR_ORDER); + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) AddPacketName(ssl, "ChangeCipher"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "ChangeCipher", change_cipher_spec, output, + sendSz, WRITE_PROTO, ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + + if (ssl->options.groupMessages) + return 0; + #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_DEBUG_DTLS) + else if (ssl->options.dtls) { + /* If using DTLS, force the ChangeCipherSpec message to be in the + * same datagram as the finished message. */ + return 0; + } + #endif + else + return SendBuffered(ssl); +} + + +#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_AEAD_ONLY) +static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, + int padLen, int content, int verify) +{ + byte result[WC_MAX_DIGEST_SIZE]; + word32 digestSz = ssl->specs.hash_size; /* actual sizes */ + word32 padSz = ssl->specs.pad_size; + int ret = 0; + + wc_Md5 md5; + wc_Sha sha; + + /* data */ + byte seq[SEQ_SZ]; + byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */ + const byte* macSecret = wolfSSL_GetMacSecret(ssl, verify); + + (void)padLen; + +#ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx); +#endif + + XMEMSET(seq, 0, SEQ_SZ); + conLen[0] = (byte)content; + c16toa((word16)sz, &conLen[ENUM_LEN]); + WriteSEQ(ssl, verify, seq); + + if (ssl->specs.mac_algorithm == md5_mac) { + ret = wc_InitMd5_ex(&md5, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + + /* inner */ + ret = wc_Md5Update(&md5, macSecret, digestSz); + ret |= wc_Md5Update(&md5, PAD1, padSz); + ret |= wc_Md5Update(&md5, seq, SEQ_SZ); + ret |= wc_Md5Update(&md5, conLen, sizeof(conLen)); + /* in buffer */ + ret |= wc_Md5Update(&md5, in, sz); + if (ret != 0) + return VERIFY_MAC_ERROR; + ret = wc_Md5Final(&md5, result); + #ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &md5.asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif + if (ret != 0) + return VERIFY_MAC_ERROR; + + /* outer */ + ret = wc_Md5Update(&md5, macSecret, digestSz); + ret |= wc_Md5Update(&md5, PAD2, padSz); + ret |= wc_Md5Update(&md5, result, digestSz); + if (ret != 0) + return VERIFY_MAC_ERROR; + ret = wc_Md5Final(&md5, digest); + #ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &md5.asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif + if (ret != 0) + return VERIFY_MAC_ERROR; + + wc_Md5Free(&md5); + } + else { + ret = wc_InitSha_ex(&sha, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + + /* inner */ + ret = wc_ShaUpdate(&sha, macSecret, digestSz); + ret |= wc_ShaUpdate(&sha, PAD1, padSz); + ret |= wc_ShaUpdate(&sha, seq, SEQ_SZ); + ret |= wc_ShaUpdate(&sha, conLen, sizeof(conLen)); + /* in buffer */ + ret |= wc_ShaUpdate(&sha, in, sz); + if (ret != 0) + return VERIFY_MAC_ERROR; + ret = wc_ShaFinal(&sha, result); + #ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &sha.asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif + if (ret != 0) + return VERIFY_MAC_ERROR; + + /* outer */ + ret = wc_ShaUpdate(&sha, macSecret, digestSz); + ret |= wc_ShaUpdate(&sha, PAD2, padSz); + ret |= wc_ShaUpdate(&sha, result, digestSz); + if (ret != 0) + return VERIFY_MAC_ERROR; + ret = wc_ShaFinal(&sha, digest); + #ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &sha.asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif + if (ret != 0) + return VERIFY_MAC_ERROR; + + wc_ShaFree(&sha); + } + return 0; +} +#endif /* !NO_OLD_TLS && !WOLFSSL_AEAD_ONLY */ + + +#ifndef NO_CERTS + +#if !defined(NO_MD5) && !defined(NO_OLD_TLS) +static int BuildMD5_CertVerify(WOLFSSL* ssl, byte* digest) +{ + int ret; + byte md5_result[WC_MD5_DIGEST_SIZE]; +#ifdef WOLFSSL_SMALL_STACK + wc_Md5* md5 = (wc_Md5*)XMALLOC(sizeof(wc_Md5), ssl->heap, DYNAMIC_TYPE_HASHCTX); +#else + wc_Md5 md5[1]; +#endif + + /* make md5 inner */ + ret = wc_Md5Copy(&ssl->hsHashes->hashMd5, md5); /* Save current position */ + if (ret == 0) + ret = wc_Md5Update(md5, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_Md5Update(md5, PAD1, PAD_MD5); + if (ret == 0) + ret = wc_Md5Final(md5, md5_result); + + /* make md5 outer */ + if (ret == 0) { + ret = wc_InitMd5_ex(md5, ssl->heap, ssl->devId); + if (ret == 0) { + ret = wc_Md5Update(md5, ssl->arrays->masterSecret, SECRET_LEN); + if (ret == 0) + ret = wc_Md5Update(md5, PAD2, PAD_MD5); + if (ret == 0) + ret = wc_Md5Update(md5, md5_result, WC_MD5_DIGEST_SIZE); + if (ret == 0) + ret = wc_Md5Final(md5, digest); + wc_Md5Free(md5); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(md5, ssl->heap, DYNAMIC_TYPE_HASHCTX); +#endif + + return ret; +} +#endif /* !NO_MD5 && !NO_OLD_TLS */ + +#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \ + defined(WOLFSSL_ALLOW_TLS_SHA1)) +static int BuildSHA_CertVerify(WOLFSSL* ssl, byte* digest) +{ + int ret; + byte sha_result[WC_SHA_DIGEST_SIZE]; +#ifdef WOLFSSL_SMALL_STACK + wc_Sha* sha = (wc_Sha*)XMALLOC(sizeof(wc_Sha), ssl->heap, DYNAMIC_TYPE_HASHCTX); +#else + wc_Sha sha[1]; +#endif + + /* make sha inner */ + ret = wc_ShaCopy(&ssl->hsHashes->hashSha, sha); /* Save current position */ + if (ret == 0) + ret = wc_ShaUpdate(sha, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_ShaUpdate(sha, PAD1, PAD_SHA); + if (ret == 0) + ret = wc_ShaFinal(sha, sha_result); + + /* make sha outer */ + if (ret == 0) { + ret = wc_InitSha_ex(sha, ssl->heap, ssl->devId); + if (ret == 0) { + ret = wc_ShaUpdate(sha, ssl->arrays->masterSecret,SECRET_LEN); + if (ret == 0) + ret = wc_ShaUpdate(sha, PAD2, PAD_SHA); + if (ret == 0) + ret = wc_ShaUpdate(sha, sha_result, WC_SHA_DIGEST_SIZE); + if (ret == 0) + ret = wc_ShaFinal(sha, digest); + wc_ShaFree(sha); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(sha, ssl->heap, DYNAMIC_TYPE_HASHCTX); +#endif + + return ret; +} +#endif /* !NO_SHA && (!NO_OLD_TLS || WOLFSSL_ALLOW_TLS_SHA1) */ + +int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes) +{ + int ret = 0; + + (void)hashes; + + if (ssl->options.tls) { + #if !defined(NO_MD5) && !defined(NO_OLD_TLS) + ret = wc_Md5GetHash(&ssl->hsHashes->hashMd5, hashes->md5); + if (ret != 0) + return ret; + #endif + #if !defined(NO_SHA) + ret = wc_ShaGetHash(&ssl->hsHashes->hashSha, hashes->sha); + if (ret != 0) + return ret; + #endif + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, + hashes->sha256); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA384 + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, + hashes->sha384); + if (ret != 0) + return ret; + #endif + #ifdef WOLFSSL_SHA512 + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, + hashes->sha512); + if (ret != 0) + return ret; + #endif + } + } + else { + #if !defined(NO_MD5) && !defined(NO_OLD_TLS) + ret = BuildMD5_CertVerify(ssl, hashes->md5); + if (ret != 0) + return ret; + #endif + #if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \ + defined(WOLFSSL_ALLOW_TLS_SHA1)) + ret = BuildSHA_CertVerify(ssl, hashes->sha); + if (ret != 0) + return ret; + #endif + } + + return ret; +} + +#endif /* !NO_CERTS */ + +#ifndef WOLFSSL_NO_TLS12 +/* Persistable BuildMessage arguments */ +typedef struct BuildMsgArgs { + word32 digestSz; + word32 sz; + word32 pad; + word32 idx; + word32 headerSz; + word16 size; + word32 ivSz; /* TLSv1.1 IV */ + byte* iv; +} BuildMsgArgs; + +static void FreeBuildMsgArgs(WOLFSSL* ssl, void* pArgs) +{ + BuildMsgArgs* args = (BuildMsgArgs*)pArgs; + + (void)ssl; + (void)args; + + if (args->iv) { + XFREE(args->iv, ssl->heap, DYNAMIC_TYPE_SALT); + args->iv = NULL; + } +} +#endif + +/* Build SSL Message, encrypted */ +int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, + int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay) +{ +#ifndef WOLFSSL_NO_TLS12 + int ret = 0; + BuildMsgArgs* args; + BuildMsgArgs lcl_args; +#ifdef WOLFSSL_ASYNC_CRYPT + args = (BuildMsgArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#endif +#endif + + WOLFSSL_ENTER("BuildMessage"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_NO_TLS12 + return BuildTls13Message(ssl, output, outSz, input, inSz, type, + hashOutput, sizeOnly, asyncOkay); +#else +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return BuildTls13Message(ssl, output, outSz, input, inSz, type, + hashOutput, sizeOnly, asyncOkay); + } +#endif + + ret = WC_NOT_PENDING_E; +#ifdef WOLFSSL_ASYNC_CRYPT + if (asyncOkay) { + ret = wolfSSL_AsyncPop(ssl, &ssl->options.buildMsgState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_buildmsg; + } + } + else +#endif + { + args = &lcl_args; + } + + /* Reset state */ + if (ret == WC_NOT_PENDING_E) { + ret = 0; + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + XMEMSET(args, 0, sizeof(BuildMsgArgs)); + + args->sz = RECORD_HEADER_SZ + inSz; + args->idx = RECORD_HEADER_SZ; + args->headerSz = RECORD_HEADER_SZ; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeBuildMsgArgs; + #endif + } + + switch (ssl->options.buildMsgState) { + case BUILD_MSG_BEGIN: + { + /* catch mistaken sizeOnly parameter */ + if (!sizeOnly && (output == NULL || input == NULL) ) { + ERROR_OUT(BAD_FUNC_ARG, exit_buildmsg); + } + if (sizeOnly && (output || input) ) { + WOLFSSL_MSG("BuildMessage w/sizeOnly doesn't need input/output"); + ERROR_OUT(BAD_FUNC_ARG, exit_buildmsg); + } + + ssl->options.buildMsgState = BUILD_MSG_SIZE; + } + FALL_THROUGH; + case BUILD_MSG_SIZE: + { + args->digestSz = ssl->specs.hash_size; + #ifdef HAVE_TRUNCATED_HMAC + if (ssl->truncated_hmac) + args->digestSz = min(TRUNCATED_HMAC_SZ, args->digestSz); + #endif + args->sz += args->digestSz; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sz += DTLS_RECORD_EXTRA; + args->idx += DTLS_RECORD_EXTRA; + args->headerSz += DTLS_RECORD_EXTRA; + } + #endif + + #ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) { + word32 blockSz = ssl->specs.block_size; + if (ssl->options.tls1_1) { + args->ivSz = blockSz; + args->sz += args->ivSz; + + if (args->ivSz > MAX_IV_SZ) + ERROR_OUT(BUFFER_E, exit_buildmsg); + } + args->sz += 1; /* pad byte */ + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMWrite) { + args->pad = (args->sz - args->headerSz - + args->digestSz) % blockSz; + } + else + #endif + args->pad = (args->sz - args->headerSz) % blockSz; + #ifdef OPENSSL_EXTRA + if(args->pad != 0) + #endif + args->pad = blockSz - args->pad; + args->sz += args->pad; + } + #endif /* WOLFSSL_AEAD_ONLY */ + + #ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha) + args->ivSz = AESGCM_EXP_IV_SZ; + + args->sz += (args->ivSz + ssl->specs.aead_mac_size - args->digestSz); + } + #endif + + /* done with size calculations */ + if (sizeOnly) + goto exit_buildmsg; + + if (args->sz > (word32)outSz) { + WOLFSSL_MSG("Oops, want to write past output buffer size"); + ERROR_OUT(BUFFER_E, exit_buildmsg); + } + + if (args->ivSz > 0) { + args->iv = (byte*)XMALLOC(args->ivSz, ssl->heap, DYNAMIC_TYPE_SALT); + if (args->iv == NULL) + ERROR_OUT(MEMORY_E, exit_buildmsg); + + ret = wc_RNG_GenerateBlock(ssl->rng, args->iv, args->ivSz); + if (ret != 0) + goto exit_buildmsg; + + } +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)) && \ + defined(HAVE_AEAD)) + if (ssl->specs.cipher_type == aead) { + if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha) + XMEMCPY(args->iv, ssl->keys.aead_exp_IV, AESGCM_EXP_IV_SZ); + } +#endif + + args->size = (word16)(args->sz - args->headerSz); /* include mac and digest */ + AddRecordHeader(output, args->size, (byte)type, ssl); + + /* write to output */ + if (args->ivSz > 0) { + XMEMCPY(output + args->idx, args->iv, + min(args->ivSz, MAX_IV_SZ)); + args->idx += args->ivSz; + } + XMEMCPY(output + args->idx, input, inSz); + args->idx += inSz; + + ssl->options.buildMsgState = BUILD_MSG_HASH; + } + FALL_THROUGH; + case BUILD_MSG_HASH: + { + if (type == handshake && hashOutput) { + ret = HashOutput(ssl, output, args->headerSz + inSz, args->ivSz); + if (ret != 0) + goto exit_buildmsg; + } + #ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) { + word32 tmpIdx; + word32 i; + + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMWrite) + tmpIdx = args->idx; + else + #endif + tmpIdx = args->idx + args->digestSz; + + for (i = 0; i <= args->pad; i++) + output[tmpIdx++] = (byte)args->pad; /* pad byte gets pad value */ + } + #endif + + ssl->options.buildMsgState = BUILD_MSG_VERIFY_MAC; + } + FALL_THROUGH; + case BUILD_MSG_VERIFY_MAC: + { + /* User Record Layer Callback handling */ + #ifdef ATOMIC_USER + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMWrite) { + if (ssl->ctx->EncryptMacCb) { + ret = ssl->ctx->EncryptMacCb(ssl, output + args->idx + + args->pad + 1, type, 0, + output + args->headerSz, + output + args->headerSz, + args->size - args->digestSz, + ssl->MacEncryptCtx); + goto exit_buildmsg; + } + } + else + #endif + { + if (ssl->ctx->MacEncryptCb) { + ret = ssl->ctx->MacEncryptCb(ssl, output + args->idx, + output + args->headerSz + args->ivSz, inSz, + type, 0, output + args->headerSz, + output + args->headerSz, args->size, + ssl->MacEncryptCtx); + goto exit_buildmsg; + } + } + #endif + + #ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type != aead + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + && !ssl->options.startedETMWrite + #endif + ) { + #ifdef HAVE_TRUNCATED_HMAC + if (ssl->truncated_hmac && + ssl->specs.hash_size > args->digestSz) { + #ifdef WOLFSSL_SMALL_STACK + byte* hmac; + #else + byte hmac[WC_MAX_DIGEST_SIZE]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + hmac = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, ssl->heap, + DYNAMIC_TYPE_DIGEST); + if (hmac == NULL) + ERROR_OUT(MEMORY_E, exit_buildmsg); + #endif + + ret = ssl->hmac(ssl, hmac, + output + args->headerSz + args->ivSz, inSz, + -1, type, 0); + XMEMCPY(output + args->idx, hmac, args->digestSz); + + #ifdef WOLFSSL_SMALL_STACK + XFREE(hmac, ssl->heap, DYNAMIC_TYPE_DIGEST); + #endif + } + else + #endif + { + ret = ssl->hmac(ssl, output + args->idx, output + + args->headerSz + args->ivSz, inSz, -1, type, 0); + } + } + #endif /* WOLFSSL_AEAD_ONLY */ + if (ret != 0) + goto exit_buildmsg; + + ssl->options.buildMsgState = BUILD_MSG_ENCRYPT; + } + FALL_THROUGH; + case BUILD_MSG_ENCRYPT: + { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMWrite) { + ret = Encrypt(ssl, output + args->headerSz, + output + args->headerSz, + args->size - args->digestSz, asyncOkay); + } + else + #endif + { + ret = Encrypt(ssl, output + args->headerSz, + output + args->headerSz, args->size, asyncOkay); + } + if (ret != 0) + goto exit_buildmsg; + ssl->options.buildMsgState = BUILD_MSG_ENCRYPTED_VERIFY_MAC; + } + FALL_THROUGH; + case BUILD_MSG_ENCRYPTED_VERIFY_MAC: + { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMWrite) { + WOLFSSL_MSG("Calculate MAC of Encrypted Data"); + + #ifdef HAVE_TRUNCATED_HMAC + if (ssl->truncated_hmac && + ssl->specs.hash_size > args->digestSz) { + #ifdef WOLFSSL_SMALL_STACK + byte* hmac = NULL; + #else + byte hmac[WC_MAX_DIGEST_SIZE]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + hmac = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, ssl->heap, + DYNAMIC_TYPE_DIGEST); + if (hmac == NULL) + ERROR_OUT(MEMORY_E, exit_buildmsg); + #endif + + ret = ssl->hmac(ssl, hmac, output + args->headerSz, + args->ivSz + inSz + args->pad + 1, -1, type, + 0); + XMEMCPY(output + args->idx + args->pad + 1, hmac, + args->digestSz); + + #ifdef WOLFSSL_SMALL_STACK + XFREE(hmac, ssl->heap, DYNAMIC_TYPE_DIGEST); + #endif + } + else + #endif + { + ret = ssl->hmac(ssl, output + args->idx + args->pad + 1, + output + args->headerSz, + args->ivSz + inSz + args->pad + 1, -1, type, + 0); + } + } + #endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ + } + } + +exit_buildmsg: + + WOLFSSL_LEAVE("BuildMessage", ret); + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + return ret; + } +#endif + + /* make sure build message state is reset */ + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + + #ifdef WOLFSSL_DTLS + if (ret == 0 && ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + + /* return sz on success */ + if (ret == 0) + ret = args->sz; + + /* Final cleanup */ + FreeBuildMsgArgs(ssl, args); +#ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = NULL; +#endif + + return ret; +#endif /* !WOLFSSL_NO_TLS12 */ +} + +#ifndef WOLFSSL_NO_TLS12 + +int SendFinished(WOLFSSL* ssl) +{ + int sendSz, + finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : + FINISHED_SZ; + byte input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ]; /* max */ + byte *output; + Hashes* hashes; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + + WOLFSSL_START(WC_FUNC_FINISHED_SEND); + WOLFSSL_ENTER("SendFinished"); + + /* setup encrypt keys */ + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + ssl->options.startedETMWrite = ssl->options.encThenMac; + #endif + + /* check for available size */ + outputSz = sizeof(input) + MAX_MSG_EXTRA; + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + headerSz += DTLS_HANDSHAKE_EXTRA; + ssl->keys.dtls_epoch++; + ssl->keys.dtls_prev_sequence_number_hi = + ssl->keys.dtls_sequence_number_hi; + ssl->keys.dtls_prev_sequence_number_lo = + ssl->keys.dtls_sequence_number_lo; + ssl->keys.dtls_sequence_number_hi = 0; + ssl->keys.dtls_sequence_number_lo = 0; + } + #endif + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl); + + /* make finished hashes */ + hashes = (Hashes*)&input[headerSz]; + ret = BuildFinished(ssl, hashes, + ssl->options.side == WOLFSSL_CLIENT_END ? client : server); + if (ret != 0) return ret; + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation) { + if (ssl->options.side == WOLFSSL_CLIENT_END) + XMEMCPY(ssl->secure_renegotiation->client_verify_data, hashes, + TLS_FINISHED_SZ); + else + XMEMCPY(ssl->secure_renegotiation->server_verify_data, hashes, + TLS_FINISHED_SZ); + } +#endif + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, input, headerSz + finishedSz)) != 0) + return ret; + } + #endif + + sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz, + handshake, 1, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + + if (!ssl->options.resuming) { +#ifndef NO_SESSION_CACHE + AddSession(ssl); /* just try */ +#endif + if (ssl->options.side == WOLFSSL_SERVER_END) { + #ifdef OPENSSL_EXTRA + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->cbmode = SSL_CB_MODE_WRITE; + if (ssl->CBIS != NULL) + ssl->CBIS(ssl, SSL_CB_HANDSHAKE_DONE, SSL_SUCCESS); + #endif + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } + else { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + #ifdef OPENSSL_EXTRA + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->cbmode = SSL_CB_MODE_WRITE; + if (ssl->CBIS != NULL) + ssl->CBIS(ssl, SSL_CB_HANDSHAKE_DONE, SSL_SUCCESS); + #endif + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "Finished", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendFinished", ret); + WOLFSSL_END(WC_FUNC_FINISHED_SEND); + + return ret; +} +#endif /* WOLFSSL_NO_TLS12 */ + +#ifndef NO_WOLFSSL_SERVER +#if (!defined(WOLFSSL_NO_TLS12) && \ + (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_CERTIFICATE_STATUS_REQUEST)) +/* Parses and decodes the certificate then initializes "request". In the case + * of !ssl->buffers.weOwnCert, ssl->ctx->certOcspRequest gets set to "request". + * + * Returns 0 on success + */ +static int CreateOcspRequest(WOLFSSL* ssl, OcspRequest* request, + DecodedCert* cert, byte* certData, word32 length) +{ + int ret; + + if (request != NULL) + XMEMSET(request, 0, sizeof(OcspRequest)); + + InitDecodedCert(cert, certData, length, ssl->heap); + /* TODO: Setup async support here */ + ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, ssl->ctx->cm); + if (ret != 0) { + WOLFSSL_MSG("ParseCert failed"); + } + if (ret == 0) + ret = InitOcspRequest(request, cert, 0, ssl->heap); + if (ret == 0) { + /* make sure ctx OCSP request is updated */ + if (!ssl->buffers.weOwnCert) { + wolfSSL_Mutex* ocspLock = &ssl->ctx->cm->ocsp_stapling->ocspLock; + if (wc_LockMutex(ocspLock) == 0) { + if (ssl->ctx->certOcspRequest == NULL) + ssl->ctx->certOcspRequest = request; + wc_UnLockMutex(ocspLock); + } + } + } + + FreeDecodedCert(cert); + + return ret; +} + + +/* Creates OCSP response and places it in variable "response". Memory + * management for "buffer* response" is up to the caller. + * + * Also creates an OcspRequest in the case that ocspRequest is null or that + * ssl->buffers.weOwnCert is set. In those cases managing ocspRequest free'ing + * is up to the caller. NOTE: in OcspCreateRequest ssl->ctx->certOcspRequest can + * be set to point to "ocspRequest" and it then should not be free'd since + * wolfSSL_CTX_free will take care of it. + * + * Returns 0 on success + */ +int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest, + buffer* response) +{ + int ret = 0; + OcspRequest* request = NULL; + byte createdRequest = 0; + + if (ssl == NULL || ocspRequest == NULL || response == NULL) + return BAD_FUNC_ARG; + + XMEMSET(response, 0, sizeof(*response)); + request = *ocspRequest; + + /* unable to fetch status. skip. */ + if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0) + return 0; + + if (request == NULL || ssl->buffers.weOwnCert) { + DerBuffer* der = ssl->buffers.certificate; + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; + #else + DecodedCert cert[1]; + #endif + + /* unable to fetch status. skip. */ + if (der->buffer == NULL || der->length == 0) + return 0; + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; + #endif + request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), ssl->heap, + DYNAMIC_TYPE_OCSP_REQUEST); + if (request == NULL) + ret = MEMORY_E; + + createdRequest = 1; + if (ret == 0) { + ret = CreateOcspRequest(ssl, request, cert, der->buffer, + der->length); + } + + if (ret != 0) { + XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + request = NULL; + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT); + #endif + } + + if (ret == 0) { + request->ssl = ssl; + ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request, response); + + /* Suppressing, not critical */ + if (ret == OCSP_CERT_REVOKED || + ret == OCSP_CERT_UNKNOWN || + ret == OCSP_LOOKUP_FAIL) { + ret = 0; + } + } + + /* free request up if error case found otherwise return it */ + if (ret != 0 && createdRequest) { + FreeOcspRequest(request); + XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + } + + if (ret == 0) + *ocspRequest = request; + + return ret; +} +#endif +#endif /* !NO_WOLFSSL_SERVER */ + +#ifndef WOLFSSL_NO_TLS12 + +#ifndef NO_CERTS +#if !defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH) +/* handle generation of certificate (11) */ +int SendCertificate(WOLFSSL* ssl) +{ + int ret = 0; + word32 certSz, certChainSz, headerSz, listSz, payloadSz; + word32 length, maxFragment; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_SEND); + WOLFSSL_ENTER("SendCertificate"); + + if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) + return 0; /* not needed */ + + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + #ifdef OPENSSL_EXTRA + if (ssl->version.major == SSLv3_MAJOR + && ssl->version.minor == SSLv3_MINOR){ + SendAlert(ssl, alert_warning, no_certificate); + return 0; + } else { + #endif + certSz = 0; + certChainSz = 0; + headerSz = CERT_HEADER_SZ; + length = CERT_HEADER_SZ; + listSz = 0; + #ifdef OPENSSL_EXTRA + } + #endif + } + else { + if (!ssl->buffers.certificate) { + WOLFSSL_MSG("Send Cert missing certificate buffer"); + return BUFFER_ERROR; + } + certSz = ssl->buffers.certificate->length; + headerSz = 2 * CERT_HEADER_SZ; + /* list + cert size */ + length = certSz + headerSz; + listSz = certSz + CERT_HEADER_SZ; + + /* may need to send rest of chain, already has leading size(s) */ + if (certSz && ssl->buffers.certChain) { + certChainSz = ssl->buffers.certChain->length; + length += certChainSz; + listSz += certChainSz; + } + else + certChainSz = 0; + } + + payloadSz = length; + + if (ssl->fragOffset != 0) + length -= (ssl->fragOffset + headerSz); + + maxFragment = MAX_RECORD_SIZE; + + if (ssl->options.dtls) { + #ifdef WOLFSSL_DTLS + /* The 100 bytes is used to account for the UDP and IP headers. + It can also include the record padding and MAC if the + SendCertificate is called for a secure renegotiation. */ + maxFragment = MAX_MTU - DTLS_RECORD_HEADER_SZ + - DTLS_HANDSHAKE_HEADER_SZ - 100; + #endif /* WOLFSSL_DTLS */ + } + + maxFragment = wolfSSL_GetMaxRecordSize(ssl, maxFragment); + + while (length > 0 && ret == 0) { + byte* output = NULL; + word32 fragSz = 0; + word32 i = RECORD_HEADER_SZ; + int sendSz = RECORD_HEADER_SZ; + + if (!ssl->options.dtls) { + if (ssl->fragOffset == 0) { + if (headerSz + certSz + certChainSz <= + maxFragment - HANDSHAKE_HEADER_SZ) { + + fragSz = headerSz + certSz + certChainSz; + } + else { + fragSz = maxFragment - HANDSHAKE_HEADER_SZ; + } + sendSz += fragSz + HANDSHAKE_HEADER_SZ; + i += HANDSHAKE_HEADER_SZ; + } + else { + fragSz = min(length, maxFragment); + sendSz += fragSz; + } + + if (IsEncryptionOn(ssl, 1)) + sendSz += MAX_MSG_EXTRA; + } + else { + #ifdef WOLFSSL_DTLS + fragSz = min(length, maxFragment); + sendSz += fragSz + DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA + + HANDSHAKE_HEADER_SZ; + i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA + + HANDSHAKE_HEADER_SZ; + #endif + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + if (ssl->fragOffset == 0) { + if (!ssl->options.dtls) { + AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); + if (!IsEncryptionOn(ssl, 1)) + HashOutputRaw(ssl, output + RECORD_HEADER_SZ, + HANDSHAKE_HEADER_SZ); + } + else { + #ifdef WOLFSSL_DTLS + AddHeaders(output, payloadSz, certificate, ssl); + if (!IsEncryptionOn(ssl, 1)) + HashOutputRaw(ssl, + output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA, + HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA); + /* Adding the headers increments these, decrement them for + * actual message header. */ + ssl->keys.dtls_handshake_number--; + AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); + ssl->keys.dtls_handshake_number--; + #endif /* WOLFSSL_DTLS */ + } + + /* list total */ + c32to24(listSz, output + i); + if (!IsEncryptionOn(ssl, 1)) + HashOutputRaw(ssl, output + i, CERT_HEADER_SZ); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + if (certSz) { + c32to24(certSz, output + i); + if (!IsEncryptionOn(ssl, 1)) + HashOutputRaw(ssl, output + i, CERT_HEADER_SZ); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + + if (!IsEncryptionOn(ssl, 1)) { + HashOutputRaw(ssl, ssl->buffers.certificate->buffer, certSz); + if (certChainSz) + HashOutputRaw(ssl, ssl->buffers.certChain->buffer, + certChainSz); + } + } + } + else { + if (!ssl->options.dtls) { + AddRecordHeader(output, fragSz, handshake, ssl); + } + else { + #ifdef WOLFSSL_DTLS + AddFragHeaders(output, fragSz, ssl->fragOffset + headerSz, + payloadSz, certificate, ssl); + ssl->keys.dtls_handshake_number--; + #endif /* WOLFSSL_DTLS */ + } + } + + /* member */ + if (certSz && ssl->fragOffset < certSz) { + word32 copySz = min(certSz - ssl->fragOffset, fragSz); + XMEMCPY(output + i, + ssl->buffers.certificate->buffer + ssl->fragOffset, copySz); + i += copySz; + ssl->fragOffset += copySz; + length -= copySz; + fragSz -= copySz; + } + if (certChainSz && fragSz) { + word32 copySz = min(certChainSz + certSz - ssl->fragOffset, fragSz); + XMEMCPY(output + i, + ssl->buffers.certChain->buffer + ssl->fragOffset - certSz, + copySz); + i += copySz; + ssl->fragOffset += copySz; + length -= copySz; + } + + if (IsEncryptionOn(ssl, 1)) { + byte* input = NULL; + int inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */ + + if (inputSz < 0) { + WOLFSSL_MSG("Send Cert bad inputSz"); + return BUFFER_E; + } + + if (inputSz > 0) { /* clang thinks could be zero, let's help */ + input = (byte*)XMALLOC(inputSz, ssl->heap, + DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + } + + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + + if (inputSz > 0) + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } + else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + } + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "Certificate"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "Certificate", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + } + + if (ret != WANT_WRITE) { + /* Clean up the fragment offset. */ + ssl->fragOffset = 0; + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + ssl->keys.dtls_handshake_number++; + #endif + if (ssl->options.side == WOLFSSL_SERVER_END){ + ssl->options.serverState = SERVER_CERT_COMPLETE; + } + } + + WOLFSSL_LEAVE("SendCertificate", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_SEND); + + return ret; +} +#endif /* !NO_WOLFSSL_SERVER || !WOLFSSL_NO_CLIENT_AUTH */ + +/* handle generation of certificate_request (13) */ +int SendCertificateRequest(WOLFSSL* ssl) +{ + byte *output; + int ret; + int sendSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 dnLen = 0; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names; +#endif + + int typeTotal = 1; /* only 1 for now */ + int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + + WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND); + WOLFSSL_ENTER("SendCertificateRequest"); + + if (IsAtLeastTLSv1_2(ssl)) + reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + /* Certificate Authorities */ + names = ssl->ctx->ca_names; + while (names != NULL) { + byte seq[MAX_SEQ_SZ]; + + /* 16-bit length | SEQ | Len | DER of name */ + dnLen += OPAQUE16_LEN + SetSequence(names->data.name->rawLen, seq) + + names->data.name->rawLen; + names = names->next; + } + reqSz += dnLen; +#endif + + if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) + return 0; /* not needed */ + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + + if (!ssl->options.dtls) { + if (IsEncryptionOn(ssl, 1)) + sendSz += MAX_MSG_EXTRA; + } + else { + #ifdef WOLFSSL_DTLS + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + } + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, reqSz, certificate_request, ssl); + + /* write to output */ + output[i++] = (byte)typeTotal; /* # of types */ +#ifdef HAVE_ECC + if ((ssl->options.cipherSuite0 == ECC_BYTE || + ssl->options.cipherSuite0 == CHACHA_BYTE) && + ssl->specs.sig_algo == ecc_dsa_sa_algo) { + output[i++] = ecdsa_sign; + } else +#endif /* HAVE_ECC */ + { + output[i++] = rsa_sign; + } + + /* supported hash/sig */ + if (IsAtLeastTLSv1_2(ssl)) { + c16toa(ssl->suites->hashSigAlgoSz, &output[i]); + i += OPAQUE16_LEN; + + XMEMCPY(&output[i], + ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz); + i += ssl->suites->hashSigAlgoSz; + } + + /* Certificate Authorities */ + c16toa((word16)dnLen, &output[i]); /* auth's */ + i += REQ_HEADER_SZ; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + names = ssl->ctx->ca_names; + while (names != NULL) { + byte seq[MAX_SEQ_SZ]; + + c16toa((word16)names->data.name->rawLen + + SetSequence(names->data.name->rawLen, seq), &output[i]); + i += OPAQUE16_LEN; + i += SetSequence(names->data.name->rawLen, output + i); + XMEMCPY(output + i, names->data.name->raw, names->data.name->rawLen); + i += names->data.name->rawLen; + names = names->next; + } +#endif + (void)i; + + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */ + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + } + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateRequest"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "CertificateRequest", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + ret = 0; + else + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendCertificateRequest", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_SEND); + + return ret; +} + +#ifndef NO_WOLFSSL_SERVER +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +static int BuildCertificateStatus(WOLFSSL* ssl, byte type, buffer* status, + byte count) +{ + byte* output = NULL; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 length = ENUM_LEN; + int sendSz = 0; + int ret = 0; + int i = 0; + + WOLFSSL_ENTER("BuildCertificateStatus"); + + switch (type) { + case WOLFSSL_CSR2_OCSP_MULTI: + length += OPAQUE24_LEN; + FALL_THROUGH; /* followed by */ + + case WOLFSSL_CSR2_OCSP: + for (i = 0; i < count; i++) + length += OPAQUE24_LEN + status[i].length; + break; + + default: + return 0; + } + + sendSz = idx + length; + + if (ssl->keys.encryptionOn) + sendSz += MAX_MSG_EXTRA; + + if ((ret = CheckAvailableSize(ssl, sendSz)) == 0) { + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, certificate_status, ssl); + + output[idx++] = type; + + if (type == WOLFSSL_CSR2_OCSP_MULTI) { + c32to24(length - (ENUM_LEN + OPAQUE24_LEN), output + idx); + idx += OPAQUE24_LEN; + } + + for (i = 0; i < count; i++) { + c32to24(status[i].length, output + idx); + idx += OPAQUE24_LEN; + + XMEMCPY(output + idx, status[i].buffer, status[i].length); + idx += status[i].length; + } + + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = idx - RECORD_HEADER_SZ; + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + ret = sendSz; + } + else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + ret = HashOutput(ssl, output, sendSz, 0); + } + + #ifdef WOLFSSL_DTLS + if (ret == 0 && IsDtlsNotSctpMode(ssl)) + ret = DtlsMsgPoolSave(ssl, output, sendSz); + #endif + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ret == 0 && ssl->hsInfoOn) + AddPacketName(ssl, "CertificateStatus"); + if (ret == 0 && ssl->toInfoOn) + AddPacketInfo(ssl, "CertificateStatus", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + #endif + + if (ret == 0) { + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + } + } + + WOLFSSL_LEAVE("BuildCertificateStatus", ret); + return ret; +} +#endif +#endif /* NO_WOLFSSL_SERVER */ + +/* handle generation of certificate_status (22) */ +int SendCertificateStatus(WOLFSSL* ssl) +{ + int ret = 0; + byte status_type = 0; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_STATUS_SEND); + WOLFSSL_ENTER("SendCertificateStatus"); + + (void) ssl; + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + status_type = ssl->status_request; +#endif + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + status_type = status_type ? status_type : ssl->status_request_v2; +#endif + + switch (status_type) { + + #ifndef NO_WOLFSSL_SERVER + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + /* case WOLFSSL_CSR_OCSP: */ + case WOLFSSL_CSR2_OCSP: + { + OcspRequest* request = ssl->ctx->certOcspRequest; + buffer response; + + ret = CreateOcspResponse(ssl, &request, &response); + + /* if a request was successfully created and not stored in + * ssl->ctx then free it */ + if (ret == 0 && request != ssl->ctx->certOcspRequest) { + FreeOcspRequest(request); + XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + request = NULL; + } + + if (ret == 0 && response.buffer) { + ret = BuildCertificateStatus(ssl, status_type, &response, 1); + + XFREE(response.buffer, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + response.buffer = NULL; + } + break; + } + + #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + + #if defined HAVE_CERTIFICATE_STATUS_REQUEST_V2 + case WOLFSSL_CSR2_OCSP_MULTI: + { + OcspRequest* request = ssl->ctx->certOcspRequest; + buffer responses[1 + MAX_CHAIN_DEPTH]; + int i = 0; + + XMEMSET(responses, 0, sizeof(responses)); + + ret = CreateOcspResponse(ssl, &request, &responses[0]); + + /* if a request was successfully created and not stored in + * ssl->ctx then free it */ + if (ret == 0 && request != ssl->ctx->certOcspRequest) { + FreeOcspRequest(request); + XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + request = NULL; + } + + if (ret == 0 && (!ssl->ctx->chainOcspRequest[0] + || ssl->buffers.weOwnCertChain)) { + buffer der; + word32 idx = 0; + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; + #endif + request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), ssl->heap, + DYNAMIC_TYPE_OCSP_REQUEST); + if (request == NULL) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT); + #endif + return MEMORY_E; + } + + while (idx + OPAQUE24_LEN < ssl->buffers.certChain->length) { + c24to32(ssl->buffers.certChain->buffer + idx, &der.length); + idx += OPAQUE24_LEN; + + der.buffer = ssl->buffers.certChain->buffer + idx; + idx += der.length; + + if (idx > ssl->buffers.certChain->length) + break; + + ret = CreateOcspRequest(ssl, request, cert, der.buffer, + der.length); + if (ret == 0) { + request->ssl = ssl; + ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, + request, &responses[i + 1]); + + /* Suppressing, not critical */ + if (ret == OCSP_CERT_REVOKED || + ret == OCSP_CERT_UNKNOWN || + ret == OCSP_LOOKUP_FAIL) { + ret = 0; + } + + + i++; + FreeOcspRequest(request); + } + } + + XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT); + #endif + } + else { + while (ret == 0 && + NULL != (request = ssl->ctx->chainOcspRequest[i])) { + request->ssl = ssl; + ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, + request, &responses[++i]); + + /* Suppressing, not critical */ + if (ret == OCSP_CERT_REVOKED || + ret == OCSP_CERT_UNKNOWN || + ret == OCSP_LOOKUP_FAIL) { + ret = 0; + } + } + } + + if (responses[0].buffer) { + if (ret == 0) { + ret = BuildCertificateStatus(ssl, status_type, responses, + (byte)i + 1); + } + + for (i = 0; i < 1 + MAX_CHAIN_DEPTH; i++) { + if (responses[i].buffer) { + XFREE(responses[i].buffer, ssl->heap, + DYNAMIC_TYPE_OCSP_REQUEST); + } + } + } + + break; + } + #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + #endif /* NO_WOLFSSL_SERVER */ + + default: + break; + } + + WOLFSSL_LEAVE("SendCertificateStatus", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_STATUS_SEND); + + return ret; +} + +#endif /* !NO_CERTS */ + +#endif /* WOLFSSL_NO_TLS12 */ + + +/* If secure renegotiation is disabled, this will always return false. + * Otherwise it checks to see if we are currently renegotiating. */ +static WC_INLINE int IsSCR(WOLFSSL* ssl) +{ +#ifndef HAVE_SECURE_RENEGOTIATION + (void)ssl; +#else /* HAVE_SECURE_RENEGOTIATION */ + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->enabled && + ssl->options.handShakeState != HANDSHAKE_DONE) + return 1; +#endif /* HAVE_SECURE_RENEGOTIATION */ + return 0; +} + + +int SendData(WOLFSSL* ssl, const void* data, int sz) +{ + int sent = 0, /* plainText size */ + sendSz, + ret, + dtlsExtra = 0; + int groupMsgs = 0; + + if (ssl->error == WANT_WRITE + #ifdef WOLFSSL_ASYNC_CRYPT + || ssl->error == WC_PENDING_E + #endif + ) { + ssl->error = 0; + } + + /* don't allow write after decrypt or mac error */ + if (ssl->error == VERIFY_MAC_ERROR || ssl->error == DECRYPT_ERROR) { + /* For DTLS allow these possible errors and allow the session + to continue despite them */ + if (ssl->options.dtls) { + ssl->error = 0; + } + else { + WOLFSSL_MSG("Not allowing write after decrypt or mac error"); + return WOLFSSL_FATAL_ERROR; + } + } + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + if (ssl->options.handShakeState == HANDSHAKE_DONE) { + WOLFSSL_MSG("handshake complete, trying to send early data"); + return BUILD_MSG_ERROR; + } + #ifdef WOLFSSL_EARLY_DATA_GROUP + groupMsgs = 1; + #endif + } + else +#endif + if (ssl->options.handShakeState != HANDSHAKE_DONE && !IsSCR(ssl)) { + int err; + WOLFSSL_MSG("handshake not complete, trying to finish"); + if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) { + #ifdef WOLFSSL_ASYNC_CRYPT + /* if async would block return WANT_WRITE */ + if (ssl->error == WC_PENDING_E) { + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + #endif + return err; + } + } + + /* last time system socket output buffer was full, try again to send */ + if (!groupMsgs && ssl->buffers.outputBuffer.length > 0) { + WOLFSSL_MSG("output buffer was full, trying to send again"); + if ( (ssl->error = SendBuffered(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + if (ssl->error == SOCKET_ERROR_E && (ssl->options.connReset || + ssl->options.isClosed)) { + ssl->error = SOCKET_PEER_CLOSED_E; + WOLFSSL_ERROR(ssl->error); + return 0; /* peer reset or closed */ + } + return ssl->error; + } + else { + /* advance sent to previous sent + plain size just sent */ + sent = ssl->buffers.prevSent + ssl->buffers.plainSz; + WOLFSSL_MSG("sent write buffered data"); + + if (sent > sz) { + WOLFSSL_MSG("error: write() after WANT_WRITE with short size"); + return ssl->error = BAD_FUNC_ARG; + } + } + } + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + dtlsExtra = DTLS_RECORD_EXTRA; + } +#endif + + for (;;) { + int len; + byte* out; + byte* sendBuffer = (byte*)data + sent; /* may switch on comp */ + int buffSz; /* may switch on comp */ + int outputSz; +#ifdef HAVE_LIBZ + byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + + if (sent == sz) break; + + len = wolfSSL_GetMaxRecordSize(ssl, sz - sent); + +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + len = min(len, MAX_UDP_SIZE); + } +#endif + buffSz = len; + + /* check for available size */ + outputSz = len + COMP_EXTRA + dtlsExtra + MAX_MSG_EXTRA; + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ssl->error = ret; + + /* get output buffer */ + out = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + +#ifdef HAVE_LIBZ + if (ssl->options.usingCompression) { + buffSz = myCompress(ssl, sendBuffer, buffSz, comp, sizeof(comp)); + if (buffSz < 0) { + return buffSz; + } + sendBuffer = comp; + } +#endif + if (!ssl->options.tls1_3) { + sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz, + application_data, 0, 0, 1); + } + else { +#ifdef WOLFSSL_TLS13 + sendSz = BuildTls13Message(ssl, out, outputSz, sendBuffer, buffSz, + application_data, 0, 0, 1); +#else + sendSz = BUFFER_ERROR; +#endif + } + if (sendSz < 0) { + #ifdef WOLFSSL_ASYNC_CRYPT + if (sendSz == WC_PENDING_E) + ssl->error = sendSz; + #endif + return BUILD_MSG_ERROR; + } + + ssl->buffers.outputBuffer.length += sendSz; + + if ( (ssl->error = SendBuffered(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + /* store for next call if WANT_WRITE or user embedSend() that + doesn't present like WANT_WRITE */ + ssl->buffers.plainSz = len; + ssl->buffers.prevSent = sent; + if (ssl->error == SOCKET_ERROR_E && (ssl->options.connReset || + ssl->options.isClosed)) { + ssl->error = SOCKET_PEER_CLOSED_E; + WOLFSSL_ERROR(ssl->error); + return 0; /* peer reset or closed */ + } + return ssl->error; + } + + sent += len; + + /* only one message per attempt */ + if (ssl->options.partialWrite == 1) { + WOLFSSL_MSG("Partial Write on, only sending one record"); + break; + } + } + + return sent; +} + +/* process input data */ +int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) +{ + int size; + + WOLFSSL_ENTER("ReceiveData()"); + + /* reset error state */ + if (ssl->error == WANT_READ + #ifdef WOLFSSL_ASYNC_CRYPT + || ssl->error == WC_PENDING_E + #endif + ) { + ssl->error = 0; + } + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + /* In DTLS mode, we forgive some errors and allow the session + * to continue despite them. */ + if (ssl->error == VERIFY_MAC_ERROR || ssl->error == DECRYPT_ERROR) + ssl->error = 0; + } +#endif /* WOLFSSL_DTLS */ + + if (ssl->error != 0 && ssl->error != WANT_WRITE) { + WOLFSSL_MSG("User calling wolfSSL_read in error state, not allowed"); + return ssl->error; + } + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + } + else +#endif + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + WOLFSSL_MSG("Handshake not complete, trying to finish"); + if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) { + #ifdef WOLFSSL_ASYNC_CRYPT + /* if async would block return WANT_WRITE */ + if (ssl->error == WC_PENDING_E) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + #endif + return err; + } + } + +#ifdef HAVE_SECURE_RENEGOTIATION +startScr: + if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) { + int err; + WOLFSSL_MSG("Need to start scr, server requested"); + if ( (err = wolfSSL_Rehandshake(ssl)) != WOLFSSL_SUCCESS) + return err; + ssl->secure_renegotiation->startScr = 0; /* only start once */ + } +#endif + + while (ssl->buffers.clearOutputBuffer.length == 0) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + if (ssl->error == ZERO_RETURN) { + WOLFSSL_MSG("Zero return, no more data coming"); + return 0; /* no more data coming */ + } + if (ssl->error == SOCKET_ERROR_E) { + if (ssl->options.connReset || ssl->options.isClosed) { + WOLFSSL_MSG("Peer reset or closed, connection done"); + ssl->error = SOCKET_PEER_CLOSED_E; + WOLFSSL_ERROR(ssl->error); + return 0; /* peer reset or closed */ + } + } + return ssl->error; + } + #ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->startScr) { + goto startScr; + } + #endif + } + + if (sz < (int)ssl->buffers.clearOutputBuffer.length) + size = sz; + else + size = ssl->buffers.clearOutputBuffer.length; + + XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size); + + if (peek == 0) { + ssl->buffers.clearOutputBuffer.length -= size; + ssl->buffers.clearOutputBuffer.buffer += size; + } + + if (ssl->buffers.clearOutputBuffer.length == 0 && + ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + + WOLFSSL_LEAVE("ReceiveData()", size); + return size; +} + + +/* send alert message */ +int SendAlert(WOLFSSL* ssl, int severity, int type) +{ + byte input[ALERT_SIZE]; + byte *output; + int sendSz; + int ret; + int outputSz; + int dtlsExtra = 0; + + WOLFSSL_ENTER("SendAlert"); + +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { + int notifyErr = 0; + + WOLFSSL_MSG("Read dup side cannot write alerts, notifying sibling"); + + if (type == close_notify) { + notifyErr = ZERO_RETURN; + } else if (severity == alert_fatal) { + notifyErr = FATAL_ERROR; + } + + if (notifyErr != 0) { + return NotifyWriteSide(ssl, notifyErr); + } + + return 0; + } +#endif + + /* if sendalert is called again for nonblocking */ + if (ssl->options.sendAlertState != 0) { + ret = SendBuffered(ssl); + if (ret == 0) + ssl->options.sendAlertState = 0; + return ret; + } + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_ALERT, type); + } + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + dtlsExtra = DTLS_RECORD_EXTRA; + #endif + + /* check for available size */ + outputSz = ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra; + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* Check output buffer */ + if (ssl->buffers.outputBuffer.buffer == NULL) + return BUFFER_E; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + input[0] = (byte)severity; + input[1] = (byte)type; + ssl->alert_history.last_tx.code = type; + ssl->alert_history.last_tx.level = severity; + if (severity == alert_fatal) { + ssl->options.isClosed = 1; /* Don't send close_notify */ + } + + /* only send encrypted alert if handshake actually complete, otherwise + other side may not be able to handle it */ + if (IsEncryptionOn(ssl, 1) && (IsAtLeastTLSv1_3(ssl->version) || + ssl->options.handShakeDone)) { + sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert, + 0, 0, 0); + } + else { + + AddRecordHeader(output, ALERT_SIZE, alert, ssl); + output += RECORD_HEADER_SZ; + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + output += DTLS_RECORD_EXTRA; + #endif + XMEMCPY(output, input, ALERT_SIZE); + + sendSz = RECORD_HEADER_SZ + ALERT_SIZE; + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA; + #endif + } + if (sendSz < 0) + return BUILD_MSG_ERROR; + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "Alert"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "Alert", alert, output, sendSz, WRITE_PROTO, + ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + ssl->options.sendAlertState = 1; + + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendAlert", ret); + + return ret; +} + +const char* wolfSSL_ERR_reason_error_string(unsigned long e) +{ +#ifdef NO_ERROR_STRINGS + + (void)e; + return "no support for error strings built in"; + +#else + + int error = (int)e; + + /* pass to wolfCrypt */ + if (error < MAX_CODE_E && error > MIN_CODE_E) { + return wc_GetErrorString(error); + } + + switch (error) { + +#ifdef WOLFSSL_WPAS + case 0 : + return "ok"; +#endif + + case UNSUPPORTED_SUITE : + return "unsupported cipher suite"; + + case INPUT_CASE_ERROR : + return "input state error"; + + case PREFIX_ERROR : + return "bad index to key rounds"; + + case MEMORY_ERROR : + return "out of memory"; + + case VERIFY_FINISHED_ERROR : + return "verify problem on finished"; + + case VERIFY_MAC_ERROR : + return "verify mac problem"; + + case PARSE_ERROR : + return "parse error on header"; + + case SIDE_ERROR : + return "wrong client/server type"; + + case NO_PEER_CERT : + return "peer didn't send cert"; + + case UNKNOWN_HANDSHAKE_TYPE : + return "weird handshake type"; + + case SOCKET_ERROR_E : + return "error state on socket"; + + case SOCKET_NODATA : + return "expected data, not there"; + + case INCOMPLETE_DATA : + return "don't have enough data to complete task"; + + case UNKNOWN_RECORD_TYPE : + return "unknown type in record hdr"; + + case DECRYPT_ERROR : + return "error during decryption"; + + case FATAL_ERROR : + return "received alert fatal error"; + + case ENCRYPT_ERROR : + return "error during encryption"; + + case FREAD_ERROR : + return "fread problem"; + + case NO_PEER_KEY : + return "need peer's key"; + + case NO_PRIVATE_KEY : + return "need the private key"; + + case NO_DH_PARAMS : + return "server missing DH params"; + + case RSA_PRIVATE_ERROR : + return "error during rsa priv op"; + + case MATCH_SUITE_ERROR : + return "can't match cipher suite"; + + case COMPRESSION_ERROR : + return "compression mismatch error"; + + case BUILD_MSG_ERROR : + return "build message failure"; + + case BAD_HELLO : + return "client hello malformed"; + + case DOMAIN_NAME_MISMATCH : + return "peer subject name mismatch"; + + case IPADDR_MISMATCH : + return "peer ip address mismatch"; + + case WANT_READ : + case WOLFSSL_ERROR_WANT_READ : + return "non-blocking socket wants data to be read"; + + case NOT_READY_ERROR : + return "handshake layer not ready yet, complete first"; + + case VERSION_ERROR : + return "record layer version error"; + + case WANT_WRITE : + case WOLFSSL_ERROR_WANT_WRITE : + return "non-blocking socket write buffer full"; + + case BUFFER_ERROR : + return "malformed buffer input error"; + + case VERIFY_CERT_ERROR : + return "verify problem on certificate"; + + case VERIFY_SIGN_ERROR : + return "verify problem based on signature"; + + case CLIENT_ID_ERROR : + return "psk client identity error"; + + case SERVER_HINT_ERROR: + return "psk server hint error"; + + case PSK_KEY_ERROR: + return "psk key callback error"; + + case NTRU_KEY_ERROR: + return "NTRU key error"; + + case NTRU_DRBG_ERROR: + return "NTRU drbg error"; + + case NTRU_ENCRYPT_ERROR: + return "NTRU encrypt error"; + + case NTRU_DECRYPT_ERROR: + return "NTRU decrypt error"; + + case GETTIME_ERROR: + return "gettimeofday() error"; + + case GETITIMER_ERROR: + return "getitimer() error"; + + case SIGACT_ERROR: + return "sigaction() error"; + + case SETITIMER_ERROR: + return "setitimer() error"; + + case LENGTH_ERROR: + return "record layer length error"; + + case PEER_KEY_ERROR: + return "cant decode peer key"; + + case ZERO_RETURN: + case WOLFSSL_ERROR_ZERO_RETURN: + return "peer sent close notify alert"; + + case ECC_CURVETYPE_ERROR: + return "Bad ECC Curve Type or unsupported"; + + case ECC_CURVE_ERROR: + return "Bad ECC Curve or unsupported"; + + case ECC_PEERKEY_ERROR: + return "Bad ECC Peer Key"; + + case ECC_MAKEKEY_ERROR: + return "ECC Make Key failure"; + + case ECC_EXPORT_ERROR: + return "ECC Export Key failure"; + + case ECC_SHARED_ERROR: + return "ECC DHE shared failure"; + + case NOT_CA_ERROR: + return "Not a CA by basic constraint error"; + + case HTTP_TIMEOUT: + return "HTTP timeout for OCSP or CRL req"; + + case BAD_CERT_MANAGER_ERROR: + return "Bad Cert Manager error"; + + case OCSP_CERT_REVOKED: + return "OCSP Cert revoked"; + + case CRL_CERT_REVOKED: + return "CRL Cert revoked"; + + case CRL_MISSING: + return "CRL missing, not loaded"; + + case MONITOR_SETUP_E: + return "CRL monitor setup error"; + + case THREAD_CREATE_E: + return "Thread creation problem"; + + case OCSP_NEED_URL: + return "OCSP need URL"; + + case OCSP_CERT_UNKNOWN: + return "OCSP Cert unknown"; + + case OCSP_LOOKUP_FAIL: + return "OCSP Responder lookup fail"; + + case MAX_CHAIN_ERROR: + return "Maximum Chain Depth Exceeded"; + + case COOKIE_ERROR: + return "DTLS Cookie Error"; + + case SEQUENCE_ERROR: + return "DTLS Sequence Error"; + + case SUITES_ERROR: + return "Suites Pointer Error"; + + case OUT_OF_ORDER_E: + return "Out of order message, fatal"; + + case BAD_KEA_TYPE_E: + return "Bad KEA type found"; + + case SANITY_CIPHER_E: + return "Sanity check on ciphertext failed"; + + case RECV_OVERFLOW_E: + return "Receive callback returned more than requested"; + + case GEN_COOKIE_E: + return "Generate Cookie Error"; + + case NO_PEER_VERIFY: + return "Need peer certificate verify Error"; + + case FWRITE_ERROR: + return "fwrite Error"; + + case CACHE_MATCH_ERROR: + return "Cache restore header match Error"; + + case UNKNOWN_SNI_HOST_NAME_E: + return "Unrecognized host name Error"; + + case UNKNOWN_MAX_FRAG_LEN_E: + return "Unrecognized max frag len Error"; + + case KEYUSE_SIGNATURE_E: + return "Key Use digitalSignature not set Error"; + + case KEYUSE_ENCIPHER_E: + return "Key Use keyEncipherment not set Error"; + + case EXTKEYUSE_AUTH_E: + return "Ext Key Use server/client auth not set Error"; + + case SEND_OOB_READ_E: + return "Send Callback Out of Bounds Read Error"; + + case SECURE_RENEGOTIATION_E: + return "Invalid Renegotiation Error"; + + case SESSION_TICKET_LEN_E: + return "Session Ticket Too Long Error"; + + case SESSION_TICKET_EXPECT_E: + return "Session Ticket Error"; + + case SESSION_SECRET_CB_E: + return "Session Secret Callback Error"; + + case NO_CHANGE_CIPHER_E: + return "Finished received from peer before Change Cipher Error"; + + case SANITY_MSG_E: + return "Sanity Check on message order Error"; + + case DUPLICATE_MSG_E: + return "Duplicate HandShake message Error"; + + case SNI_UNSUPPORTED: + return "Protocol version does not support SNI Error"; + + case SOCKET_PEER_CLOSED_E: + return "Peer closed underlying transport Error"; + + case BAD_TICKET_KEY_CB_SZ: + return "Bad user session ticket key callback Size Error"; + + case BAD_TICKET_MSG_SZ: + return "Bad session ticket message Size Error"; + + case BAD_TICKET_ENCRYPT: + return "Bad user ticket callback encrypt Error"; + + case DH_KEY_SIZE_E: + return "DH key too small Error"; + + case SNI_ABSENT_ERROR: + return "No Server Name Indication extension Error"; + + case RSA_SIGN_FAULT: + return "RSA Signature Fault Error"; + + case HANDSHAKE_SIZE_ERROR: + return "Handshake message too large Error"; + + case UNKNOWN_ALPN_PROTOCOL_NAME_E: + return "Unrecognized protocol name Error"; + + case BAD_CERTIFICATE_STATUS_ERROR: + return "Bad Certificate Status Message Error"; + + case OCSP_INVALID_STATUS: + return "Invalid OCSP Status Error"; + + case OCSP_WANT_READ: + return "OCSP nonblock wants read"; + + case RSA_KEY_SIZE_E: + return "RSA key too small"; + + case ECC_KEY_SIZE_E: + return "ECC key too small"; + + case DTLS_EXPORT_VER_E: + return "Version needs updated after code change or version mismatch"; + + case INPUT_SIZE_E: + return "Input size too large Error"; + + case CTX_INIT_MUTEX_E: + return "Initialize ctx mutex error"; + + case EXT_MASTER_SECRET_NEEDED_E: + return "Extended Master Secret must be enabled to resume EMS session"; + + case DTLS_POOL_SZ_E: + return "Maximum DTLS pool size exceeded"; + + case DECODE_E: + return "Decode handshake message error"; + + case WRITE_DUP_READ_E: + return "Write dup write side can't read error"; + + case WRITE_DUP_WRITE_E: + return "Write dup read side can't write error"; + + case INVALID_CERT_CTX_E: + return "Certificate context does not match request or not empty"; + + case BAD_KEY_SHARE_DATA: + return "The Key Share data contains group that wasn't in Client Hello"; + + case MISSING_HANDSHAKE_DATA: + return "The handshake message is missing required data"; + + case BAD_BINDER: + return "Binder value does not match value server calculated"; + + case EXT_NOT_ALLOWED: + return "Extension type not allowed in handshake message type"; + + case INVALID_PARAMETER: + return "The security parameter is invalid"; + + case UNSUPPORTED_EXTENSION: + return "TLS Extension not requested by the client"; + + case PRF_MISSING: + return "Pseudo-random function is not enabled"; + + case KEY_SHARE_ERROR: + return "Key share extension did not contain a valid named group"; + + case POST_HAND_AUTH_ERROR: + return "Client will not do post handshake authentication"; + + case HRR_COOKIE_ERROR: + return "Cookie does not match one sent in HelloRetryRequest"; + + case MCAST_HIGHWATER_CB_E: + return "Multicast highwater callback returned error"; + + case ALERT_COUNT_E: + return "Alert Count exceeded error"; + + case EXT_MISSING: + return "Required TLS extension missing"; + + case DTLS_RETX_OVER_TX: + return "DTLS interrupting flight transmit with retransmit"; + + case DH_PARAMS_NOT_FFDHE_E: + return "Server DH parameters were not from the FFDHE set as required"; + + case TCA_INVALID_ID_TYPE: + return "TLS Extension Trusted CA ID type invalid"; + + case TCA_ABSENT_ERROR: + return "TLS Extension Trusted CA ID response absent"; + + case TSIP_MAC_DIGSZ_E: + return "TSIP MAC size invalid, must be sized for SHA-1 or SHA-256"; + + case CLIENT_CERT_CB_ERROR: + return "Error importing client cert or key from callback"; + + case SSL_SHUTDOWN_ALREADY_DONE_E: + return "Shutdown has already occurred"; + + case TLS13_SECRET_CB_E: + return "TLS1.3 Secret Callback Error"; + + default : + return "unknown error number"; + } + +#endif /* NO_ERROR_STRINGS */ +} + +void SetErrorString(int error, char* str) +{ + XSTRNCPY(str, wolfSSL_ERR_reason_error_string(error), WOLFSSL_MAX_ERROR_SZ); + str[WOLFSSL_MAX_ERROR_SZ-1] = 0; +} + +#ifndef NO_ERROR_STRINGS + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),(v),(u)} + #else + #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w)} + #endif +#else + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),(v),(u)} + #else + #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w)} + #endif +#endif + +static const CipherSuiteInfo cipher_names[] = +{ + +#ifdef BUILD_TLS_AES_128_GCM_SHA256 + SUITE_INFO("TLS13-AES128-GCM-SHA256","TLS_AES_128_GCM_SHA256",TLS13_BYTE,TLS_AES_128_GCM_SHA256, TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_AES_256_GCM_SHA384 + SUITE_INFO("TLS13-AES256-GCM-SHA384","TLS_AES_256_GCM_SHA384",TLS13_BYTE,TLS_AES_256_GCM_SHA384, TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + SUITE_INFO("TLS13-CHACHA20-POLY1305-SHA256","TLS_CHACHA20_POLY1305_SHA256",TLS13_BYTE,TLS_CHACHA20_POLY1305_SHA256, TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_AES_128_CCM_SHA256 + SUITE_INFO("TLS13-AES128-CCM-SHA256","TLS_AES_128_CCM_SHA256",TLS13_BYTE,TLS_AES_128_CCM_SHA256, TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + SUITE_INFO("TLS13-AES128-CCM-8-SHA256","TLS_AES_128_CCM_8_SHA256",TLS13_BYTE,TLS_AES_128_CCM_8_SHA256,TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_SHA256_SHA256 + SUITE_INFO("TLS13-SHA256-SHA256","TLS_SHA256_SHA256",ECC_BYTE,TLS_SHA256_SHA256,TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_SHA384_SHA384 + SUITE_INFO("TLS13-SHA384-SHA384","TLS_SHA384_SHA384",ECC_BYTE,TLS_SHA384_SHA384,TLSv1_3_MINOR, SSLv3_MAJOR), +#endif + +#ifndef WOLFSSL_NO_TLS12 + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + SUITE_INFO("RC4-SHA","SSL_RSA_WITH_RC4_128_SHA",CIPHER_BYTE,SSL_RSA_WITH_RC4_128_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + SUITE_INFO("RC4-MD5","SSL_RSA_WITH_RC4_128_MD5",CIPHER_BYTE,SSL_RSA_WITH_RC4_128_MD5,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("DES-CBC3-SHA","SSL_RSA_WITH_3DES_EDE_CBC_SHA",CIPHER_BYTE,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + SUITE_INFO("AES128-SHA","TLS_RSA_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_AES_128_CBC_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + SUITE_INFO("AES256-SHA","TLS_RSA_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_AES_256_CBC_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_MD5 + SUITE_INFO("NULL-MD5","TLS_RSA_WITH_NULL_MD5",CIPHER_BYTE,TLS_RSA_WITH_NULL_MD5,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + SUITE_INFO("NULL-SHA","TLS_RSA_WITH_NULL_SHA",CIPHER_BYTE,TLS_RSA_WITH_NULL_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 + SUITE_INFO("NULL-SHA256","TLS_RSA_WITH_NULL_SHA256",CIPHER_BYTE,TLS_RSA_WITH_NULL_SHA256,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + SUITE_INFO("DHE-RSA-AES128-SHA","TLS_DHE_RSA_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + SUITE_INFO("DHE-RSA-AES256-SHA","TLS_DHE_RSA_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + SUITE_INFO("DHE-PSK-AES256-GCM-SHA384","TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + SUITE_INFO("DHE-PSK-AES128-GCM-SHA256","TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384 + SUITE_INFO("PSK-AES256-GCM-SHA384","TLS_PSK_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_PSK_WITH_AES_256_GCM_SHA384,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256 + SUITE_INFO("PSK-AES128-GCM-SHA256","TLS_PSK_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_PSK_WITH_AES_128_GCM_SHA256,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + SUITE_INFO("DHE-PSK-AES256-CBC-SHA384","TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + SUITE_INFO("DHE-PSK-AES128-CBC-SHA256","TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384 + SUITE_INFO("PSK-AES256-CBC-SHA384","TLS_PSK_WITH_AES_256_CBC_SHA384",CIPHER_BYTE,TLS_PSK_WITH_AES_256_CBC_SHA384,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 + SUITE_INFO("PSK-AES128-CBC-SHA256","TLS_PSK_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_PSK_WITH_AES_128_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + SUITE_INFO("PSK-AES128-CBC-SHA","TLS_PSK_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_PSK_WITH_AES_128_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + SUITE_INFO("PSK-AES256-CBC-SHA","TLS_PSK_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_PSK_WITH_AES_256_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM + SUITE_INFO("DHE-PSK-AES128-CCM","TLS_DHE_PSK_WITH_AES_128_CCM",ECC_BYTE,TLS_DHE_PSK_WITH_AES_128_CCM,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM + SUITE_INFO("DHE-PSK-AES256-CCM","TLS_DHE_PSK_WITH_AES_256_CCM",ECC_BYTE,TLS_DHE_PSK_WITH_AES_256_CCM,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM + SUITE_INFO("PSK-AES128-CCM","TLS_PSK_WITH_AES_128_CCM",ECC_BYTE,TLS_PSK_WITH_AES_128_CCM,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM + SUITE_INFO("PSK-AES256-CCM","TLS_PSK_WITH_AES_256_CCM",ECC_BYTE,TLS_PSK_WITH_AES_256_CCM,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + SUITE_INFO("PSK-AES128-CCM-8","TLS_PSK_WITH_AES_128_CCM_8",ECC_BYTE,TLS_PSK_WITH_AES_128_CCM_8,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + SUITE_INFO("PSK-AES256-CCM-8","TLS_PSK_WITH_AES_256_CCM_8",ECC_BYTE,TLS_PSK_WITH_AES_256_CCM_8,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384 + SUITE_INFO("DHE-PSK-NULL-SHA384","TLS_DHE_PSK_WITH_NULL_SHA384",CIPHER_BYTE,TLS_DHE_PSK_WITH_NULL_SHA384,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256 + SUITE_INFO("DHE-PSK-NULL-SHA256","TLS_DHE_PSK_WITH_NULL_SHA256",CIPHER_BYTE,TLS_DHE_PSK_WITH_NULL_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384 + SUITE_INFO("PSK-NULL-SHA384","TLS_PSK_WITH_NULL_SHA384",CIPHER_BYTE,TLS_PSK_WITH_NULL_SHA384,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 + SUITE_INFO("PSK-NULL-SHA256","TLS_PSK_WITH_NULL_SHA256",CIPHER_BYTE,TLS_PSK_WITH_NULL_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + SUITE_INFO("PSK-NULL-SHA","TLS_PSK_WITH_NULL_SHA",CIPHER_BYTE,TLS_PSK_WITH_NULL_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + SUITE_INFO("HC128-MD5","TLS_RSA_WITH_HC_128_MD5",CIPHER_BYTE,TLS_RSA_WITH_HC_128_MD5,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + SUITE_INFO("HC128-SHA","TLS_RSA_WITH_HC_128_SHA",CIPHER_BYTE,TLS_RSA_WITH_HC_128_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + SUITE_INFO("RABBIT-SHA","TLS_RSA_WITH_RABBIT_SHA",CIPHER_BYTE,TLS_RSA_WITH_RABBIT_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + SUITE_INFO("NTRU-RC4-SHA","TLS_NTRU_RSA_WITH_RC4_128_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_RC4_128_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("NTRU-DES-CBC3-SHA","TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + SUITE_INFO("NTRU-AES128-SHA","TLS_NTRU_RSA_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_AES_128_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + SUITE_INFO("NTRU-AES256-SHA","TLS_NTRU_RSA_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_AES_256_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + SUITE_INFO("AES128-CCM-8","TLS_RSA_WITH_AES_128_CCM_8",ECC_BYTE,TLS_RSA_WITH_AES_128_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + SUITE_INFO("AES256-CCM-8","TLS_RSA_WITH_AES_256_CCM_8",ECC_BYTE,TLS_RSA_WITH_AES_256_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM + SUITE_INFO("ECDHE-ECDSA-AES128-CCM","TLS_ECDHE_ECDSA_WITH_AES_128_CCM",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CCM, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + SUITE_INFO("ECDHE-ECDSA-AES128-CCM-8","TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + SUITE_INFO("ECDHE-ECDSA-AES256-CCM-8","TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + SUITE_INFO("ECDHE-RSA-AES128-SHA","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + SUITE_INFO("ECDHE-RSA-AES256-SHA","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + SUITE_INFO("ECDHE-ECDSA-AES128-SHA","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + SUITE_INFO("ECDHE-ECDSA-AES256-SHA","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + SUITE_INFO("ECDHE-RSA-RC4-SHA","TLS_ECDHE_RSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("ECDHE-RSA-DES-CBC3-SHA","TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + SUITE_INFO("ECDHE-ECDSA-RC4-SHA","TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("ECDHE-ECDSA-DES-CBC3-SHA","TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 + SUITE_INFO("AES128-SHA256","TLS_RSA_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_AES_128_CBC_SHA256, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 + SUITE_INFO("AES256-SHA256","TLS_RSA_WITH_AES_256_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_AES_256_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + SUITE_INFO("DHE-RSA-AES128-SHA256","TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + SUITE_INFO("DHE-RSA-AES256-SHA256","TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + SUITE_INFO("ECDH-RSA-AES128-SHA","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + SUITE_INFO("ECDH-RSA-AES256-SHA","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + SUITE_INFO("ECDH-ECDSA-AES128-SHA","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + SUITE_INFO("ECDH-ECDSA-AES256-SHA","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + SUITE_INFO("ECDH-RSA-RC4-SHA","TLS_ECDH_RSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_RC4_128_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("ECDH-RSA-DES-CBC3-SHA","TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + SUITE_INFO("ECDH-ECDSA-RC4-SHA","TLS_ECDH_ECDSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("ECDH-ECDSA-DES-CBC3-SHA","TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + SUITE_INFO("AES128-GCM-SHA256","TLS_RSA_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_RSA_WITH_AES_128_GCM_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + SUITE_INFO("AES256-GCM-SHA384","TLS_RSA_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_RSA_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + SUITE_INFO("DHE-RSA-AES128-GCM-SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + SUITE_INFO("DHE-RSA-AES256-GCM-SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + SUITE_INFO("ECDHE-RSA-AES128-GCM-SHA256","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + SUITE_INFO("ECDHE-RSA-AES256-GCM-SHA384","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + SUITE_INFO("ECDHE-ECDSA-AES128-GCM-SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + SUITE_INFO("ECDHE-ECDSA-AES256-GCM-SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + SUITE_INFO("ECDH-RSA-AES128-GCM-SHA256","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + SUITE_INFO("ECDH-RSA-AES256-GCM-SHA384","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + SUITE_INFO("ECDH-ECDSA-AES128-GCM-SHA256","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + SUITE_INFO("ECDH-ECDSA-AES256-GCM-SHA384","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + SUITE_INFO("CAMELLIA128-SHA","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + SUITE_INFO("DHE-RSA-CAMELLIA128-SHA","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + SUITE_INFO("CAMELLIA256-SHA","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + SUITE_INFO("DHE-RSA-CAMELLIA256-SHA","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + SUITE_INFO("CAMELLIA128-SHA256","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + SUITE_INFO("DHE-RSA-CAMELLIA128-SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + SUITE_INFO("CAMELLIA256-SHA256","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + SUITE_INFO("DHE-RSA-CAMELLIA256-SHA256","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + SUITE_INFO("ECDHE-RSA-AES128-SHA256","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + SUITE_INFO("ECDHE-ECDSA-AES128-SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + SUITE_INFO("ECDH-RSA-AES128-SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + SUITE_INFO("ECDH-ECDSA-AES128-SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + SUITE_INFO("ECDHE-RSA-AES256-SHA384","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + SUITE_INFO("ECDHE-ECDSA-AES256-SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + SUITE_INFO("ECDH-RSA-AES256-SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + SUITE_INFO("ECDH-ECDSA-AES256-SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + SUITE_INFO("ECDHE-RSA-CHACHA20-POLY1305","TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + SUITE_INFO("ECDHE-ECDSA-CHACHA20-POLY1305","TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + SUITE_INFO("DHE-RSA-CHACHA20-POLY1305","TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + SUITE_INFO("ECDHE-RSA-CHACHA20-POLY1305-OLD","TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + SUITE_INFO("ECDHE-ECDSA-CHACHA20-POLY1305-OLD","TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + SUITE_INFO("DHE-RSA-CHACHA20-POLY1305-OLD","TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256",CHACHA_BYTE,TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA + SUITE_INFO("ADH-AES128-SHA","TLS_DH_anon_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_DH_anon_WITH_AES_128_CBC_SHA, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384 + SUITE_INFO("ADH-AES256-GCM-SHA384","TLS_DH_anon_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_DH_anon_WITH_AES_256_GCM_SHA384, TLSv1_2_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_QSH + SUITE_INFO("QSH","TLS_QSH",QSH_BYTE,TLS_QSH, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef HAVE_RENEGOTIATION_INDICATION + SUITE_INFO("RENEGOTIATION-INFO","TLS_EMPTY_RENEGOTIATION_INFO_SCSV",CIPHER_BYTE,TLS_EMPTY_RENEGOTIATION_INFO_SCSV,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + SUITE_INFO("IDEA-CBC-SHA","SSL_RSA_WITH_IDEA_CBC_SHA",CIPHER_BYTE,SSL_RSA_WITH_IDEA_CBC_SHA,SSLv3_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA + SUITE_INFO("ECDHE-ECDSA-NULL-SHA","TLS_ECDHE_ECDSA_WITH_NULL_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256 + SUITE_INFO("ECDHE-PSK-NULL-SHA256","TLS_ECDHE_PSK_WITH_NULL_SHA256",ECC_BYTE,TLS_ECDHE_PSK_WITH_NULL_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + SUITE_INFO("ECDHE-PSK-AES128-CBC-SHA256","TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,TLSv1_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 + SUITE_INFO("PSK-CHACHA20-POLY1305","TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 + SUITE_INFO("ECDHE-PSK-CHACHA20-POLY1305","TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 + SUITE_INFO("DHE-PSK-CHACHA20-POLY1305","TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,TLSv1_2_MINOR,SSLv3_MAJOR), +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + SUITE_INFO("EDH-RSA-DES-CBC3-SHA","TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLSv1_MINOR, SSLv3_MAJOR), +#endif + +#ifdef BUILD_WDM_WITH_NULL_SHA256 + SUITE_INFO("WDM-NULL-SHA256","WDM_WITH_NULL_SHA256",CIPHER_BYTE,WDM_WITH_NULL_SHA256, TLSv1_3_MINOR, SSLv3_MAJOR) +#endif + +#endif /* WOLFSSL_NO_TLS12 */ +}; + + +/* returns the cipher_names array */ +const CipherSuiteInfo* GetCipherNames(void) +{ + return cipher_names; +} + + +/* returns the number of elements in the cipher_names array */ +int GetCipherNamesSize(void) +{ + return (int)(sizeof(cipher_names) / sizeof(CipherSuiteInfo)); +} + + +const char* GetCipherNameInternal(const byte cipherSuite0, const byte cipherSuite) +{ + int i; + const char* nameInternal = "None"; + + for (i = 0; i < GetCipherNamesSize(); i++) { + if ((cipher_names[i].cipherSuite0 == cipherSuite0) && + (cipher_names[i].cipherSuite == cipherSuite)) { + nameInternal = cipher_names[i].name; + break; + } + } + return nameInternal; +} + +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +const char* GetCipherKeaStr(char n[][MAX_SEGMENT_SZ]) { + const char* keaStr = NULL; + const char *n0,*n1,*n2,*n3,*n4; + n0 = n[0]; + n1 = n[1]; + n2 = n[2]; + n3 = n[3]; + n4 = n[4]; + + if (XSTRNCMP(n0,"ECDHE",5) == 0 && XSTRNCMP(n1,"PSK",3) == 0) + keaStr = "ECDHEPSK"; + else if (XSTRNCMP(n0,"ECDH",4) == 0) + keaStr = "ECDH"; + else if (XSTRNCMP(n0,"DHE",3) == 0 && XSTRNCMP(n1,"PSK",3) == 0) + keaStr = "DHEPSK"; + else if (XSTRNCMP(n0,"DHE",3) == 0) + keaStr = "DH"; + else if (XSTRNCMP(n0,"RSA",3) == 0 && XSTRNCMP(n1,"PSK",3) == 0) + keaStr = "RSAPSK"; + else if (XSTRNCMP(n0,"SRP",3) == 0) + keaStr = "SRP"; + else if (XSTRNCMP(n0,"PSK",3) == 0) + keaStr = "PSK"; + else if (XSTRNCMP(n0,"EDH",3) == 0) + keaStr = "EDH"; + else if ((XSTRNCMP(n1,"SHA",3) == 0) || (XSTRNCMP(n2,"SHA",3) == 0) || + (XSTRNCMP(n3,"SHA",3) == 0) || (XSTRNCMP(n4,"SHA",3) == 0) || + (XSTRNCMP(n2,"RSA",3) == 0) || (XSTRNCMP(n0,"AES128",6) == 0) || + (XSTRNCMP(n0,"AES256",6) == 0) || (XSTRNCMP(n1,"MD5",3) == 0)) + keaStr = "RSA"; + else + keaStr = "unknown"; + + return keaStr; +} + +const char* GetCipherAuthStr(char n[][MAX_SEGMENT_SZ]) { + + const char* authStr = NULL; + const char *n0,*n1,*n2; + n0 = n[0]; + n1 = n[1]; + n2 = n[2]; + + if ((XSTRNCMP(n0,"AES128",6) == 0) || (XSTRNCMP(n0,"AES256",6) == 0) || + ((XSTRNCMP(n0,"TLS13",5) == 0) && ((XSTRNCMP(n1,"AES128",6) == 0) || + (XSTRNCMP(n1,"AES256",6) == 0) || (XSTRNCMP(n1,"CHACHA20",8) == 0))) || + (XSTRNCMP(n0,"RSA",3) == 0) || (XSTRNCMP(n1,"RSA",3) == 0) || + (XSTRNCMP(n1,"SHA",3) == 0) || (XSTRNCMP(n2,"SHA",3) == 0) || + (XSTRNCMP(n1,"MD5",3) == 0)) + authStr = "RSA"; + else if (XSTRNCMP(n0,"PSK",3) == 0 || XSTRNCMP(n1,"PSK",3) == 0) + authStr = "PSK"; + else if (XSTRNCMP(n0,"SRP",3) == 0 && XSTRNCMP(n1,"AES",3) == 0) + authStr = "SRP"; + else if (XSTRNCMP(n1,"ECDSA",5) == 0) + authStr = "ECDSA"; + else + authStr = "unknown"; + + return authStr; +} + +const char* GetCipherEncStr(char n[][MAX_SEGMENT_SZ]) { + const char* encStr = NULL; + const char *n0,*n1,*n2,*n3; + n0 = n[0]; + n1 = n[1]; + n2 = n[2]; + n3 = n[3]; + + if ((XSTRNCMP(n0,"AES256",6) == 0 && XSTRNCMP(n1,"GCM",3) == 0) || + (XSTRNCMP(n1,"AES256",6) == 0 && XSTRNCMP(n2,"GCM",3) == 0) || + (XSTRNCMP(n2,"AES256",6) == 0 && XSTRNCMP(n3,"GCM",3) == 0)) + encStr = "AESGCM(256)"; + + else if ((XSTRNCMP(n0,"AES128",6) == 0 && XSTRNCMP(n1,"GCM",3) == 0) || + (XSTRNCMP(n1,"AES128",6) == 0 && XSTRNCMP(n2,"GCM",3) == 0) || + (XSTRNCMP(n2,"AES128",6) == 0 && XSTRNCMP(n3,"GCM",3) == 0)) + encStr = "AESGCM(128)"; + + else if ((XSTRNCMP(n0,"AES128",6) == 0 && XSTRNCMP(n1,"CCM",3) == 0) || + (XSTRNCMP(n1,"AES128",6) == 0 && XSTRNCMP(n2,"CCM",3) == 0) || + (XSTRNCMP(n2,"AES128",6) == 0 && XSTRNCMP(n3,"CCM",3) == 0)) + encStr = "AESCCM(128)"; + + else if ((XSTRNCMP(n0,"AES128",6) == 0) || + (XSTRNCMP(n1,"AES128",6) == 0) || + (XSTRNCMP(n2,"AES128",6) == 0) || + (XSTRNCMP(n1,"AES",3) == 0 && XSTRNCMP(n2,"128",3) == 0) || + (XSTRNCMP(n2,"AES",3) == 0 && XSTRNCMP(n3,"128",3) == 0)) + encStr = "AES(128)"; + + else if ((XSTRNCMP(n0,"AES256",6) == 0) || + (XSTRNCMP(n1,"AES256",6) == 0) || + (XSTRNCMP(n2,"AES256",6) == 0) || + (XSTRNCMP(n1,"AES",3) == 0 && XSTRNCMP(n2,"256",3) == 0) || + (XSTRNCMP(n2,"AES",3) == 0 && XSTRNCMP(n3,"256",3) == 0)) + encStr = "AES(256)"; + + else if ((XSTRNCMP(n0,"CAMELLIA256",11) == 0) || + (XSTRNCMP(n2,"CAMELLIA256",11) == 0)) + encStr = "CAMELLIA(256)"; + else if ((XSTRNCMP(n0,"CAMELLIA128",11) == 0) || + (XSTRNCMP(n2,"CAMELLIA128",11) == 0)) + encStr = "CAMELLIA(128)"; + else if ((XSTRNCMP(n0,"RC4",3) == 0) || (XSTRNCMP(n2,"RC4",3) == 0)) + encStr = "RC4"; + else if (((XSTRNCMP(n0,"DES",3) == 0) || (XSTRNCMP(n2,"DES",3) == 0)) && + ((XSTRNCMP(n1,"CBC3",4) == 0) || (XSTRNCMP(n3,"CBC3",4) == 0))) + encStr = "3DES"; + else if ((XSTRNCMP(n1,"CHACHA20",8) == 0 && XSTRNCMP(n2,"POLY1305",8) == 0) || + (XSTRNCMP(n2,"CHACHA20",8) == 0 && XSTRNCMP(n3,"POLY1305",8) == 0)) + encStr = "CHACHA20/POLY1305(256)"; + else if ((XSTRNCMP(n0,"NULL",4) == 0) || (XSTRNCMP(n1,"NULL",4) == 0) || + (XSTRNCMP(n2,"NULL",4) == 0) || + ((XSTRNCMP(n0,"TLS13",5) == 0) && (XSTRNCMP(n3,"",0) == 0))) + encStr = "None"; + else if ((XSTRNCMP(n0,"IDEA",4) == 0)) + encStr = "IDEA"; + else if ((XSTRNCMP(n0,"RABBIT",4) == 0)) + encStr = "RABBIT"; + else if ((XSTRNCMP(n0,"HC128",5) == 0)) + encStr = "HC128"; + else + encStr = "unknown"; + + return encStr; +} + +/* Returns the MAC string of a cipher or "unknown" on failure */ +const char* GetCipherMacStr(char n[][MAX_SEGMENT_SZ]) { + + const char* macStr = NULL; + const char *n1,*n2,*n3,*n4; + n1 = n[1]; + n2 = n[2]; + n3 = n[3]; + n4 = n[4]; + + if ((XSTRNCMP(n4,"SHA256",6) == 0) || (XSTRNCMP(n3,"SHA256",6) == 0) || + (XSTRNCMP(n2,"SHA256",6) == 0) || (XSTRNCMP(n1,"SHA256",6) == 0)) + macStr = "SHA256"; + else if ((XSTRNCMP(n4,"SHA384",6) == 0) || + (XSTRNCMP(n3,"SHA384",6) == 0) || + (XSTRNCMP(n2,"SHA384",6) == 0) || + (XSTRNCMP(n1,"SHA384",6) == 0)) + macStr = "SHA384"; + else if ((XSTRNCMP(n4,"SHA",3) == 0) || (XSTRNCMP(n3,"SHA",3) == 0) || + (XSTRNCMP(n2,"SHA",3) == 0) || (XSTRNCMP(n1,"SHA",3) == 0) || + (XSTRNCMP(n1,"MD5",3) == 0)) + macStr = "SHA1"; + else if ((XSTRNCMP(n3,"GCM",3) == 0) || + (XSTRNCMP(n1,"CCM",3) == 0) || + (XSTRNCMP(n2,"CCM",3) == 0) || (XSTRNCMP(n3,"CCM",3) == 0) || + (XSTRNCMP(n1,"CHACHA20",8) == 0 && XSTRNCMP(n2,"POLY1305",8) == 0) || + (XSTRNCMP(n2,"CHACHA20",8) == 0 && XSTRNCMP(n3,"POLY1305",8) == 0)) + macStr = "AEAD"; + else + macStr = "unknown"; + + return macStr; +} + +/* Returns the number of bits based on the cipher enc string, or 0 on failure */ +int SetCipherBits(const char* enc) { + int ret = WOLFSSL_FAILURE; + + if ((XSTRNCMP(enc,"AESGCM(256)",11) == 0) || + (XSTRNCMP(enc,"AES(256)",8) == 0) || + (XSTRNCMP(enc,"CAMELLIA(256)",13) == 0) || + (XSTRNCMP(enc,"CHACHA20/POLY1305(256)",22) == 0)) + ret = 256; + else if + ((XSTRNCMP(enc,"3DES",4) == 0)) + ret = 168; + else if + ((XSTRNCMP(enc,"AESGCM(128)",11) == 0) || + (XSTRNCMP(enc,"AES(128)",8) == 0) || + (XSTRNCMP(enc,"CAMELLIA(128)",13) == 0) || + (XSTRNCMP(enc,"IDEA",4) == 0) || + (XSTRNCMP(enc,"RC4",3) == 0)) + ret = 128; + else if + ((XSTRNCMP(enc,"DES",3) == 0)) + ret = 56; + + return ret; +} +#endif /* WOLFSSL_QT || OPENSSL_ALL */ + +const char* GetCipherNameIana(const byte cipherSuite0, const byte cipherSuite) +{ +#ifndef NO_ERROR_STRINGS + int i; + const char* nameIana = "NONE"; + + for (i = 0; i < GetCipherNamesSize(); i++) { + if ((cipher_names[i].cipherSuite0 == cipherSuite0) && + (cipher_names[i].cipherSuite == cipherSuite)) { + nameIana = cipher_names[i].name_iana; + break; + } + } + return nameIana; +#else + (void)cipherSuite0; + (void)cipherSuite; + return NULL; +#endif +} + +const char* wolfSSL_get_cipher_name_internal(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return NULL; + } + + return GetCipherNameInternal(ssl->options.cipherSuite0, ssl->options.cipherSuite); +} + +const char* wolfSSL_get_cipher_name_iana(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return NULL; + } + + return GetCipherNameIana(ssl->options.cipherSuite0, ssl->options.cipherSuite); +} + +int GetCipherSuiteFromName(const char* name, byte* cipherSuite0, + byte* cipherSuite) +{ + int ret = BAD_FUNC_ARG; + int i; + unsigned long len = (unsigned long)XSTRLEN(name); + + for (i = 0; i < GetCipherNamesSize(); i++) { + if (XSTRNCMP(name, cipher_names[i].name, len) == 0) { + *cipherSuite0 = cipher_names[i].cipherSuite0; + *cipherSuite = cipher_names[i].cipherSuite; + ret = 0; + break; + } + } + + return ret; +} + +/** +Set the enabled cipher suites. + +@param [out] suites Suites structure. +@param [in] list List of cipher suites, only supports full name from + cipher_names[] delimited by ':'. + +@return true on success, else false. +*/ +int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list) +{ + int ret = 0; + int idx = 0; + int haveRSAsig = 0; + int haveECDSAsig = 0; + int haveAnon = 0; + const int suiteSz = GetCipherNamesSize(); + char* next = (char*)list; + + if (suites == NULL || list == NULL) { + WOLFSSL_MSG("SetCipherList parameter error"); + return 0; + } + + if (next[0] == 0 || XSTRNCMP(next, "ALL", 3) == 0 || + XSTRNCMP(next, "DEFAULT", 7) == 0) + return 1; /* wolfSSL default */ + + do { + char* current = next; + char name[MAX_SUITE_NAME + 1]; + int i; + word32 length; + + next = XSTRSTR(next, ":"); + length = min(sizeof(name), !next ? (word32)XSTRLEN(current) /* last */ + : (word32)(next - current)); + + XSTRNCPY(name, current, length); + name[(length == sizeof(name)) ? length - 1 : length] = 0; + + for (i = 0; i < suiteSz; i++) { + if (XSTRNCMP(name, cipher_names[i].name, sizeof(name)) == 0 + #ifndef NO_ERROR_STRINGS + || XSTRNCMP(name, cipher_names[i].name_iana, sizeof(name)) == 0 + #endif + ) { + #ifdef WOLFSSL_DTLS + /* don't allow stream ciphers with DTLS */ + if (ctx->method->version.major == DTLS_MAJOR) { + if (XSTRSTR(name, "RC4") || + XSTRSTR(name, "HC128") || + XSTRSTR(name, "RABBIT")) + { + WOLFSSL_MSG("Stream ciphers not supported with DTLS"); + continue; + } + + } + #endif /* WOLFSSL_DTLS */ + + if (idx + 1 >= WOLFSSL_MAX_SUITE_SZ) { + WOLFSSL_MSG("WOLFSSL_MAX_SUITE_SZ set too low"); + return 0; /* suites buffer not large enough, error out */ + } + + suites->suites[idx++] = cipher_names[i].cipherSuite0; + suites->suites[idx++] = cipher_names[i].cipherSuite; + /* The suites are either ECDSA, RSA, PSK, or Anon. The RSA + * suites don't necessarily have RSA in the name. */ + #ifdef WOLFSSL_TLS13 + if (cipher_names[i].cipherSuite0 == TLS13_BYTE || + (cipher_names[i].cipherSuite0 == ECC_BYTE && + (cipher_names[i].cipherSuite == TLS_SHA256_SHA256 || + cipher_names[i].cipherSuite == TLS_SHA384_SHA384))) { + #ifndef NO_RSA + haveRSAsig = 1; + #endif + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + haveECDSAsig = 1; + #endif + } + else + #endif + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA")) + haveECDSAsig = 1; + else + #endif + #ifdef HAVE_ANON + if (XSTRSTR(name, "ADH")) + haveAnon = 1; + else + #endif + if (haveRSAsig == 0 + #ifndef NO_PSK + && (XSTRSTR(name, "PSK") == NULL) + #endif + ) { + haveRSAsig = 1; + } + + ret = 1; /* found at least one */ + break; + } + } + } + while (next++); /* ++ needed to skip ':' */ + + if (ret) { + int keySz = 0; + #ifndef NO_CERTS + keySz = ctx->privateKeySz; + #endif + suites->setSuites = 1; + suites->suiteSz = (word16)idx; + InitSuitesHashSigAlgo(suites, haveECDSAsig, haveRSAsig, haveAnon, 1, + keySz); + } + + (void)ctx; + + return ret; +} + + +#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) +int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz) +{ + word32 i; + int ret = MATCH_SUITE_ERROR; + + ssl->suites->sigAlgo = ssl->specs.sig_algo; + + /* set defaults */ + if (IsAtLeastTLSv1_3(ssl->version)) { + ssl->suites->hashAlgo = sha256_mac; + #ifndef NO_CERTS + ssl->suites->sigAlgo = ssl->buffers.keyType; + #endif + } +#ifndef WOLFSSL_NO_TLS12 + else if (IsAtLeastTLSv1_2(ssl)) { + #ifdef WOLFSSL_ALLOW_TLS_SHA1 + ssl->suites->hashAlgo = sha_mac; + #else + ssl->suites->hashAlgo = sha256_mac; + #endif + } + else { + ssl->suites->hashAlgo = sha_mac; + } +#endif + + if (hashSigAlgoSz == 0) + return 0; + + /* i+1 since peek a byte ahead for type */ + for (i = 0; (i+1) < hashSigAlgoSz; i += HELLO_EXT_SIGALGO_SZ) { + byte hashAlgo = 0, sigAlgo = 0; + + DecodeSigAlg(&hashSigAlgo[i], &hashAlgo, &sigAlgo); + #ifdef HAVE_ED25519 + if (ssl->pkCurveOID == ECC_ED25519_OID) { + if (sigAlgo != ed25519_sa_algo) + continue; + if (sigAlgo == ed25519_sa_algo && + ssl->suites->sigAlgo == ecc_dsa_sa_algo) { + ssl->suites->sigAlgo = sigAlgo; + ssl->suites->hashAlgo = sha512_mac; + ret = 0; + break; + } + } + #endif + #ifdef HAVE_ED448 + if (ssl->pkCurveOID == ECC_ED448_OID) { + if (sigAlgo != ed448_sa_algo) + continue; + + if (sigAlgo == ed448_sa_algo && + ssl->suites->sigAlgo == ecc_dsa_sa_algo) { + ssl->suites->sigAlgo = sigAlgo; + ssl->suites->hashAlgo = sha512_mac; + ret = 0; + break; + } + } + #endif + #if defined(WOLFSSL_TLS13) && defined(HAVE_ECC) + if (IsAtLeastTLSv1_3(ssl->version) && sigAlgo == ssl->suites->sigAlgo && + sigAlgo == ecc_dsa_sa_algo) { + + int digestSz = GetMacDigestSize(hashAlgo); + if (digestSz <= 0) + continue; + + /* TLS 1.3 signature algorithms for ECDSA match hash length with + * key size. + */ + if (digestSz != ssl->buffers.keySz) + continue; + + ssl->suites->hashAlgo = hashAlgo; + ssl->suites->sigAlgo = sigAlgo; + ret = 0; + break; /* done selected sig/hash algorithms */ + } + else + #endif + /* For ECDSA the `USE_ECDSA_KEYSZ_HASH_ALGO` build option will choose a hash + * algorithm that matches the ephemeral ECDHE key size or the next highest + * available. This workaround resolves issue with some peer's that do not + * properly support scenarios such as a P-256 key hashed with SHA512. + */ + #if defined(HAVE_ECC) && defined(USE_ECDSA_KEYSZ_HASH_ALGO) + if (sigAlgo == ssl->suites->sigAlgo && sigAlgo == ecc_dsa_sa_algo) { + int digestSz = GetMacDigestSize(hashAlgo); + if (digestSz <= 0) + continue; + + /* For ecc_dsa_sa_algo, pick hash algo that is curve size unless + algorithm in not compiled in, then choose next highest */ + if (digestSz == ssl->eccTempKeySz) { + ssl->suites->hashAlgo = hashAlgo; + ssl->suites->sigAlgo = sigAlgo; + #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE) + ssl->namedGroup = 0; + #endif + ret = 0; + break; /* done selected sig/hash algorithms */ + } + /* not strong enough, so keep checking hashSigAlso list */ + if (digestSz < ssl->eccTempKeySz) + continue; + + /* mark as highest and check remainder of hashSigAlgo list */ + ssl->suites->hashAlgo = hashAlgo; + ssl->suites->sigAlgo = sigAlgo; + ret = 0; + } + else + #endif + #ifdef WC_RSA_PSS + if (IsAtLeastTLSv1_3(ssl->version) && + ssl->suites->sigAlgo == rsa_sa_algo && + sigAlgo != rsa_pss_sa_algo) { + continue; + } + else if (sigAlgo == ssl->suites->sigAlgo || + (sigAlgo == rsa_pss_sa_algo && + (ssl->suites->sigAlgo == rsa_sa_algo))) + #else + if (sigAlgo == ssl->suites->sigAlgo) + #endif + { + /* pick highest available between both server and client */ + switch (hashAlgo) { + case sha_mac: + #ifdef WOLFSSL_SHA224 + case sha224_mac: + #endif + #ifndef NO_SHA256 + case sha256_mac: + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + #endif + #ifdef WOLFSSL_SHA512 + case sha512_mac: + #endif + /* not strong enough, so keep checking hashSigAlso list */ + if (hashAlgo < ssl->suites->hashAlgo) { + ret = 0; + continue; + } + /* mark as highest and check remainder of hashSigAlgo list */ + ssl->suites->hashAlgo = hashAlgo; + ssl->suites->sigAlgo = sigAlgo; + break; + default: + continue; + } + ret = 0; + break; + } +#if defined(WOLFSSL_TLS13) + else if (ssl->specs.sig_algo == 0 && IsAtLeastTLSv1_3(ssl->version)) { + } +#endif + else if (ssl->specs.sig_algo == 0) + { + ssl->suites->hashAlgo = ssl->specs.mac_algorithm; + ret = 0; + } + } + + return ret; +} +#endif /* !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) */ + +#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + + /* Initialize HandShakeInfo */ + void InitHandShakeInfo(HandShakeInfo* info, WOLFSSL* ssl) + { + int i; + + info->ssl = ssl; + info->cipherName[0] = 0; + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) + info->packetNames[i][0] = 0; + info->numberPackets = 0; + info->negotiationError = 0; + } + + /* Set Final HandShakeInfo parameters */ + void FinishHandShakeInfo(HandShakeInfo* info) + { + int i; + int sz = GetCipherNamesSize(); + + for (i = 0; i < sz; i++) + if (info->ssl->options.cipherSuite == + (byte)cipher_names[i].cipherSuite) { + if (info->ssl->options.cipherSuite0 == ECC_BYTE) + continue; /* ECC suites at end */ + XSTRNCPY(info->cipherName, cipher_names[i].name, MAX_CIPHERNAME_SZ); + info->cipherName[MAX_CIPHERNAME_SZ] = '\0'; + break; + } + + /* error max and min are negative numbers */ + if (info->ssl->error <= MIN_PARAM_ERR && info->ssl->error >= MAX_PARAM_ERR) + info->negotiationError = info->ssl->error; + } + + + /* Add name to info packet names, increase packet name count */ + void AddPacketName(WOLFSSL* ssl, const char* name) + { + #ifdef WOLFSSL_CALLBACKS + HandShakeInfo* info = &ssl->handShakeInfo; + if (info->numberPackets < MAX_PACKETS_HANDSHAKE) { + char* packetName = info->packetNames[info->numberPackets]; + XSTRNCPY(packetName, name, MAX_PACKETNAME_SZ); + packetName[MAX_PACKETNAME_SZ] = '\0'; + info->numberPackets++; + } + #endif + (void)ssl; + (void)name; + } + + + #ifdef WOLFSSL_CALLBACKS + /* Initialize TimeoutInfo */ + void InitTimeoutInfo(TimeoutInfo* info) + { + int i; + + info->timeoutName[0] = 0; + info->flags = 0; + + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) { + info->packets[i].packetName[0] = 0; + info->packets[i].timestamp.tv_sec = 0; + info->packets[i].timestamp.tv_usec = 0; + info->packets[i].bufferValue = 0; + info->packets[i].valueSz = 0; + } + info->numberPackets = 0; + info->timeoutValue.tv_sec = 0; + info->timeoutValue.tv_usec = 0; + } + + + /* Free TimeoutInfo */ + void FreeTimeoutInfo(TimeoutInfo* info, void* heap) + { + int i; + (void)heap; + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) + if (info->packets[i].bufferValue) { + XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO); + info->packets[i].bufferValue = 0; + } + + } + + /* Add packet name to previously added packet info */ + void AddLateName(const char* name, TimeoutInfo* info) + { + /* make sure we have a valid previous one */ + if (info->numberPackets > 0 && info->numberPackets < + MAX_PACKETS_HANDSHAKE) { + char* packetName = info->packets[info->numberPackets-1].packetName; + XSTRNCPY(packetName, name, MAX_PACKETNAME_SZ); + packetName[MAX_PACKETNAME_SZ] = '\0'; + } + } + + /* Add record header to previously added packet info */ + void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info) + { + /* make sure we have a valid previous one */ + if (info->numberPackets > 0 && info->numberPackets < + MAX_PACKETS_HANDSHAKE) { + if (info->packets[info->numberPackets - 1].bufferValue) + XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl, + RECORD_HEADER_SZ); + else + XMEMCPY(info->packets[info->numberPackets - 1].value, rl, + RECORD_HEADER_SZ); + } + } + + #endif /* WOLFSSL_CALLBACKS */ + + + /* Add PacketInfo to TimeoutInfo + * + * ssl WOLFSSL structure sending or receiving packet + * name name of packet being sent + * type type of packet being sent + * data data bing sent with packet + * sz size of data buffer + * written 1 if this packet is being written to wire, 0 if being read + * heap custom heap to use for mallocs/frees + */ + void AddPacketInfo(WOLFSSL* ssl, const char* name, int type, + const byte* data, int sz, int written, void* heap) + { + #ifdef WOLFSSL_CALLBACKS + TimeoutInfo* info = &ssl->timeoutInfo; + + if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) { + WOLFSSL_TIMEVAL currTime; + + /* may add name after */ + if (name) { + char* packetName = info->packets[info->numberPackets].packetName; + XSTRNCPY(packetName, name, MAX_PACKETNAME_SZ); + packetName[MAX_PACKETNAME_SZ] = '\0'; + } + + /* add data, put in buffer if bigger than static buffer */ + info->packets[info->numberPackets].valueSz = sz; + if (sz < MAX_VALUE_SZ) + XMEMCPY(info->packets[info->numberPackets].value, data, sz); + else { + info->packets[info->numberPackets].bufferValue = + (byte*)XMALLOC(sz, heap, DYNAMIC_TYPE_INFO); + if (!info->packets[info->numberPackets].bufferValue) + /* let next alloc catch, just don't fill, not fatal here */ + info->packets[info->numberPackets].valueSz = 0; + else + XMEMCPY(info->packets[info->numberPackets].bufferValue, + data, sz); + } + gettimeofday(&currTime, 0); + info->packets[info->numberPackets].timestamp.tv_sec = + currTime.tv_sec; + info->packets[info->numberPackets].timestamp.tv_usec = + currTime.tv_usec; + info->numberPackets++; + } + #endif /* WOLFSSL_CALLBACKS */ + #ifdef OPENSSL_EXTRA + if (ssl->protoMsgCb != NULL && sz > RECORD_HEADER_SZ) { + /* version from hex to dec 16 is 16^1, 256 from 16^2 and + 4096 from 16^3 */ + int version = (ssl->version.minor & 0X0F) + + (ssl->version.minor & 0xF0) * 16 + + (ssl->version.major & 0X0F) * 256 + + (ssl->version.major & 0xF0) * 4096; + + ssl->protoMsgCb(written, version, type, + (const void *)(data + RECORD_HEADER_SZ), + (size_t)(sz - RECORD_HEADER_SZ), + ssl, ssl->protoMsgCtx); + } + #endif /* OPENSSL_EXTRA */ + (void)written; + (void)name; + (void)heap; + (void)type; + (void)ssl; + } + +#endif /* WOLFSSL_CALLBACKS */ + +#if !defined(NO_CERTS) + +/* Decode the private key - RSA/ECC/Ed25519/Ed448 - and creates a key object. + * The signature type is set as well. + * The maximum length of a signature is returned. + * + * ssl The SSL/TLS object. + * length The length of a signature. + * returns 0 on success, otherwise failure. + */ +int DecodePrivateKey(WOLFSSL *ssl, word16* length) +{ + int ret = BAD_FUNC_ARG; + int keySz; + word32 idx; + +#ifdef HAVE_PK_CALLBACKS + /* allow no private key if using PK callbacks and CB is set */ + if (wolfSSL_IsPrivatePkSet(ssl)) { + *length = GetPrivateKeySigSize(ssl); + return 0; + } + else +#endif + + /* make sure private key exists */ + if (ssl->buffers.key == NULL || ssl->buffers.key->buffer == NULL) { + WOLFSSL_MSG("Private key missing!"); + ERROR_OUT(NO_PRIVATE_KEY, exit_dpk); + } + +#ifdef HAVE_PKCS11 + if (ssl->buffers.keyDevId != INVALID_DEVID && ssl->buffers.keyId) { + if (ssl->buffers.keyType == rsa_sa_algo) + ssl->hsType = DYNAMIC_TYPE_RSA; + else if (ssl->buffers.keyType == ecc_dsa_sa_algo) + ssl->hsType = DYNAMIC_TYPE_ECC; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + + if (ssl->buffers.keyType == rsa_sa_algo) { + #ifndef NO_RSA + ret = wc_InitRsaKey_Id((RsaKey*)ssl->hsKey, + ssl->buffers.key->buffer, ssl->buffers.key->length, + ssl->heap, ssl->buffers.keyDevId); + if (ret == 0) { + if (ssl->buffers.keySz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + ERROR_OUT(RSA_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = (word16)ssl->buffers.keySz; + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else if (ssl->buffers.keyType == ecc_dsa_sa_algo) { + #ifdef HAVE_ECC + ret = wc_ecc_init_id((ecc_key*)ssl->hsKey, ssl->buffers.key->buffer, + ssl->buffers.key->length, ssl->heap, + ssl->buffers.keyDevId); + if (ret == 0) { + if (ssl->buffers.keySz < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = (word16)wc_ecc_sig_size_calc(ssl->buffers.keySz); + } + #else + ret = NOT_COMPILED_IN; + #endif + } + goto exit_dpk; + } +#endif + +#ifndef NO_RSA + if (ssl->buffers.keyType == rsa_sa_algo || ssl->buffers.keyType == 0) { + ssl->hsType = DYNAMIC_TYPE_RSA; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + + WOLFSSL_MSG("Trying RSA private key"); + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an RSA private key. */ + ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (RsaKey*)ssl->hsKey, ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using RSA private key"); + + /* It worked so check it meets minimum key size requirements. */ + keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsKey); + if (keySz < 0) { /* check if keySz has error case */ + ERROR_OUT(keySz, exit_dpk); + } + + if (keySz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + ERROR_OUT(RSA_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = (word16)keySz; + + goto exit_dpk; + } + } +#endif /* !NO_RSA */ + +#ifdef HAVE_ECC +#ifndef NO_RSA + FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); +#endif /* !NO_RSA */ + + if (ssl->buffers.keyType == ecc_dsa_sa_algo || ssl->buffers.keyType == 0) { + ssl->hsType = DYNAMIC_TYPE_ECC; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + + #ifndef NO_RSA + WOLFSSL_MSG("Trying ECC private key, RSA didn't work"); + #else + WOLFSSL_MSG("Trying ECC private key"); + #endif + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an ECC private key. */ + ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (ecc_key*)ssl->hsKey, + ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using ECC private key"); + + /* Check it meets the minimum ECC key size requirements. */ + keySz = wc_ecc_size((ecc_key*)ssl->hsKey); + if (keySz < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = (word16)wc_ecc_sig_size((ecc_key*)ssl->hsKey); + + goto exit_dpk; + } + } +#endif +#ifdef HAVE_ED25519 + #if !defined(NO_RSA) || defined(HAVE_ECC) + FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); + #endif + + if (ssl->buffers.keyType == ed25519_sa_algo || ssl->buffers.keyType == 0) { + ssl->hsType = DYNAMIC_TYPE_ED25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + + #ifdef HAVE_ECC + WOLFSSL_MSG("Trying ED25519 private key, ECC didn't work"); + #elif !defined(NO_RSA) + WOLFSSL_MSG("Trying ED25519 private key, RSA didn't work"); + #else + WOLFSSL_MSG("Trying ED25519 private key"); + #endif + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an ED25519 private key. */ + ret = wc_Ed25519PrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (ed25519_key*)ssl->hsKey, + ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using ED25519 private key"); + + /* Check it meets the minimum ECC key size requirements. */ + if (ED25519_KEY_SIZE < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ED25519 key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = ED25519_SIG_SIZE; + + goto exit_dpk; + } + } +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + #if !defined(NO_RSA) || defined(HAVE_ECC) + FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); + #endif + + if (ssl->buffers.keyType == ed448_sa_algo || ssl->buffers.keyType == 0) { + ssl->hsType = DYNAMIC_TYPE_ED448; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + + #ifdef HAVE_ED25519 + WOLFSSL_MSG("Trying ED448 private key, ED25519 didn't work"); + #elif defined(HAVE_ECC) + WOLFSSL_MSG("Trying ED448 private key, ECC didn't work"); + #elif !defined(NO_RSA) + WOLFSSL_MSG("Trying ED448 private key, RSA didn't work"); + #else + WOLFSSL_MSG("Trying ED447 private key"); + #endif + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an ED448 private key. */ + ret = wc_Ed448PrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (ed448_key*)ssl->hsKey, + ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using ED448 private key"); + + /* Check it meets the minimum ECC key size requirements. */ + if (ED448_KEY_SIZE < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ED448 key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = ED448_SIG_SIZE; + + goto exit_dpk; + } + } +#endif /* HAVE_ED448 */ + + (void)idx; + (void)keySz; + (void)length; +exit_dpk: + return ret; +} + +#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */ + +/* client only parts */ +#ifndef NO_WOLFSSL_CLIENT + +#ifndef WOLFSSL_NO_TLS12 + + /* handle generation of client_hello (1) */ + int SendClientHello(WOLFSSL* ssl) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int idSz = ssl->options.resuming + ? ssl->session.sessionIDSz + : 0; + int ret; + word16 extSz = 0; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + return SendTls13ClientHello(ssl); +#endif + + WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND); + WOLFSSL_ENTER("SendClientHello"); + + if (ssl->suites == NULL) { + WOLFSSL_MSG("Bad suites pointer in SendClientHello"); + return SUITES_ERROR; + } + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.resuming && ssl->session.ticketLen > 0) { + SessionTicket* ticket; + + ticket = TLSX_SessionTicket_Create(0, ssl->session.ticket, + ssl->session.ticketLen, ssl->heap); + if (ticket == NULL) return MEMORY_E; + + ret = TLSX_UseSessionTicket(&ssl->extensions, ticket, ssl->heap); + if (ret != WOLFSSL_SUCCESS) { + TLSX_SessionTicket_Free(ticket, ssl->heap); + return ret; + } + + idSz = 0; + } +#endif + length = VERSION_SZ + RAN_LEN + + idSz + ENUM_LEN + + ssl->suites->suiteSz + SUITE_LEN + + COMP_LEN + ENUM_LEN; + +#ifdef HAVE_TLS_EXTENSIONS + /* auto populate extensions supported unless user defined */ + if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) + return ret; + #ifdef HAVE_QSH + if (QSH_Init(ssl) != 0) + return MEMORY_E; + #endif + extSz = 0; + ret = TLSX_GetRequestSize(ssl, client_hello, &extSz); + if (ret != 0) + return ret; + length += extSz; +#else + if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) + extSz += HELLO_EXT_SZ + HELLO_EXT_SIGALGO_SZ + + ssl->suites->hashSigAlgoSz; +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) + extSz += HELLO_EXT_SZ; +#endif + if (extSz != 0) + length += extSz + HELLO_EXT_SZ_SZ; +#endif + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + length += ENUM_LEN; /* cookie */ + if (ssl->arrays->cookieSz != 0) length += ssl->arrays->cookieSz; + sendSz = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ; + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + } +#endif + + if (IsEncryptionOn(ssl, 1)) + sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, client_hello, ssl); + + /* client hello, first version */ + output[idx++] = ssl->version.major; + output[idx++] = ssl->version.minor; + ssl->chVersion = ssl->version; /* store in case changed */ + + /* then random */ + if (ssl->options.connectState == CONNECT_BEGIN) { + ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + if (ret != 0) + return ret; + + /* store random */ + XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN); + } else { +#ifdef WOLFSSL_DTLS + /* send same random on hello again */ + XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); +#endif + } + idx += RAN_LEN; + + /* then session id */ + output[idx++] = (byte)idSz; + if (idSz) { + XMEMCPY(output + idx, ssl->session.sessionID, + ssl->session.sessionIDSz); + idx += ssl->session.sessionIDSz; + } + + /* then DTLS cookie */ +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + byte cookieSz = ssl->arrays->cookieSz; + + output[idx++] = cookieSz; + if (cookieSz) { + XMEMCPY(&output[idx], ssl->arrays->cookie, cookieSz); + idx += cookieSz; + } + } +#endif + /* then cipher suites */ + c16toa(ssl->suites->suiteSz, output + idx); + idx += OPAQUE16_LEN; + XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); + idx += ssl->suites->suiteSz; + + /* last, compression */ + output[idx++] = COMP_LEN; + if (ssl->options.usingCompression) + output[idx++] = ZLIB_COMPRESSION; + else + output[idx++] = NO_COMPRESSION; + +#ifdef HAVE_TLS_EXTENSIONS + extSz = 0; + ret = TLSX_WriteRequest(ssl, output + idx, client_hello, &extSz); + if (ret != 0) + return ret; + idx += extSz; + + (void)idx; /* suppress analyzer warning, keep idx current */ +#else + if (extSz != 0) { + c16toa(extSz, output + idx); + idx += HELLO_EXT_SZ_SZ; + + if (IsAtLeastTLSv1_2(ssl)) { + if (ssl->suites->hashSigAlgoSz) { + word16 i; + /* extension type */ + c16toa(HELLO_EXT_SIG_ALGO, output + idx); + idx += HELLO_EXT_TYPE_SZ; + /* extension data length */ + c16toa(HELLO_EXT_SIGALGO_SZ + ssl->suites->hashSigAlgoSz, + output + idx); + idx += HELLO_EXT_SZ_SZ; + /* sig algos length */ + c16toa(ssl->suites->hashSigAlgoSz, output + idx); + idx += HELLO_EXT_SIGALGO_SZ; + for (i=0; i < ssl->suites->hashSigAlgoSz; i++, idx++) { + output[idx] = ssl->suites->hashSigAlgo[i]; + } + } + } +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + c16toa(HELLO_EXT_EXTMS, output + idx); + idx += HELLO_EXT_TYPE_SZ; + c16toa(0, output + idx); + idx += HELLO_EXT_SZ_SZ; + } +#endif + } +#endif + + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */ + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } else { + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + } + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; +#ifdef OPENSSL_EXTRA + ssl->cbmode = SSL_CB_MODE_WRITE; + if (ssl->CBIS != NULL) + ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS); +#endif + +#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "ClientHello", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND); + + return ret; + } + + + /* handle processing of DTLS hello_verify_request (3) */ + static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) + { + ProtocolVersion pv; + byte cookieSz; + word32 begin = *inOutIdx; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "HelloVerifyRequest"); + if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); +#endif + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + DtlsMsgPoolReset(ssl); + } +#endif + + if (OPAQUE16_LEN + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + XMEMCPY(&pv, input + *inOutIdx, OPAQUE16_LEN); + *inOutIdx += OPAQUE16_LEN; + + if (pv.major != DTLS_MAJOR || + (pv.minor != DTLS_MINOR && pv.minor != DTLSv1_2_MINOR)) + return VERSION_ERROR; + + cookieSz = input[(*inOutIdx)++]; + + if (cookieSz) { + if ((*inOutIdx - begin) + cookieSz > size) + return BUFFER_ERROR; + +#ifdef WOLFSSL_DTLS + if (cookieSz <= MAX_COOKIE_LEN) { + XMEMCPY(ssl->arrays->cookie, input + *inOutIdx, cookieSz); + ssl->arrays->cookieSz = cookieSz; + } +#endif + *inOutIdx += cookieSz; + } + + ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + return 0; + } + + + static WC_INLINE int DSH_CheckSessionId(WOLFSSL* ssl) + { + int ret = 0; + +#ifdef HAVE_SECRET_CALLBACK + /* If a session secret callback exists, we are using that + * key instead of the saved session key. */ + ret = ret || (ssl->sessionSecretCb != NULL); +#endif + +#ifdef HAVE_SESSION_TICKET + /* server may send blank ticket which may not be expected to indicate + * existing one ok but will also be sending a new one */ + ret = ret || (ssl->session.ticketLen > 0); +#endif + + ret = ret || + (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, + ssl->session.sessionID, ID_LEN) == 0); + + return ret; + } + + /* Check the version in the received message is valid and set protocol + * version to use. + * + * ssl The SSL/TLS object. + * pv The protocol version from the packet. + * returns 0 on success, otherwise failure. + */ + int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv) + { + #ifdef WOLFSSL_TLS13_DRAFT + if (pv.major == TLS_DRAFT_MAJOR) { + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_3_MINOR; + } + #endif + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_HANDSHAKE_START, SSL_SUCCESS); + } + #endif + + if (pv.minor > ssl->version.minor) { + WOLFSSL_MSG("Server using higher version, fatal error"); + return VERSION_ERROR; + } + if (pv.minor < ssl->version.minor) { + WOLFSSL_MSG("server using lower version"); + + /* Check for downgrade attack. */ + if (!ssl->options.downgrade) { + WOLFSSL_MSG("\tno downgrade allowed, fatal error"); + return VERSION_ERROR; + } + if (pv.minor < ssl->options.minDowngrade) { + WOLFSSL_MSG("\tversion below minimum allowed, fatal error"); + return VERSION_ERROR; + } + + #ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->enabled && + ssl->options.handShakeDone) { + WOLFSSL_MSG("Server changed version during scr"); + return VERSION_ERROR; + } + #endif + + /* Checks made - OK to downgrade. */ + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + WOLFSSL_MSG("\tdowngrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + /* turn off tls 1.1+ */ + WOLFSSL_MSG("\tdowngrading to TLSv1"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + WOLFSSL_MSG("\tdowngrading to TLSv1.1"); + ssl->version.minor = TLSv1_1_MINOR; + } + else if (pv.minor == TLSv1_2_MINOR) { + WOLFSSL_MSG(" downgrading to TLSv1.2"); + ssl->version.minor = TLSv1_2_MINOR; + } + } + +#ifdef OPENSSL_EXTRA + /* check if option is set to not allow the current version + * set from either wolfSSL_set_options or wolfSSL_CTX_set_options */ + if (!ssl->options.dtls && ssl->options.downgrade && + ssl->options.mask > 0) { + if (ssl->version.minor == TLSv1_2_MINOR && + (ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) { + WOLFSSL_MSG("\tOption set to not allow TLSv1.2, Downgrading"); + ssl->version.minor = TLSv1_1_MINOR; + } + if (ssl->version.minor == TLSv1_1_MINOR && + (ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) { + WOLFSSL_MSG("\tOption set to not allow TLSv1.1, Downgrading"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + if (ssl->version.minor == TLSv1_MINOR && + (ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) { + WOLFSSL_MSG("\tOption set to not allow TLSv1, Downgrading"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + if (ssl->version.minor == SSLv3_MINOR && + (ssl->options.mask & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) { + WOLFSSL_MSG("\tError, option set to not allow SSLv3"); + return VERSION_ERROR; + } + + if (ssl->version.minor < ssl->options.minDowngrade) { + WOLFSSL_MSG("\tversion below minimum allowed, fatal error"); + return VERSION_ERROR; + } + } +#endif + + return 0; + } + + /* handle processing of server_hello (2) */ + int DoServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte cs0; /* cipher suite bytes 0, 1 */ + byte cs1; + ProtocolVersion pv; + byte compression; + word32 i = *inOutIdx; + word32 begin = i; + int ret; + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_DO); + WOLFSSL_ENTER("DoServerHello"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ServerHello"); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(pv)) { + byte type = server_hello; + return DoTls13ServerHello(ssl, input, inOutIdx, helloSz, &type); + } +#endif + + /* random */ + XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); + i += RAN_LEN; + + /* session id */ + ssl->arrays->sessionIDSz = input[i++]; + + if (ssl->arrays->sessionIDSz > ID_LEN) { + WOLFSSL_MSG("Invalid session ID size"); + ssl->arrays->sessionIDSz = 0; + return BUFFER_ERROR; + } + else if (ssl->arrays->sessionIDSz) { + if ((i - begin) + ssl->arrays->sessionIDSz > helloSz) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->sessionID, input + i, + ssl->arrays->sessionIDSz); + i += ssl->arrays->sessionIDSz; + ssl->options.haveSessionId = 1; + } + + + /* suite and compression */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + cs0 = input[i++]; + cs1 = input[i++]; + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled && + ssl->options.handShakeDone) { + if (ssl->options.cipherSuite0 != cs0 || + ssl->options.cipherSuite != cs1) { + WOLFSSL_MSG("Server changed cipher suite during scr"); + return MATCH_SUITE_ERROR; + } + } +#endif + + ssl->options.cipherSuite0 = cs0; + ssl->options.cipherSuite = cs1; + compression = input[i++]; + +#ifndef WOLFSSL_NO_STRICT_CIPHER_SUITE + { + word32 idx, found = 0; + /* confirm server_hello cipher suite is one sent in client_hello */ + for (idx = 0; idx < ssl->suites->suiteSz; idx += 2) { + if (ssl->suites->suites[idx] == cs0 && + ssl->suites->suites[idx+1] == cs1) { + found = 1; + break; + } + } + if (!found) { + WOLFSSL_MSG("ServerHello did not use cipher suite from ClientHello"); + return MATCH_SUITE_ERROR; + } + } +#endif /* !WOLFSSL_NO_STRICT_CIPHER_SUITE */ + + if (compression != NO_COMPRESSION && !ssl->options.usingCompression) { + WOLFSSL_MSG("Server forcing compression w/o support"); + return COMPRESSION_ERROR; + } + + if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) { + WOLFSSL_MSG("Server refused compression, turning off"); + ssl->options.usingCompression = 0; /* turn off if server refused */ + } + + *inOutIdx = i; + +#ifdef HAVE_TLS_EXTENSIONS + if ( (i - begin) < helloSz) { + if (TLSX_SupportExtensions(ssl)) { + word16 totalExtSz; + + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, + server_hello, NULL))) + return ret; + + i += totalExtSz; + *inOutIdx = i; + } + else + *inOutIdx = begin + helloSz; /* skip extensions */ + } + else + ssl->options.haveEMS = 0; /* If no extensions, no EMS */ +#else + { + int allowExt = 0; + byte pendingEMS = 0; + + if ( (i - begin) < helloSz) { + if (ssl->version.major == SSLv3_MAJOR && + ssl->version.minor >= TLSv1_MINOR) { + + allowExt = 1; + } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) + allowExt = 1; +#endif + + if (allowExt) { + word16 totalExtSz; + + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + while (totalExtSz) { + word16 extId, extSz; + + if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz) + return BUFFER_ERROR; + + ato16(&input[i], &extId); + i += OPAQUE16_LEN; + ato16(&input[i], &extSz); + i += OPAQUE16_LEN; + + if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz) + return BUFFER_ERROR; + + if (extId == HELLO_EXT_EXTMS) + pendingEMS = 1; + else + i += extSz; + + totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz; + } + + *inOutIdx = i; + } + else + *inOutIdx = begin + helloSz; /* skip extensions */ + } + + if (!pendingEMS && ssl->options.haveEMS) + ssl->options.haveEMS = 0; + } +#endif + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + if (IsEncryptionOn(ssl, 0)) { + *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMWrite && + ssl->specs.cipher_type == block) { + *inOutIdx += MacSize(ssl); + } + #endif + } + +#ifdef HAVE_SECRET_CALLBACK + if (ssl->sessionSecretCb != NULL) { + int secretSz = SECRET_LEN; + ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, + &secretSz, ssl->sessionSecretCtx); + if (ret != 0 || secretSz != SECRET_LEN) + return SESSION_SECRET_CB_E; + } +#endif /* HAVE_SECRET_CALLBACK */ + + ret = CompleteServerHello(ssl); + + WOLFSSL_LEAVE("DoServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_DO); + + return ret; + } + +#ifdef WOLFSSL_TLS13 + /* returns 1 if able to do TLS 1.3 otherwise 0 */ + static int TLSv1_3_Capable(WOLFSSL* ssl) + { + #ifndef WOLFSSL_TLS13 + return 0; + #else + int ret = 0; + + if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) { + ret = 1; + } + + #ifdef OPENSSL_EXTRA + if ((wolfSSL_get_options(ssl) & SSL_OP_NO_TLSv1_3)) { + /* option set at run time to disable TLS 1.3 */ + ret = 0; + } + #endif + return ret; + #endif + } +#endif /* WOLFSSL_TLS13 */ + + int CompleteServerHello(WOLFSSL* ssl) + { + int ret; + + if (!ssl->options.resuming) { + byte* down = ssl->arrays->serverRandom + RAN_LEN - + TLS13_DOWNGRADE_SZ - 1; + byte vers = ssl->arrays->serverRandom[RAN_LEN - 1]; + #ifdef WOLFSSL_TLS13 + if (TLSv1_3_Capable(ssl)) { + /* TLS v1.3 capable client not allowed to downgrade when + * connecting to TLS v1.3 capable server unless cipher suite + * demands it. + */ + if (XMEMCMP(down, tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 && + (vers == 0 || vers == 1)) { + SendAlert(ssl, alert_fatal, illegal_parameter); + return VERSION_ERROR; + } + } + else + #endif + if (ssl->ctx->method->version.major == SSLv3_MAJOR && + ssl->ctx->method->version.minor == TLSv1_2_MINOR) { + /* TLS v1.2 capable client not allowed to downgrade when + * connecting to TLS v1.2 capable server. + */ + if (XMEMCMP(down, tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 && + vers == 0) { + SendAlert(ssl, alert_fatal, illegal_parameter); + return VERSION_ERROR; + } + } + } + else { + if (DSH_CheckSessionId(ssl)) { + if (SetCipherSpecs(ssl) == 0) { + + XMEMCPY(ssl->arrays->masterSecret, + ssl->session.masterSecret, SECRET_LEN); + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + ret = -1; /* default value */ + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif /* NO_OLD_TLS */ + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + + return ret; + } + else { + WOLFSSL_MSG("Unsupported cipher suite, DoServerHello"); + return UNSUPPORTED_SUITE; + } + } + else { + WOLFSSL_MSG("Server denied resumption attempt"); + ssl->options.resuming = 0; /* server denied resumption try */ + } + } + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + DtlsMsgPoolReset(ssl); + } + #endif + + return SetCipherSpecs(ssl); + } + +#endif /* WOLFSSL_NO_TLS12 */ + + + /* Make sure client setup is valid for this suite, true on success */ + int VerifyClientSuite(WOLFSSL* ssl) + { + int havePSK = 0; + byte first = ssl->options.cipherSuite0; + byte second = ssl->options.cipherSuite; + + WOLFSSL_ENTER("VerifyClientSuite"); + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + + if (CipherRequires(first, second, REQUIRES_PSK)) { + WOLFSSL_MSG("Requires PSK"); + if (havePSK == 0) { + WOLFSSL_MSG("Don't have PSK"); + return 0; + } + } + + return 1; /* success */ + } + +#ifndef WOLFSSL_NO_TLS12 + +#ifndef NO_CERTS + /* handle processing of certificate_request (13) */ + static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32* + inOutIdx, word32 size) + { + word16 len; + word32 begin = *inOutIdx; + #ifdef OPENSSL_EXTRA + int ret; + WOLFSSL_X509* x509 = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + #endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_DO); + WOLFSSL_ENTER("DoCertificateRequest"); + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateRequest"); + if (ssl->toInfoOn) + AddLateName("CertificateRequest", &ssl->timeoutInfo); + #endif + + if (OPAQUE8_LEN > size) + return BUFFER_ERROR; + + len = input[(*inOutIdx)++]; + + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + /* types, read in here */ + *inOutIdx += len; + + /* signature and hash signature algorithm */ + if (IsAtLeastTLSv1_2(ssl)) { + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + if (PickHashSigAlgo(ssl, input + *inOutIdx, len) != 0 && + ssl->buffers.certificate && + ssl->buffers.certificate->buffer) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + WOLFSSL_MSG("Using PK for client private key"); + return INVALID_PARAMETER; + } + #endif + if (ssl->buffers.key && ssl->buffers.key->buffer) { + return INVALID_PARAMETER; + } + } + *inOutIdx += len; + #ifdef WC_RSA_PSS + ssl->pssAlgo = 0; + if (ssl->suites->sigAlgo == rsa_pss_sa_algo) + ssl->pssAlgo |= 1 << ssl->suites->hashAlgo; + #endif + } + + /* authorities */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + while (len) { + word16 dnSz; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &dnSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + dnSz > size) + return BUFFER_ERROR; + + *inOutIdx += dnSz; + len -= OPAQUE16_LEN + dnSz; + } + + #ifdef OPENSSL_EXTRA + /* call client cert callback if no cert has been loaded */ + if ((ssl->ctx->CBClientCert != NULL) && + (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer)) { + + ret = ssl->ctx->CBClientCert(ssl, &x509, &pkey); + if (ret == 1) { + if ((wolfSSL_use_certificate(ssl, x509) != WOLFSSL_SUCCESS) || + (wolfSSL_use_PrivateKey(ssl, pkey) != WOLFSSL_SUCCESS)) { + return CLIENT_CERT_CB_ERROR; + } + wolfSSL_X509_free(x509); + wolfSSL_EVP_PKEY_free(pkey); + + } else if (ret < 0) { + return WOLFSSL_ERROR_WANT_X509_LOOKUP; + } + } + #endif + + /* don't send client cert or cert verify if user hasn't provided + cert and private key */ + if (ssl->buffers.certificate && ssl->buffers.certificate->buffer) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + WOLFSSL_MSG("Using PK for client private key"); + ssl->options.sendVerify = SEND_CERT; + } + #endif + if (ssl->buffers.key && ssl->buffers.key->buffer) { + ssl->options.sendVerify = SEND_CERT; + } + } + #ifdef OPENSSL_EXTRA + else + #else + else if (IsTLS(ssl)) + #endif + { + ssl->options.sendVerify = SEND_BLANK_CERT; + } + + if (IsEncryptionOn(ssl, 0)) { + *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + *inOutIdx += MacSize(ssl); + #endif + } + + WOLFSSL_LEAVE("DoCertificateRequest", 0); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO); + + return 0; + } +#endif /* !NO_CERTS */ + + +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + + static int CheckCurveId(int tlsCurveId) + { + int ret = ECC_CURVE_ERROR; + + switch (tlsCurveId) { + #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP160R1: return ECC_SECP160R1_OID; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + case WOLFSSL_ECC_SECP160R2: return ECC_SECP160R2_OID; + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP160K1: return ECC_SECP160K1_OID; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP192R1: return ECC_SECP192R1_OID; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP192K1: return ECC_SECP192K1_OID; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP224R1: return ECC_SECP224R1_OID; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP224K1: return ECC_SECP224K1_OID; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: return ECC_X25519_OID; + #endif + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: return ECC_SECP256R1_OID; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP256K1: return ECC_SECP256K1_OID; + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP256R1: return ECC_BRAINPOOLP256R1_OID; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #ifdef HAVE_CURVE448 + case WOLFSSL_ECC_X448: return ECC_X448_OID; + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: return ECC_SECP384R1_OID; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP384R1: return ECC_BRAINPOOLP384R1_OID; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP512R1: return ECC_BRAINPOOLP512R1_OID; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: return ECC_SECP521R1_OID; + #endif /* !NO_ECC_SECP */ + #endif + } + + return ret; + } + +#endif /* HAVE_ECC */ + +/* Persistable DoServerKeyExchange arguments */ +typedef struct DskeArgs { + byte* output; /* not allocated */ +#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + byte* verifySig; +#endif + word32 idx; + word32 begin; +#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + word16 verifySigSz; +#endif + word16 sigSz; + byte sigAlgo; + byte hashAlgo; +#if !defined(NO_RSA) && defined(WC_RSA_PSS) + int bits; +#endif +} DskeArgs; + +static void FreeDskeArgs(WOLFSSL* ssl, void* pArgs) +{ + DskeArgs* args = (DskeArgs*)pArgs; + + (void)ssl; + (void)args; + +#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + if (args->verifySig) { + XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->verifySig = NULL; + } +#endif +} + +#ifndef NO_DH +static int GetDhPublicKey(WOLFSSL* ssl, const byte* input, word32 size, + DskeArgs* args) +{ + int ret = 0; + word16 length; +#ifdef HAVE_FFDHE + const DhParams* params = NULL; + int group = 0; +#endif + + ssl->buffers.weOwnDH = 1; + + ssl->buffers.serverDH_P.buffer = NULL; + ssl->buffers.serverDH_G.buffer = NULL; + ssl->buffers.serverDH_Pub.buffer = NULL; + + /* p */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_gdpk); + } + + ato16(input + args->idx, &length); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_gdpk); + } + + if (length < ssl->options.minDhKeySz) { + WOLFSSL_MSG("Server using a DH key that is too small"); + SendAlert(ssl, alert_fatal, handshake_failure); + ERROR_OUT(DH_KEY_SIZE_E, exit_gdpk); + } + if (length > ssl->options.maxDhKeySz) { + WOLFSSL_MSG("Server using a DH key that is too big"); + SendAlert(ssl, alert_fatal, handshake_failure); + ERROR_OUT(DH_KEY_SIZE_E, exit_gdpk); + } + + ssl->buffers.serverDH_P.buffer = + (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ssl->buffers.serverDH_P.buffer) { + ssl->buffers.serverDH_P.length = length; + } + else { + ERROR_OUT(MEMORY_ERROR, exit_gdpk); + } + + XMEMCPY(ssl->buffers.serverDH_P.buffer, input + args->idx, + length); + args->idx += length; + + ssl->options.dhKeySz = length; + + /* g */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_gdpk); + } + + ato16(input + args->idx, &length); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_gdpk); + } + + ssl->buffers.serverDH_G.buffer = + (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ssl->buffers.serverDH_G.buffer) { + ssl->buffers.serverDH_G.length = length; + } + else { + ERROR_OUT(MEMORY_ERROR, exit_gdpk); + } + + XMEMCPY(ssl->buffers.serverDH_G.buffer, input + args->idx, + length); + args->idx += length; + + /* pub */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_gdpk); + } + + ato16(input + args->idx, &length); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_gdpk); + } + + ssl->buffers.serverDH_Pub.buffer = + (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ssl->buffers.serverDH_Pub.buffer) { + ssl->buffers.serverDH_Pub.length = length; + } + else { + ERROR_OUT(MEMORY_ERROR, exit_gdpk); + } + + XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + args->idx, + length); + args->idx += length; + +#ifdef HAVE_FFDHE + switch (ssl->options.dhKeySz) { + #ifdef HAVE_FFDHE_2048 + case 2048/8: + params = wc_Dh_ffdhe2048_Get(); + group = WOLFSSL_FFDHE_2048; + break; + #endif + #ifdef HAVE_FFDHE_3072 + case 3072/8: + params = wc_Dh_ffdhe3072_Get(); + group = WOLFSSL_FFDHE_3072; + break; + #endif + #ifdef HAVE_FFDHE_4096 + case 4096/8: + params = wc_Dh_ffdhe4096_Get(); + group = WOLFSSL_FFDHE_4096; + break; + #endif + #ifdef HAVE_FFDHE_6144 + case 6144/8: + params = wc_Dh_ffdhe6144_Get(); + group = WOLFSSL_FFDHE_6144; + break; + #endif + #ifdef HAVE_FFDHE_8192 + case 8192/8: + params = wc_Dh_ffdhe8192_Get(); + group = WOLFSSL_FFDHE_8192; + break; + #endif + default: + break; + } + + if (params == NULL || params->g_len != ssl->buffers.serverDH_G.length || + (XMEMCMP(ssl->buffers.serverDH_G.buffer, params->g, + params->g_len) != 0) || + (XMEMCMP(ssl->buffers.serverDH_P.buffer, params->p, + params->p_len) != 0)) { + WOLFSSL_MSG("Server not using FFDHE parameters"); + #ifdef WOLFSSL_REQUIRE_FFDHE + SendAlert(ssl, alert_fatal, handshake_failure); + ERROR_OUT(DH_PARAMS_NOT_FFDHE_E, exit_gdpk); + #endif + } + else { + ssl->namedGroup = group; + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ssl->options.dhDoKeyTest = 0; + #endif + } +#endif /* HAVE_FFDHE */ + +exit_gdpk: + return ret; +} +#endif + +/* handle processing of server_key_exchange (12) */ +static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ + int ret = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + DskeArgs* args = (DskeArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + DskeArgs args[1]; +#endif + + (void)input; + (void)size; + + WOLFSSL_START(WC_FUNC_SERVER_KEY_EXCHANGE_DO); + WOLFSSL_ENTER("DoServerKeyExchange"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_dske; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(DskeArgs)); + args->idx = *inOutIdx; + args->begin = *inOutIdx; + args->sigAlgo = ssl->specs.sig_algo; + args->hashAlgo = sha_mac; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeDskeArgs; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "ServerKeyExchange"); + if (ssl->toInfoOn) + AddLateName("ServerKeyExchange", &ssl->timeoutInfo); + #endif + + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + int srvHintLen; + word16 length; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + ato16(input + args->idx, &length); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + /* get PSK server hint from the wire */ + srvHintLen = min(length, MAX_PSK_ID_LEN); + XMEMCPY(ssl->arrays->server_hint, input + args->idx, + srvHintLen); + ssl->arrays->server_hint[srvHintLen] = '\0'; /* null term */ + args->idx += length; + break; + } + #endif /* !NO_PSK */ + #ifndef NO_DH + case diffie_hellman_kea: + { + ret = GetDhPublicKey(ssl, input, size, args); + if (ret != 0) + goto exit_dske; + break; + } + #endif /* !NO_DH */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + byte b; + #ifdef HAVE_ECC + int curveId; + #endif + int curveOid; + word16 length; + + if ((args->idx - args->begin) + ENUM_LEN + OPAQUE16_LEN + + OPAQUE8_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + b = input[args->idx++]; + if (b != named_curve) { + ERROR_OUT(ECC_CURVETYPE_ERROR, exit_dske); + } + + args->idx += 1; /* curve type, eat leading 0 */ + b = input[args->idx++]; + if ((curveOid = CheckCurveId(b)) < 0) { + ERROR_OUT(ECC_CURVE_ERROR, exit_dske); + } + ssl->ecdhCurveOID = curveOid; + #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE) + ssl->namedGroup = 0; + #endif + + length = input[args->idx++]; + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (ssl->peerX25519Key == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerX25519KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } + } + + if ((ret = wc_curve25519_check_public( + input + args->idx, length, + EC25519_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + if (wc_curve25519_import_public_ex(input + args->idx, + length, ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerX25519KeyPresent = 1; + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + if (ssl->peerX448Key == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerX448KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE448, + ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } + } + + if ((ret = wc_curve448_check_public( + input + args->idx, length, + EC448_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + if (wc_curve448_import_public_ex(input + args->idx, + length, ssl->peerX448Key, + EC448_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerX448KeyPresent = 1; + break; + } + #endif + #ifdef HAVE_ECC + if (ssl->peerEccKey == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } + } + + curveId = wc_ecc_get_oid(curveOid, NULL, NULL); + if (wc_ecc_import_x963_ex(input + args->idx, length, + ssl->peerEccKey, curveId) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, illegal_parameter); + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerEccKeyPresent = 1; + #endif + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + int srvHintLen; + word16 length; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + ato16(input + args->idx, &length); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + /* get PSK server hint from the wire */ + srvHintLen = min(length, MAX_PSK_ID_LEN); + XMEMCPY(ssl->arrays->server_hint, input + args->idx, + srvHintLen); + ssl->arrays->server_hint[srvHintLen] = '\0'; /* null term */ + args->idx += length; + + ret = GetDhPublicKey(ssl, input, size, args); + if (ret != 0) + goto exit_dske; + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + byte b; + int curveOid, curveId; + int srvHintLen; + word16 length; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + ato16(input + args->idx, &length); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + /* get PSK server hint from the wire */ + srvHintLen = min(length, MAX_PSK_ID_LEN); + XMEMCPY(ssl->arrays->server_hint, input + args->idx, + srvHintLen); + ssl->arrays->server_hint[srvHintLen] = '\0'; /* null term */ + + args->idx += length; + + if ((args->idx - args->begin) + ENUM_LEN + OPAQUE16_LEN + + OPAQUE8_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + /* Check curve name and ID */ + b = input[args->idx++]; + if (b != named_curve) { + ERROR_OUT(ECC_CURVETYPE_ERROR, exit_dske); + } + + args->idx += 1; /* curve type, eat leading 0 */ + b = input[args->idx++]; + if ((curveOid = CheckCurveId(b)) < 0) { + ERROR_OUT(ECC_CURVE_ERROR, exit_dske); + } + + length = input[args->idx++]; + if ((args->idx - args->begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (ssl->peerX25519Key == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } + } + + if ((ret = wc_curve25519_check_public( + input + args->idx, length, + EC25519_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + if (wc_curve25519_import_public_ex(input + args->idx, + length, ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerX25519KeyPresent = 1; + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + if (ssl->peerX448Key == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE448, + ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } + } + + if ((ret = wc_curve448_check_public( + input + args->idx, length, + EC448_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + if (wc_curve448_import_public_ex(input + args->idx, + length, ssl->peerX448Key, + EC448_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerX448KeyPresent = 1; + break; + } + #endif + + if (ssl->peerEccKey == NULL) { + ret = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + if (ret != 0) { + goto exit_dske; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + if (ret != 0) { + goto exit_dske; + } + } + + curveId = wc_ecc_get_oid(curveOid, NULL, NULL); + if (wc_ecc_import_x963_ex(input + args->idx, length, + ssl->peerEccKey, curveId) != 0) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dske); + } + + args->idx += length; + ssl->peerEccKeyPresent = 1; + break; + } + #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) && !NO_PSK */ + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + switch(ssl->specs.kea) + { + case psk_kea: + case dhe_psk_kea: + case ecdhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + + case diffie_hellman_kea: + case ecc_diffie_hellman_kea: + { + #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) \ + && !defined(HAVE_ED448) + ERROR_OUT(NOT_COMPILED_IN, exit_dske); + #else + enum wc_HashType hashType; + word16 verifySz; + + if (ssl->options.usingAnon_cipher) { + break; + } + + verifySz = (word16)(args->idx - args->begin); + if (verifySz > MAX_DH_SZ) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + if (IsAtLeastTLSv1_2(ssl)) { + if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > + size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + DecodeSigAlg(&input[args->idx], &args->hashAlgo, + &args->sigAlgo); + args->idx += 2; + hashType = HashAlgoToType(args->hashAlgo); + if (hashType == WC_HASH_TYPE_NONE) { + ERROR_OUT(ALGO_ID_E, exit_dske); + } + } else { + /* only using sha and md5 for rsa */ + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + if (args->sigAlgo == rsa_sa_algo) { + hashType = WC_HASH_TYPE_MD5_SHA; + } + #else + ERROR_OUT(ALGO_ID_E, exit_dske); + #endif + } + + /* signature */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + ato16(input + args->idx, &args->verifySigSz); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + args->verifySigSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + + /* buffer for signature */ + ssl->buffers.sig.buffer = (byte*)XMALLOC(SEED_LEN + verifySz, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_dske); + } + ssl->buffers.sig.length = SEED_LEN + verifySz; + + /* build message to hash */ + XMEMCPY(ssl->buffers.sig.buffer, + ssl->arrays->clientRandom, RAN_LEN); + XMEMCPY(&ssl->buffers.sig.buffer[RAN_LEN], + ssl->arrays->serverRandom, RAN_LEN); + XMEMCPY(&ssl->buffers.sig.buffer[RAN_LEN * 2], + input + args->begin, verifySz); /* message */ + + if (args->sigAlgo != ed25519_sa_algo) { + int digest_sz = wc_HashGetDigestSize(hashType); + if (digest_sz <= 0) { + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + ssl->buffers.digest.length = (unsigned int)digest_sz; + + /* buffer for hash */ + ssl->buffers.digest.buffer = (byte*)XMALLOC( + ssl->buffers.digest.length, ssl->heap, + DYNAMIC_TYPE_DIGEST); + if (ssl->buffers.digest.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_dske); + } + + /* Perform hash */ + ret = wc_Hash(hashType, ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->buffers.digest.buffer, + ssl->buffers.digest.length); + if (ret != 0) { + goto exit_dske; + } + } + + switch (args->sigAlgo) + { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + if (ssl->peerRsaKey == NULL || + !ssl->peerRsaKeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_dske); + } + break; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + { + if (!ssl->peerEccDsaKeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_dske); + } + break; + } + #endif /* HAVE_ECC */ + #if defined(HAVE_ED25519) + case ed25519_sa_algo: + { + if (!ssl->peerEd25519KeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_dske); + } + break; + } + #endif /* HAVE_ED25519 */ + #if defined(HAVE_ED448) + case ed448_sa_algo: + { + if (!ssl->peerEd448KeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_dske); + } + break; + } + #endif /* HAVE_ED448 */ + + default: + ret = ALGO_ID_E; + } /* switch (args->sigAlgo) */ + + #endif /* NO_DH && !HAVE_ECC && !HAVE_ED25519 && !HAVE_ED448 */ + break; + } + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + switch(ssl->specs.kea) + { + case psk_kea: + case dhe_psk_kea: + case ecdhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + + case diffie_hellman_kea: + case ecc_diffie_hellman_kea: + { + #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) \ + && !defined(HAVE_ED448) + ERROR_OUT(NOT_COMPILED_IN, exit_dske); + #else + if (ssl->options.usingAnon_cipher) { + break; + } + + if (args->verifySig == NULL) { + args->verifySig = (byte*)XMALLOC(args->verifySigSz, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (args->verifySig == NULL) { + ERROR_OUT(MEMORY_E, exit_dske); + } + XMEMCPY(args->verifySig, input + args->idx, + args->verifySigSz); + } + + switch (args->sigAlgo) + { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + ret = RsaVerify(ssl, + args->verifySig, args->verifySigSz, + &args->output, + args->sigAlgo, args->hashAlgo, + ssl->peerRsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerRsaKey + #else + NULL + #endif + ); + + if (ret >= 0) { + args->sigSz = (word16)ret; + #ifdef WC_RSA_PSS + args->bits = mp_count_bits(&ssl->peerRsaKey->n); + #endif + ret = 0; + } + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + /* peerRsaKey */ + FreeKey(ssl, DYNAMIC_TYPE_RSA, + (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; + } + break; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + { + ret = EccVerify(ssl, + args->verifySig, args->verifySigSz, + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + ssl->peerEccDsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEccDsaKey + #else + NULL + #endif + ); + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + /* peerEccDsaKey */ + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + break; + } + #endif /* HAVE_ECC */ + #if defined(HAVE_ED25519) + case ed25519_sa_algo: + { + ret = Ed25519Verify(ssl, + args->verifySig, args->verifySigSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd25519Key + #else + NULL + #endif + ); + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + /* peerEccDsaKey */ + FreeKey(ssl, DYNAMIC_TYPE_ED25519, + (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + } + break; + } + #endif /* HAVE_ED25519 */ + #if defined(HAVE_ED448) + case ed448_sa_algo: + { + ret = Ed448Verify(ssl, + args->verifySig, args->verifySigSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->peerEd448Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd448Key + #else + NULL + #endif + ); + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + /* peerEccDsaKey */ + FreeKey(ssl, DYNAMIC_TYPE_ED448, + (void**)&ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; + } + break; + } + #endif /* HAVE_ED448 */ + + default: + ret = ALGO_ID_E; + } /* switch (sigAlgo) */ + #endif /* NO_DH && !HAVE_ECC && !HAVE_ED25519 && !HAVE_ED448 */ + break; + } + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + switch(ssl->specs.kea) + { + case psk_kea: + case dhe_psk_kea: + case ecdhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + + case diffie_hellman_kea: + case ecc_diffie_hellman_kea: + { + #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) \ + && !defined(HAVE_ED448) + ERROR_OUT(NOT_COMPILED_IN, exit_dske); + #else + if (ssl->options.usingAnon_cipher) { + break; + } + + /* increment index after verify is done */ + args->idx += args->verifySigSz; + + switch(args->sigAlgo) + { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #ifdef HAVE_SELFTEST + ret = wc_RsaPSS_CheckPadding( + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + args->output, args->sigSz, + HashAlgoToType(args->hashAlgo)); + #else + ret = wc_RsaPSS_CheckPadding_ex( + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + args->output, args->sigSz, + HashAlgoToType(args->hashAlgo), + -1, args->bits); + #endif + if (ret != 0) + return ret; + break; + #endif + case rsa_sa_algo: + { + if (IsAtLeastTLSv1_2(ssl)) { + #ifdef WOLFSSL_SMALL_STACK + byte* encodedSig; + #else + byte encodedSig[MAX_ENCODED_SIG_SZ]; + #endif + word32 encSigSz; + + #ifdef WOLFSSL_SMALL_STACK + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + ERROR_OUT(MEMORY_E, exit_dske); + } + #endif + + encSigSz = wc_EncodeSignature(encodedSig, + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + TypeHash(args->hashAlgo)); + if (encSigSz != args->sigSz || !args->output || + XMEMCMP(args->output, encodedSig, + min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) { + ret = VERIFY_SIGN_ERROR; + } + #ifdef WOLFSSL_SMALL_STACK + XFREE(encodedSig, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + #endif + if (ret != 0) { + goto exit_dske; + } + } + else if (args->sigSz != FINISHED_SZ || + !args->output || + XMEMCMP(args->output, + ssl->buffers.digest.buffer, + FINISHED_SZ) != 0) { + ERROR_OUT(VERIFY_SIGN_ERROR, exit_dske); + } + break; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + /* Nothing to do in this algo */ + break; + #endif /* HAVE_ECC */ + #if defined(HAVE_ED25519) + case ed25519_sa_algo: + /* Nothing to do in this algo */ + break; + #endif /* HAVE_ED25519 */ + #if defined(HAVE_ED448) + case ed448_sa_algo: + /* Nothing to do in this algo */ + break; + #endif /* HAVE_ED448 */ + default: + ret = ALGO_ID_E; + } /* switch (sigAlgo) */ + #endif /* NO_DH && !HAVE_ECC && !HAVE_ED25519 && !HAVE_ED448 */ + break; + } + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + if (IsEncryptionOn(ssl, 0)) { + args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + args->idx += MacSize(ssl); + #endif + } + + /* QSH extensions */ + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + word16 name; + int qshSz; + + /* extension name */ + ato16(input + args->idx, &name); + args->idx += OPAQUE16_LEN; + + if (name == TLSX_QUANTUM_SAFE_HYBRID) { + /* if qshSz is larger than 0 it is the length of + buffer used */ + if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + args->idx, + size, 0)) < 0) { + ERROR_OUT(qshSz, exit_dske); + } + args->idx += qshSz; + } + else { + /* unknown extension sent server ignored handshake */ + ERROR_OUT(BUFFER_ERROR, exit_dske); + } + } + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + /* return index */ + *inOutIdx = args->idx; + + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_dske: + + WOLFSSL_LEAVE("DoServerKeyExchange", ret); + WOLFSSL_END(WC_FUNC_SERVER_KEY_EXCHANGE_DO); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + /* Mark message as not received so it can process again */ + ssl->msgsReceived.got_server_key_exchange = 0; + + return ret; + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Final cleanup */ + FreeDskeArgs(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} + + +#ifdef HAVE_QSH + +#ifdef HAVE_NTRU +/* Encrypt a byte array using ntru + key a struct containing the public key to use + bufIn array to be encrypted + inSz size of bufIn array + bufOut cipher text out + outSz will be set to the new size of cipher text + */ +static int NtruSecretEncrypt(QSHKey* key, byte* bufIn, word32 inSz, + byte* bufOut, word16* outSz) +{ + int ret; + DRBG_HANDLE drbg; + + /* sanity checks on input arguments */ + if (key == NULL || bufIn == NULL || bufOut == NULL || outSz == NULL) + return BAD_FUNC_ARG; + + if (key->pub.buffer == NULL) + return BAD_FUNC_ARG; + + switch (key->name) { + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + break; + default: + WOLFSSL_MSG("Unknown QSH encryption key!"); + return -1; + } + + /* set up ntru drbg */ + ret = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) + return NTRU_DRBG_ERROR; + + /* encrypt the byte array */ + ret = ntru_crypto_ntru_encrypt(drbg, key->pub.length, key->pub.buffer, + inSz, bufIn, outSz, bufOut); + ntru_crypto_drbg_uninstantiate(drbg); + if (ret != NTRU_OK) + return NTRU_ENCRYPT_ERROR; + + return ret; +} + +/* Decrypt a byte array using ntru + key a struct containing the private key to use + bufIn array to be decrypted + inSz size of bufIn array + bufOut plain text out + outSz will be set to the new size of plain text + */ + +static int NtruSecretDecrypt(QSHKey* key, byte* bufIn, word32 inSz, + byte* bufOut, word16* outSz) +{ + int ret; + DRBG_HANDLE drbg; + + /* sanity checks on input arguments */ + if (key == NULL || bufIn == NULL || bufOut == NULL || outSz == NULL) + return BAD_FUNC_ARG; + + if (key->pri.buffer == NULL) + return BAD_FUNC_ARG; + + switch (key->name) { + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + break; + default: + WOLFSSL_MSG("Unknown QSH decryption key!"); + return -1; + } + + + /* set up drbg */ + ret = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) + return NTRU_DRBG_ERROR; + + /* decrypt cipher text */ + ret = ntru_crypto_ntru_decrypt(key->pri.length, key->pri.buffer, + inSz, bufIn, outSz, bufOut); + ntru_crypto_drbg_uninstantiate(drbg); + if (ret != NTRU_OK) + return NTRU_ENCRYPT_ERROR; + + return ret; +} +#endif /* HAVE_NTRU */ + +int QSH_Init(WOLFSSL* ssl) +{ + /* check so not initializing twice when running DTLS */ + if (ssl->QSH_secret != NULL) + return 0; + + /* malloc memory for holding generated secret information */ + if ((ssl->QSH_secret = (QSHSecret*)XMALLOC(sizeof(QSHSecret), ssl->heap, + DYNAMIC_TYPE_QSH)) == NULL) + return MEMORY_E; + + ssl->QSH_secret->CliSi = (buffer*)XMALLOC(sizeof(buffer), ssl->heap, + DYNAMIC_TYPE_SECRET); + if (ssl->QSH_secret->CliSi == NULL) + return MEMORY_E; + + ssl->QSH_secret->SerSi = (buffer*)XMALLOC(sizeof(buffer), ssl->heap, + DYNAMIC_TYPE_SECRET); + if (ssl->QSH_secret->SerSi == NULL) + return MEMORY_E; + + /* initialize variables */ + ssl->QSH_secret->list = NULL; + ssl->QSH_secret->CliSi->length = 0; + ssl->QSH_secret->CliSi->buffer = NULL; + ssl->QSH_secret->SerSi->length = 0; + ssl->QSH_secret->SerSi->buffer = NULL; + + return 0; +} + + +static int QSH_Encrypt(QSHKey* key, byte* in, word32 szIn, + byte* out, word32* szOut) +{ + int ret = 0; + word16 size = *szOut; + + (void)in; + (void)szIn; + (void)out; + (void)szOut; + + WOLFSSL_MSG("Encrypting QSH key material"); + + switch (key->name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + ret = NtruSecretEncrypt(key, in, szIn, out, &size); + break; + #endif + default: + WOLFSSL_MSG("Unknown QSH encryption key!"); + return -1; + } + + *szOut = size; + + return ret; +} + + +/* Decrypt using Quantum Safe Handshake algorithms */ +int QSH_Decrypt(QSHKey* key, byte* in, word32 szIn, byte* out, word16* szOut) +{ + int ret = 0; + word16 size = *szOut; + + (void)in; + (void)szIn; + (void)out; + (void)szOut; + + WOLFSSL_MSG("Decrypting QSH key material"); + + switch (key->name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + ret = NtruSecretDecrypt(key, in, szIn, out, &size); + break; + #endif + default: + WOLFSSL_MSG("Unknown QSH decryption key!"); + return -1; + } + + *szOut = size; + + return ret; +} + + +/* Get the max cipher text for corresponding encryption scheme + (encrypting 48 or max plain text whichever is smaller) + */ +static word32 QSH_MaxSecret(QSHKey* key) +{ + int ret = 0; +#ifdef HAVE_NTRU + byte isNtru = 0; + word16 inSz = 48; + word16 outSz; + DRBG_HANDLE drbg = 0; + byte bufIn[48]; +#endif + + if (key == NULL || key->pub.length == 0) + return 0; + + switch(key->name) { +#ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + isNtru = 1; + break; + case WOLFSSL_NTRU_EESS593: + isNtru = 1; + break; + case WOLFSSL_NTRU_EESS743: + isNtru = 1; + break; +#endif + default: + WOLFSSL_MSG("Unknown QSH encryption scheme size!"); + return 0; + } + +#ifdef HAVE_NTRU + if (isNtru) { + ret = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) + return NTRU_DRBG_ERROR; + ret = ntru_crypto_ntru_encrypt(drbg, key->pub.length, + key->pub.buffer, inSz, bufIn, &outSz, NULL); + if (ret != NTRU_OK) { + return NTRU_ENCRYPT_ERROR; + } + ntru_crypto_drbg_uninstantiate(drbg); + ret = outSz; + } +#endif + + return ret; +} + +/* Generate the secret byte material for pms + returns length on success and -1 on fail + */ +static int QSH_GenerateSerCliSecret(WOLFSSL* ssl, byte isServer) +{ + int sz = 0; + int plainSz = 48; /* lesser of 48 and max plain text able to encrypt */ + int offset = 0; + word32 tmpSz = 0; + buffer* buf; + QSHKey* current; + QSHScheme* schmPre = NULL; + QSHScheme* schm = NULL; + + if (ssl == NULL) + return -1; + + WOLFSSL_MSG("Generating QSH secret key material"); + + current = ssl->peerQSHKey; + /* get size of buffer needed */ + while (current) { + if (current->pub.length != 0) { + sz += plainSz; + } + current = (QSHKey*)current->next; + } + + /* allocate memory for buffer */ + if (isServer) { + buf = ssl->QSH_secret->SerSi; + } + else { + buf = ssl->QSH_secret->CliSi; + } + buf->length = sz; + buf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_SECRET); + if (buf->buffer == NULL) { + WOLFSSL_ERROR(MEMORY_E); + } + + /* create secret information */ + sz = 0; + current = ssl->peerQSHKey; + while (current) { + schm = (QSHScheme*)XMALLOC(sizeof(QSHScheme), ssl->heap, + DYNAMIC_TYPE_QSH); + if (schm == NULL) + return MEMORY_E; + + /* initialize variables */ + schm->name = 0; + schm->PK = NULL; + schm->PKLen = 0; + schm->next = NULL; + if (ssl->QSH_secret->list == NULL) { + ssl->QSH_secret->list = schm; + } + else { + if (schmPre) + schmPre->next = schm; + } + + tmpSz = QSH_MaxSecret(current); + + if ((schm->PK = (byte*)XMALLOC(tmpSz, ssl->heap, + DYNAMIC_TYPE_SECRET)) == NULL) + return -1; + + /* store info for writing extension */ + schm->name = current->name; + + /* no key to use for encryption */ + if (tmpSz == 0) { + current = (QSHKey*)current->next; + continue; + } + + if (wc_RNG_GenerateBlock(ssl->rng, buf->buffer + offset, plainSz) + != 0) { + return -1; + } + if (QSH_Encrypt(current, buf->buffer + offset, plainSz, schm->PK, + &tmpSz) != 0) { + return -1; + } + schm->PKLen = tmpSz; + + sz += tmpSz; + offset += plainSz; + schmPre = schm; + current = (QSHKey*)current->next; + } + + return sz; +} + + +static word32 QSH_KeyGetSize(WOLFSSL* ssl) +{ + word32 sz = 0; + QSHKey* current; + + if (ssl == NULL) + return -1; + + current = ssl->peerQSHKey; + sz += OPAQUE16_LEN; /* type of extension ie 0x00 0x18 */ + sz += OPAQUE24_LEN; + /* get size of buffer needed */ + while (current) { + sz += OPAQUE16_LEN; /* scheme id */ + sz += OPAQUE16_LEN; /* encrypted key len*/ + sz += QSH_MaxSecret(current); + current = (QSHKey*)current->next; + } + + return sz; +} + + +/* handle QSH key Exchange + return 0 on success + */ +static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) +{ + int ret = 0; + + WOLFSSL_ENTER("QSH KeyExchange"); + + ret = QSH_GenerateSerCliSecret(ssl, isServer); + if (ret < 0) + return MEMORY_E; + + return 0; +} + +#endif /* HAVE_QSH */ + + +typedef struct SckeArgs { + byte* output; /* not allocated */ + byte* encSecret; + byte* input; + word32 encSz; + word32 length; + int sendSz; + int inputSz; +} SckeArgs; + +static void FreeSckeArgs(WOLFSSL* ssl, void* pArgs) +{ + SckeArgs* args = (SckeArgs*)pArgs; + + (void)ssl; + + if (args->encSecret) { + XFREE(args->encSecret, ssl->heap, DYNAMIC_TYPE_SECRET); + args->encSecret = NULL; + } + if (args->input) { + XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + args->input = NULL; + } +} + +/* handle generation client_key_exchange (16) */ +int SendClientKeyExchange(WOLFSSL* ssl) +{ + int ret = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + SckeArgs* args = (SckeArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + SckeArgs args[1]; +#endif + + WOLFSSL_START(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND); + WOLFSSL_ENTER("SendClientKeyExchange"); + +#ifdef OPENSSL_EXTRA + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + ssl->cbmode = SSL_CB_MODE_WRITE; + if (ssl->CBIS != NULL) + ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS); +#endif + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_scke; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(SckeArgs)); + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeSckeArgs; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + if (ssl->peerRsaKey == NULL || + ssl->peerRsaKeyPresent == 0) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + break; + #endif + #ifndef NO_DH + case diffie_hellman_kea: + if (ssl->buffers.serverDH_P.buffer == NULL || + ssl->buffers.serverDH_G.buffer == NULL || + ssl->buffers.serverDH_Pub.buffer == NULL) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + break; + #endif /* NO_DH */ + #ifndef NO_PSK + case psk_kea: + /* sanity check that PSK client callback has been set */ + if (ssl->options.client_psk_cb == NULL) { + WOLFSSL_MSG("No client PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_scke); + } + break; + #endif /* NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + if (ssl->buffers.serverDH_P.buffer == NULL || + ssl->buffers.serverDH_G.buffer == NULL || + ssl->buffers.serverDH_Pub.buffer == NULL) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + /* sanity check that PSK client callback has been set */ + if (ssl->options.client_psk_cb == NULL) { + WOLFSSL_MSG("No client PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_scke); + } + break; + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + /* sanity check that PSK client callback has been set */ + if (ssl->options.client_psk_cb == NULL) { + WOLFSSL_MSG("No client PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_scke); + } + + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + /* Check client ECC public key */ + if (!ssl->peerX25519Key || !ssl->peerX25519Key->dp) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + /* create private key */ + ssl->hsType = DYNAMIC_TYPE_CURVE25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = X25519MakeKey(ssl, (curve25519_key*)ssl->hsKey, + ssl->peerX25519Key); + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->peerX448KeyPresent) { + /* Check client ECC public key */ + if (!ssl->peerX448Key) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X448SharedSecretCb != NULL) { + break; + } + #endif + + /* create private key */ + ssl->hsType = DYNAMIC_TYPE_CURVE448; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = X448MakeKey(ssl, (curve448_key*)ssl->hsKey, + ssl->peerX448Key); + break; + } + #endif + /* Check client ECC public key */ + if (!ssl->peerEccKey || !ssl->peerEccKeyPresent || + !ssl->peerEccKey->dp) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->EccSharedSecretCb != NULL) { + break; + } + #endif + + /* create ephemeral private key */ + ssl->hsType = DYNAMIC_TYPE_ECC; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = EccMakeKey(ssl, (ecc_key*)ssl->hsKey, ssl->peerEccKey); + + break; + #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) && !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + if (ssl->peerNtruKeyPresent == 0) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + break; + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + #ifdef HAVE_ECC + ecc_key* peerKey; + #endif + + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (ssl->ctx->X25519SharedSecretCb != NULL) + break; + } + else + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + if (ssl->ctx->X448SharedSecretCb != NULL) + break; + } + else + #endif + if (ssl->ctx->EccSharedSecretCb != NULL) { + break; + } + #endif /* HAVE_PK_CALLBACKS */ + + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + if (!ssl->peerX25519Key || !ssl->peerX25519Key->dp) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + /* create private key */ + ssl->hsType = DYNAMIC_TYPE_CURVE25519; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = X25519MakeKey(ssl, (curve25519_key*)ssl->hsKey, + ssl->peerX25519Key); + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->peerX448KeyPresent) { + if (!ssl->peerX448Key) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + /* create private key */ + ssl->hsType = DYNAMIC_TYPE_CURVE448; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = X448MakeKey(ssl, (curve448_key*)ssl->hsKey, + ssl->peerX448Key); + break; + } + #endif + #ifdef HAVE_ECC + if (ssl->specs.static_ecdh) { + /* Note: EccDsa is really fixed Ecc key here */ + if (!ssl->peerEccDsaKey || !ssl->peerEccDsaKeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + peerKey = ssl->peerEccDsaKey; + } + else { + if (!ssl->peerEccKey || !ssl->peerEccKeyPresent) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + peerKey = ssl->peerEccKey; + } + if (peerKey == NULL) { + ERROR_OUT(NO_PEER_KEY, exit_scke); + } + + /* create ephemeral private key */ + ssl->hsType = DYNAMIC_TYPE_ECC; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_scke; + } + + ret = EccMakeKey(ssl, (ecc_key*)ssl->hsKey, peerKey); + #endif + + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_scke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + args->encSz = MAX_ENCRYPT_SZ; + args->encSecret = (byte*)XMALLOC(args->encSz, ssl->heap, + DYNAMIC_TYPE_SECRET); + if (args->encSecret == NULL) { + ERROR_OUT(MEMORY_E, exit_scke); + } + if (ssl->arrays->preMasterSecret == NULL) { + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, + ssl->heap, DYNAMIC_TYPE_SECRET); + if (ssl->arrays->preMasterSecret == NULL) { + ERROR_OUT(MEMORY_E, exit_scke); + } + XMEMSET(ssl->arrays->preMasterSecret, 0, ENCRYPT_LEN); + } + + switch(ssl->specs.kea) + { + #ifndef NO_RSA + case rsa_kea: + { + /* build PreMasterSecret with RNG data */ + #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) { + ret = tsip_generatePremasterSecret( + &ssl->arrays->preMasterSecret[VERSION_SZ], + ENCRYPT_LEN - VERSION_SZ); + } else { + #endif + ret = wc_RNG_GenerateBlock(ssl->rng, + &ssl->arrays->preMasterSecret[VERSION_SZ], + SECRET_LEN - VERSION_SZ); + #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + } + #endif + if (ret != 0) { + goto exit_scke; + } + + ssl->arrays->preMasterSecret[0] = ssl->chVersion.major; + ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor; + + ssl->arrays->preMasterSz = SECRET_LEN; + + break; + } + #endif /* !NO_RSA */ + #ifndef NO_DH + case diffie_hellman_kea: + { + ssl->buffers.sig.length = ENCRYPT_LEN; + ssl->buffers.sig.buffer = (byte*)XMALLOC(ENCRYPT_LEN, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_scke); + } + + ret = AllocKey(ssl, DYNAMIC_TYPE_DH, + (void**)&ssl->buffers.serverDH_Key); + if (ret != 0) { + goto exit_scke; + } + + #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + if (ssl->options.dhDoKeyTest && + !ssl->options.dhKeyTested) + { + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); + if (ret != 0) { + goto exit_scke; + } + ssl->options.dhKeyTested = 1; + } + else + #endif + { + ret = wc_DhSetKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret != 0) { + goto exit_scke; + } + } + + /* for DH, encSecret is Yc, agree is pre-master */ + ret = DhGenKeyPair(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length, + args->encSecret, &args->encSz); + + /* set the max agree result size */ + ssl->arrays->preMasterSz = ENCRYPT_LEN; + break; + } + #endif /* !NO_DH */ + #ifndef NO_PSK + case psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays->server_hint, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_scke); + } + ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; /* null term */ + args->encSz = (word32)XSTRLEN(ssl->arrays->client_identity); + if (args->encSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_scke); + } + XMEMCPY(args->encSecret, ssl->arrays->client_identity, + args->encSz); + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16)ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + XMEMSET(pms, 0, ssl->arrays->psk_keySz); + pms += ssl->arrays->psk_keySz; + c16toa((word16)ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz = (ssl->arrays->psk_keySz * 2) + + (2 * OPAQUE16_LEN); + ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->psk_keySz = 0; /* No further need */ + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + word32 esSz = 0; + args->output = args->encSecret; + + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays->server_hint, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_scke); + } + ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; /* null term */ + esSz = (word32)XSTRLEN(ssl->arrays->client_identity); + + if (esSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_scke); + } + + ssl->buffers.sig.length = ENCRYPT_LEN; + ssl->buffers.sig.buffer = (byte*)XMALLOC(ENCRYPT_LEN, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_scke); + } + + c16toa((word16)esSz, args->output); + args->output += OPAQUE16_LEN; + XMEMCPY(args->output, ssl->arrays->client_identity, esSz); + args->output += esSz; + args->encSz = esSz + OPAQUE16_LEN; + + args->length = 0; + + ret = AllocKey(ssl, DYNAMIC_TYPE_DH, + (void**)&ssl->buffers.serverDH_Key); + if (ret != 0) { + goto exit_scke; + } + + #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + if (ssl->options.dhDoKeyTest && + !ssl->options.dhKeyTested) + { + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); + if (ret != 0) { + goto exit_scke; + } + ssl->options.dhKeyTested = 1; + } + else + #endif + { + ret = wc_DhSetKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret != 0) { + goto exit_scke; + } + } + + /* for DH, encSecret is Yc, agree is pre-master */ + ret = DhGenKeyPair(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length, + args->output + OPAQUE16_LEN, &args->length); + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + word32 esSz = 0; + args->output = args->encSecret; + + /* Send PSK client identity */ + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays->server_hint, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_scke); + } + ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; /* null term */ + esSz = (word32)XSTRLEN(ssl->arrays->client_identity); + if (esSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_scke); + } + + /* place size and identity in output buffer sz:identity */ + c16toa((word16)esSz, args->output); + args->output += OPAQUE16_LEN; + XMEMCPY(args->output, ssl->arrays->client_identity, esSz); + args->output += esSz; + args->encSz = esSz + OPAQUE16_LEN; + + /* length is used for public key size */ + args->length = MAX_ENCRYPT_SZ; + + /* Create shared ECC key leaving room at the beginning + of buffer for size of shared key. */ + ssl->arrays->preMasterSz = ENCRYPT_LEN - OPAQUE16_LEN; + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + ret = wc_curve25519_export_public_ex( + (curve25519_key*)ssl->hsKey, + args->output + OPAQUE8_LEN, &args->length, + EC25519_LITTLE_ENDIAN); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X448SharedSecretCb != NULL) { + break; + } + #endif + + ret = wc_curve448_export_public_ex( + (curve448_key*)ssl->hsKey, + args->output + OPAQUE8_LEN, &args->length, + EC448_LITTLE_ENDIAN); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->EccSharedSecretCb != NULL) { + break; + } + #endif + + /* Place ECC key in output buffer, leaving room for size */ + ret = wc_ecc_export_x963((ecc_key*)ssl->hsKey, + args->output + OPAQUE8_LEN, &args->length); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) && !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + ret = wc_RNG_GenerateBlock(ssl->rng, + ssl->arrays->preMasterSecret, SECRET_LEN); + if (ret != 0) { + goto exit_scke; + } + + ssl->arrays->preMasterSz = SECRET_LEN; + args->encSz = MAX_ENCRYPT_SZ; + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + ssl->arrays->preMasterSz = ENCRYPT_LEN; + + #ifdef HAVE_CURVE25519 + if (ssl->hsType == DYNAMIC_TYPE_CURVE25519) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + ret = wc_curve25519_export_public_ex( + (curve25519_key*)ssl->hsKey, + args->encSecret + OPAQUE8_LEN, &args->encSz, + EC25519_LITTLE_ENDIAN); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->hsType == DYNAMIC_TYPE_CURVE448) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X448SharedSecretCb != NULL) { + break; + } + #endif + + ret = wc_curve448_export_public_ex( + (curve448_key*)ssl->hsKey, + args->encSecret + OPAQUE8_LEN, &args->encSz, + EC448_LITTLE_ENDIAN); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + + break; + } + #endif + #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->EccSharedSecretCb != NULL) { + break; + } + #endif + + /* Place ECC key in buffer, leaving room for size */ + ret = wc_ecc_export_x963((ecc_key*)ssl->hsKey, + args->encSecret + OPAQUE8_LEN, &args->encSz); + if (ret != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_scke); + } + #endif /* HAVE_ECC */ + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_scke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + switch(ssl->specs.kea) + { + #ifndef NO_RSA + case rsa_kea: + { + #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl) && + wc_RsaEncryptSize(ssl->peerRsaKey) == 256) { + ret = tsip_generateEncryptPreMasterSecret(ssl, + args->encSecret, + &args->encSz); + + } else + #endif + ret = RsaEnc(ssl, + ssl->arrays->preMasterSecret, SECRET_LEN, + args->encSecret, &args->encSz, + ssl->peerRsaKey, + #if defined(HAVE_PK_CALLBACKS) + &ssl->buffers.peerRsaKey + #else + NULL + #endif + ); + + break; + } + #endif /* !NO_RSA */ + #ifndef NO_DH + case diffie_hellman_kea: + { + ret = DhAgree(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, + ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz); + break; + } + #endif /* !NO_DH */ + #ifndef NO_PSK + case psk_kea: + { + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + ret = DhAgree(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, + ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->arrays->preMasterSz); + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)ssl->hsKey, ssl->peerX25519Key, + args->output + OPAQUE8_LEN, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END + ); + if (!ssl->specs.static_ecdh + #ifdef WOLFSSL_ASYNC_CRYPT + && ret != WC_PENDING_E + #endif + ) { + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + } + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->peerX448KeyPresent) { + ret = X448SharedSecret(ssl, + (curve448_key*)ssl->hsKey, ssl->peerX448Key, + args->output + OPAQUE8_LEN, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END + ); + if (!ssl->specs.static_ecdh + #ifdef WOLFSSL_ASYNC_CRYPT + && ret != WC_PENDING_E + #endif + ) { + FreeKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + } + break; + } + #endif + ret = EccSharedSecret(ssl, + (ecc_key*)ssl->hsKey, ssl->peerEccKey, + args->output + OPAQUE8_LEN, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END + ); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + } + break; + } + #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) && !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + word32 rc; + word16 tmpEncSz = (word16)args->encSz; + DRBG_HANDLE drbg; + + rc = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg); + if (rc != DRBG_OK) { + ERROR_OUT(NTRU_DRBG_ERROR, exit_scke); + } + rc = ntru_crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen, + ssl->peerNtruKey, + ssl->arrays->preMasterSz, + ssl->arrays->preMasterSecret, + &tmpEncSz, + args->encSecret); + args->encSz = tmpEncSz; + ntru_crypto_drbg_uninstantiate(drbg); + if (rc != NTRU_OK) { + ERROR_OUT(NTRU_ENCRYPT_ERROR, exit_scke); + } + ret = 0; + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + #ifdef HAVE_ECC + ecc_key* peerKey; + #endif + + #ifdef HAVE_CURVE25519 + if (ssl->peerX25519KeyPresent) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)ssl->hsKey, ssl->peerX25519Key, + args->encSecret + OPAQUE8_LEN, &args->encSz, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END + ); + if (!ssl->specs.static_ecdh + #ifdef WOLFSSL_ASYNC_CRYPT + && ret != WC_PENDING_E + #endif + ) { + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + } + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->peerX448KeyPresent) { + ret = X448SharedSecret(ssl, + (curve448_key*)ssl->hsKey, ssl->peerX448Key, + args->encSecret + OPAQUE8_LEN, &args->encSz, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END + ); + if (!ssl->specs.static_ecdh + #ifdef WOLFSSL_ASYNC_CRYPT + && ret != WC_PENDING_E + #endif + ) { + FreeKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + } + break; + } + #endif + #ifdef HAVE_ECC + peerKey = (ssl->specs.static_ecdh) ? + ssl->peerEccDsaKey : ssl->peerEccKey; + + ret = EccSharedSecret(ssl, + (ecc_key*)ssl->hsKey, peerKey, + args->encSecret + OPAQUE8_LEN, &args->encSz, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_CLIENT_END + ); + if (!ssl->specs.static_ecdh + #ifdef WOLFSSL_ASYNC_CRYPT + && ret != WC_PENDING_E + #endif + && !ssl->options.keepResources) { + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + } + #endif + + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_scke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + switch(ssl->specs.kea) + { + #ifndef NO_RSA + case rsa_kea: + { + break; + } + #endif /* !NO_RSA */ + #ifndef NO_DH + case diffie_hellman_kea: + { + break; + } + #endif /* !NO_DH */ + #ifndef NO_PSK + case psk_kea: + { + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + + /* validate args */ + if (args->output == NULL || args->length == 0) { + ERROR_OUT(BAD_FUNC_ARG, exit_scke); + } + + c16toa((word16)args->length, args->output); + args->encSz += args->length + OPAQUE16_LEN; + c16toa((word16)ssl->arrays->preMasterSz, pms); + ssl->arrays->preMasterSz += OPAQUE16_LEN; + pms += ssl->arrays->preMasterSz; + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16)ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz += + ssl->arrays->psk_keySz + OPAQUE16_LEN; + ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->psk_keySz = 0; /* No further need */ + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + + /* validate args */ + if (args->output == NULL || args->length > ENCRYPT_LEN) { + ERROR_OUT(BAD_FUNC_ARG, exit_scke); + } + + /* place size of public key in output buffer */ + *args->output = (byte)args->length; + args->encSz += args->length + OPAQUE8_LEN; + + /* Create pre master secret is the concatenation of + eccSize + eccSharedKey + pskSize + pskKey */ + c16toa((word16)ssl->arrays->preMasterSz, pms); + ssl->arrays->preMasterSz += OPAQUE16_LEN; + pms += ssl->arrays->preMasterSz; + + c16toa((word16)ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz += + ssl->arrays->psk_keySz + OPAQUE16_LEN; + + ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->psk_keySz = 0; /* No further need */ + break; + } + #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) && !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + /* place size of public key in buffer */ + *args->encSecret = (byte)args->encSz; + args->encSz += OPAQUE8_LEN; + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + + default: + ret = BAD_KEA_TYPE_E; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_scke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + word32 tlsSz = 0; + word32 idx = 0; + + #ifdef HAVE_QSH + word32 qshSz = 0; + if (ssl->peerQSHKeyPresent) { + qshSz = QSH_KeyGetSize(ssl); + } + #endif + + if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea) { + tlsSz = 2; + } + + if (ssl->specs.kea == ecc_diffie_hellman_kea || + ssl->specs.kea == dhe_psk_kea || + ssl->specs.kea == ecdhe_psk_kea) { /* always off */ + tlsSz = 0; + } + + idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + args->sendSz = args->encSz + tlsSz + idx; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + args->sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + } + #endif + + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + #ifdef HAVE_QSH + args->encSz += qshSz; + args->sendSz += qshSz; + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_scke; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + byte idxSave = idx; + idx = args->sendSz - qshSz; + + if (QSH_KeyExchangeWrite(ssl, 0) != 0) { + ERROR_OUT(MEMORY_E, exit_scke); + } + + /* extension type */ + c16toa(TLSX_QUANTUM_SAFE_HYBRID, args->output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, + args->output + idx) > qshSz - OPAQUE16_LEN) { + ERROR_OUT(MEMORY_E, exit_scke); + } + + idx = idxSave; + } + #endif + + AddHeaders(args->output, args->encSz + tlsSz, client_key_exchange, ssl); + + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + args->encSz -= qshSz; + } + #endif + if (tlsSz) { + c16toa((word16)args->encSz, &args->output[idx]); + idx += OPAQUE16_LEN; + } + XMEMCPY(args->output + idx, args->encSecret, args->encSz); + idx += args->encSz; + + if (IsEncryptionOn(ssl, 1)) { + args->inputSz = idx - RECORD_HEADER_SZ; /* buildmsg adds rechdr */ + args->input = (byte*)XMALLOC(args->inputSz, ssl->heap, + DYNAMIC_TYPE_IN_BUFFER); + if (args->input == NULL) { + ERROR_OUT(MEMORY_E, exit_scke); + } + + XMEMCPY(args->input, args->output + RECORD_HEADER_SZ, + args->inputSz); + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + if (IsEncryptionOn(ssl, 1)) { + ret = BuildMessage(ssl, args->output, args->sendSz, + args->input, args->inputSz, handshake, 1, 0, 0); + XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + args->input = NULL; /* make sure its not double free'd on cleanup */ + + if (ret >= 0) { + args->sendSz = ret; + ret = 0; + } + } + else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + ret = HashOutput(ssl, args->output, args->sendSz, 0); + } + + if (ret != 0) { + goto exit_scke; + } + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz)) != 0) { + goto exit_scke; + } + } + #endif + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "ClientKeyExchange"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "ClientKeyExchange", handshake, + args->output, args->sendSz, WRITE_PROTO, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += args->sendSz; + + if (!ssl->options.groupMessages) { + ret = SendBuffered(ssl); + } + if (ret == 0 || ret == WANT_WRITE) { + int tmpRet = MakeMasterSecret(ssl); + if (tmpRet != 0) { + ret = tmpRet; /* save WANT_WRITE unless more serious */ + } + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + } + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_scke: + + WOLFSSL_LEAVE("SendClientKeyExchange", ret); + WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) + return ret; +#endif + + /* No further need for PMS */ + if (ssl->arrays->preMasterSecret != NULL) { + ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); + } + ssl->arrays->preMasterSz = 0; + + /* Final cleanup */ + FreeSckeArgs(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifndef NO_CERTS + +#ifdef HAVE_PK_CALLBACKS + int GetPrivateKeySigSize(WOLFSSL* ssl) + { + int sigSz = 0; + + if (ssl == NULL) + return 0; + + switch (ssl->buffers.keyType) { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + sigSz = ssl->buffers.keySz; + ssl->hsType = DYNAMIC_TYPE_RSA; + break; + #endif + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + sigSz = wc_ecc_sig_size_calc(ssl->buffers.keySz); + ssl->hsType = DYNAMIC_TYPE_ECC; + break; + #endif + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + sigSz = ED25519_SIG_SIZE; /* fixed known value */ + ssl->hsType = DYNAMIC_TYPE_ED25519; + break; + #endif + #ifdef HAVE_ED448 + case ed448_sa_algo: + sigSz = ED448_SIG_SIZE; /* fixed known value */ + ssl->hsType = DYNAMIC_TYPE_ED448; + break; + #endif + default: + break; + } + return sigSz; + } +#endif /* HAVE_PK_CALLBACKS */ + +#ifndef WOLFSSL_NO_TLS12 + +#ifndef WOLFSSL_NO_CLIENT_AUTH +typedef struct ScvArgs { + byte* output; /* not allocated */ +#ifndef NO_RSA + byte* verifySig; +#endif + byte* verify; /* not allocated */ + byte* input; + word32 idx; + word32 extraSz; + word32 sigSz; + int sendSz; + int inputSz; + word16 length; + byte sigAlgo; +} ScvArgs; + +static void FreeScvArgs(WOLFSSL* ssl, void* pArgs) +{ + ScvArgs* args = (ScvArgs*)pArgs; + + (void)ssl; + +#ifndef NO_RSA + if (args->verifySig) { + XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->verifySig = NULL; + } +#endif + if (args->input) { + XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + args->input = NULL; + } +} + +/* handle generation of certificate_verify (15) */ +int SendCertificateVerify(WOLFSSL* ssl) +{ + int ret = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + ScvArgs* args = (ScvArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + ScvArgs args[1]; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND); + WOLFSSL_ENTER("SendCertificateVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_scv; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(ScvArgs)); + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeScvArgs; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + return 0; /* sent blank cert, can't verify */ + } + + args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA; + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_scv; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes); + if (ret != 0) { + goto exit_scv; + } + + if (ssl->buffers.key == NULL) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) + args->length = GetPrivateKeySigSize(ssl); + else + #endif + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + else { + /* Decode private key. */ + ret = DecodePrivateKey(ssl, &args->length); + if (ret != 0) { + goto exit_scv; + } + } + + if (args->length == 0) { + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + + /* idx is used to track verify pointer offset to output */ + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; + args->extraSz = 0; /* tls 1.2 hash/sig */ + + /* build encoded signature buffer */ + ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ; + ssl->buffers.sig.buffer = (byte*)XMALLOC(ssl->buffers.sig.length, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + args->verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + #ifndef NO_OLD_TLS + #ifndef NO_SHA + /* old tls default */ + SetDigest(ssl, sha_mac); + #endif + #else + #ifndef NO_SHA256 + /* new tls default */ + SetDigest(ssl, sha256_mac); + #endif + #endif /* !NO_OLD_TLS */ + + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + #ifdef WC_RSA_PSS + if (IsAtLeastTLSv1_2(ssl) && + (ssl->pssAlgo & (1 << ssl->suites->hashAlgo))) { + args->sigAlgo = rsa_pss_sa_algo; + } + else + #endif + args->sigAlgo = rsa_sa_algo; + } + else if (ssl->hsType == DYNAMIC_TYPE_ECC) + args->sigAlgo = ecc_dsa_sa_algo; + else if (ssl->hsType == DYNAMIC_TYPE_ED25519) + args->sigAlgo = ed25519_sa_algo; + else if (ssl->hsType == DYNAMIC_TYPE_ED448) + args->sigAlgo = ed448_sa_algo; + + if (IsAtLeastTLSv1_2(ssl)) { + EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, + args->verify); + args->extraSz = HASH_SIG_SIZE; + SetDigest(ssl, ssl->suites->hashAlgo); + } + #ifndef NO_OLD_TLS + else { + /* if old TLS load MD5 and SHA hash as value to sign */ + XMEMCPY(ssl->buffers.sig.buffer, + (byte*)ssl->hsHashes->certHashes.md5, FINISHED_SZ); + } + #endif + + #ifndef NO_RSA + if (args->sigAlgo == rsa_sa_algo) { + ssl->buffers.sig.length = FINISHED_SZ; + args->sigSz = ENCRYPT_LEN; + + if (IsAtLeastTLSv1_2(ssl)) { + ssl->buffers.sig.length = wc_EncodeSignature( + ssl->buffers.sig.buffer, ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + TypeHash(ssl->suites->hashAlgo)); + } + + /* prepend hdr */ + c16toa(args->length, args->verify + args->extraSz); + } + #ifdef WC_RSA_PSS + else if (args->sigAlgo == rsa_pss_sa_algo) { + XMEMCPY(ssl->buffers.sig.buffer, ssl->buffers.digest.buffer, + ssl->buffers.digest.length); + ssl->buffers.sig.length = ssl->buffers.digest.length; + args->sigSz = ENCRYPT_LEN; + + /* prepend hdr */ + c16toa(args->length, args->verify + args->extraSz); + } + #endif + #endif /* !NO_RSA */ + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) + if (args->sigAlgo == ed25519_sa_algo) { + ret = Ed25519CheckPubKey(ssl); + if (ret != 0) + goto exit_scv; + } + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ + #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH) + if (args->sigAlgo == ed448_sa_algo) { + ret = Ed448CheckPubKey(ssl); + if (ret != 0) + goto exit_scv; + } + #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) { + ecc_key* key = (ecc_key*)ssl->hsKey; + + ret = EccSign(ssl, + ssl->buffers.digest.buffer, ssl->buffers.digest.length, + ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + } + #endif /* HAVE_ECC */ + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ed25519_key* key = (ed25519_key*)ssl->hsKey; + + ret = Ed25519Sign(ssl, + ssl->hsHashes->messages, ssl->hsHashes->length, + ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + } + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ + #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH) + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ed448_key* key = (ed448_key*)ssl->hsKey; + + ret = Ed448Sign(ssl, + ssl->hsHashes->messages, ssl->hsHashes->length, + ssl->buffers.sig.buffer, (word32*)&ssl->buffers.sig.length, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + } + #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */ + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + RsaKey* key = (RsaKey*)ssl->hsKey; + + /* restore verify pointer */ + args->verify = &args->output[args->idx]; + + ret = RsaSign(ssl, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, + args->verify + args->extraSz + VERIFY_HEADER, &args->sigSz, + args->sigAlgo, ssl->suites->hashAlgo, key, + ssl->buffers.key + ); + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + /* restore verify pointer */ + args->verify = &args->output[args->idx]; + + switch (ssl->hsType) { + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + #endif + #ifdef HAVE_ED25519 + case DYNAMIC_TYPE_ED25519: + #endif + #ifdef HAVE_ED448 + case DYNAMIC_TYPE_ED448: + #endif + args->length = (word16)ssl->buffers.sig.length; + /* prepend hdr */ + c16toa(args->length, args->verify + args->extraSz); + XMEMCPY(args->verify + args->extraSz + VERIFY_HEADER, + ssl->buffers.sig.buffer, ssl->buffers.sig.length); + break; + #endif + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + { + RsaKey* key = (RsaKey*)ssl->hsKey; + + if (args->verifySig == NULL) { + args->verifySig = (byte*)XMALLOC(args->sigSz, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->verifySig == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + XMEMCPY(args->verifySig, args->verify + args->extraSz + + VERIFY_HEADER, args->sigSz); + } + + /* check for signature faults */ + ret = VerifyRsaSign(ssl, + args->verifySig, args->sigSz, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, + args->sigAlgo, ssl->suites->hashAlgo, key, + ssl->buffers.key + ); + break; + } + #endif /* !NO_RSA */ + default: + break; + } + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + if (args->output == NULL) { + ERROR_OUT(BUFFER_ERROR, exit_scv); + } + AddHeaders(args->output, (word32)args->length + args->extraSz + + VERIFY_HEADER, certificate_verify, ssl); + + args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + + (word32)args->length + args->extraSz + VERIFY_HEADER; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + if (IsEncryptionOn(ssl, 1)) { + args->inputSz = args->sendSz - RECORD_HEADER_SZ; + /* build msg adds rec hdr */ + args->input = (byte*)XMALLOC(args->inputSz, ssl->heap, + DYNAMIC_TYPE_IN_BUFFER); + if (args->input == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + XMEMCPY(args->input, args->output + RECORD_HEADER_SZ, + args->inputSz); + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + if (IsEncryptionOn(ssl, 1)) { + ret = BuildMessage(ssl, args->output, + MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, + args->input, args->inputSz, handshake, + 1, 0, 1); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + goto exit_scv; + #endif + + XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + args->input = NULL; /* make sure its not double free'd on cleanup */ + + if (ret >= 0) { + args->sendSz = ret; + ret = 0; + } + } + else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + ret = HashOutput(ssl, args->output, args->sendSz, 0); + } + + if (ret != 0) { + goto exit_scv; + } + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz); + } + #endif + + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateVerify"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "CertificateVerify", handshake, + args->output, args->sendSz, WRITE_PROTO, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += args->sendSz; + + if (!ssl->options.groupMessages) { + ret = SendBuffered(ssl); + } + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_scv: + + WOLFSSL_LEAVE("SendCertificateVerify", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + return ret; + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Digest is not allocated, so do this to prevent free */ + ssl->buffers.digest.buffer = NULL; + ssl->buffers.digest.length = 0; + + /* Final cleanup */ + FreeScvArgs(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} +#endif /* WOLFSSL_NO_CLIENT_AUTH */ + +#endif /* WOLFSSL_NO_TLS12 */ + +#endif /* NO_CERTS */ + + +#ifdef HAVE_SESSION_TICKET +int SetTicket(WOLFSSL* ssl, const byte* ticket, word32 length) +{ + /* Free old dynamic ticket if we already had one */ + if (ssl->session.isDynamic) { + XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + ssl->session.ticket = ssl->session.staticTicket; + ssl->session.isDynamic = 0; + } + + if (length > sizeof(ssl->session.staticTicket)) { + byte* sessionTicket = + (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + if (sessionTicket == NULL) + return MEMORY_E; + ssl->session.ticket = sessionTicket; + ssl->session.isDynamic = 1; + } + ssl->session.ticketLen = (word16)length; + + if (length > 0) { + XMEMCPY(ssl->session.ticket, ticket, length); + if (ssl->session_ticket_cb != NULL) { + ssl->session_ticket_cb(ssl, + ssl->session.ticket, ssl->session.ticketLen, + ssl->session_ticket_ctx); + } + /* Create a fake sessionID based on the ticket, this will + * supersede the existing session cache info. */ + ssl->options.haveSessionId = 1; +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + XMEMCPY(ssl->session.sessionID, + ssl->session.ticket + length - ID_LEN, ID_LEN); + } + else +#endif + XMEMCPY(ssl->arrays->sessionID, + ssl->session.ticket + length - ID_LEN, ID_LEN); + } + + return 0; +} + +#ifndef WOLFSSL_NO_TLS12 + +/* handle processing of session_ticket (4) */ +static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size) +{ + word32 begin = *inOutIdx; + word32 lifetime; + word16 length; + int ret; + + if (ssl->expect_session_ticket == 0) { + WOLFSSL_MSG("Unexpected session ticket"); + return SESSION_TICKET_EXPECT_E; + } + + if (OPAQUE32_LEN > size) + return BUFFER_ERROR; + + ato32(input + *inOutIdx, &lifetime); + *inOutIdx += OPAQUE32_LEN; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + if ((ret = SetTicket(ssl, input + *inOutIdx, length)) != 0) + return ret; + *inOutIdx += length; + if (length > 0) { + ssl->timeout = lifetime; +#ifndef NO_SESSION_CACHE + AddSession(ssl); +#endif + } + + if (IsEncryptionOn(ssl, 0)) { + *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + *inOutIdx += MacSize(ssl); + #endif + } + + ssl->expect_session_ticket = 0; + + return 0; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#endif /* HAVE_SESSION_TICKET */ + +#endif /* NO_WOLFSSL_CLIENT */ + +#ifdef HAVE_ECC + /* returns the WOLFSSL_* version of the curve from the OID sum */ + word16 GetCurveByOID(int oidSum) { + switch(oidSum) { + #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case ECC_SECP160R1_OID: + return WOLFSSL_ECC_SECP160R1; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + case ECC_SECP160R2_OID: + return WOLFSSL_ECC_SECP160R2; + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_KOBLITZ + case ECC_SECP160K1_OID: + return WOLFSSL_ECC_SECP160K1; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case ECC_SECP192R1_OID: + return WOLFSSL_ECC_SECP192R1; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case ECC_SECP192K1_OID: + return WOLFSSL_ECC_SECP192K1; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case ECC_SECP224R1_OID: + return WOLFSSL_ECC_SECP224R1; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case ECC_SECP224K1_OID: + return WOLFSSL_ECC_SECP224K1; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case ECC_SECP256R1_OID: + return WOLFSSL_ECC_SECP256R1; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case ECC_SECP256K1_OID: + return WOLFSSL_ECC_SECP256K1; + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + case ECC_BRAINPOOLP256R1_OID: + return WOLFSSL_ECC_BRAINPOOLP256R1; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case ECC_SECP384R1_OID: + return WOLFSSL_ECC_SECP384R1; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + case ECC_BRAINPOOLP384R1_OID: + return WOLFSSL_ECC_BRAINPOOLP384R1; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_BRAINPOOL + case ECC_BRAINPOOLP512R1_OID: + return WOLFSSL_ECC_BRAINPOOLP512R1; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case ECC_SECP521R1_OID: + return WOLFSSL_ECC_SECP521R1; + #endif /* !NO_ECC_SECP */ + #endif + default: + WOLFSSL_MSG("Curve OID not compiled in or implemented"); + return 0; + } + } +#endif /* HAVE_ECC */ + + +#ifndef NO_WOLFSSL_SERVER + +#ifndef WOLFSSL_NO_TLS12 + + /* handle generation of server_hello (2) */ + int SendServerHello(WOLFSSL* ssl) + { + int ret; + byte *output; + word16 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + byte sessIdSz = ID_LEN; + byte echoId = 0; /* ticket echo id flag */ + byte cacheOff = 0; /* session cache off flag */ + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); + WOLFSSL_ENTER("SendServerHello"); + + length = VERSION_SZ + RAN_LEN + + ID_LEN + ENUM_LEN + + SUITE_LEN + + ENUM_LEN; + +#ifdef HAVE_TLS_EXTENSIONS + ret = TLSX_GetResponseSize(ssl, server_hello, &length); + if (ret != 0) + return ret; + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket) { + /* echo session id sz can be 0,32 or bogus len in between */ + sessIdSz = ssl->arrays->sessionIDSz; + if (sessIdSz > ID_LEN) { + WOLFSSL_MSG("Bad bogus session id len"); + return BUFFER_ERROR; + } + if (!IsAtLeastTLSv1_3(ssl->version)) + length -= (ID_LEN - sessIdSz); /* adjust ID_LEN assumption */ + echoId = 1; + } + #endif /* HAVE_SESSION_TICKET */ +#else + if (ssl->options.haveEMS) { + length += HELLO_EXT_SZ_SZ + HELLO_EXT_SZ; + } +#endif + + /* is the session cache off at build or runtime */ +#ifdef NO_SESSION_CACHE + cacheOff = 1; +#else + if (ssl->options.sessionCacheOff == 1) { + cacheOff = 1; + } +#endif + + /* if no session cache don't send a session ID unless we're echoing + * an ID as part of session tickets */ + if (echoId == 0 && cacheOff == 1) { + length -= ID_LEN; /* adjust ID_LEN assumption */ + sessIdSz = 0; + } + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + /* Server Hello should use the same sequence number as the + * Client Hello. */ + ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi; + ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif /* WOLFSSL_DTLS */ + + if (IsEncryptionOn(ssl, 1)) + sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, server_hello, ssl); + + /* now write to output */ + /* first version */ + output[idx++] = (byte)ssl->version.major; + output[idx++] = (byte)ssl->version.minor; + + /* then random and session id */ + if (!ssl->options.resuming) { + /* generate random part and session id */ + ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, + RAN_LEN + sizeof(sessIdSz) + sessIdSz); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_TLS13 + if (TLSv1_3_Capable(ssl)) { + /* TLS v1.3 capable server downgraded. */ + XMEMCPY(output + idx + RAN_LEN - (TLS13_DOWNGRADE_SZ + 1), + tls13Downgrade, TLS13_DOWNGRADE_SZ); + output[idx + RAN_LEN - 1] = (byte)IsAtLeastTLSv1_2(ssl); + } + else +#endif + if (ssl->ctx->method->version.major == SSLv3_MAJOR && + ssl->ctx->method->version.minor == TLSv1_2_MINOR && + !IsAtLeastTLSv1_2(ssl)) { + /* TLS v1.2 capable server downgraded. */ + XMEMCPY(output + idx + RAN_LEN - (TLS13_DOWNGRADE_SZ + 1), + tls13Downgrade, TLS13_DOWNGRADE_SZ); + output[idx + RAN_LEN - 1] = 0; + } + + /* store info in SSL for later */ + XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); + idx += RAN_LEN; + output[idx++] = sessIdSz; + XMEMCPY(ssl->arrays->sessionID, output + idx, sessIdSz); + ssl->arrays->sessionIDSz = sessIdSz; + } + else { + /* If resuming, use info from SSL */ + XMEMCPY(output + idx, ssl->arrays->serverRandom, RAN_LEN); + idx += RAN_LEN; + output[idx++] = sessIdSz; + XMEMCPY(output + idx, ssl->arrays->sessionID, sessIdSz); + } + idx += sessIdSz; + +#ifdef SHOW_SECRETS + { + int j; + printf("server random: "); + for (j = 0; j < RAN_LEN; j++) + printf("%02x", ssl->arrays->serverRandom[j]); + printf("\n"); + } +#endif + + /* then cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + + /* then compression */ + if (ssl->options.usingCompression) + output[idx++] = ZLIB_COMPRESSION; + else + output[idx++] = NO_COMPRESSION; + + /* last, extensions */ +#ifdef HAVE_TLS_EXTENSIONS + { + word16 offset = 0; + ret = TLSX_WriteResponse(ssl, output + idx, server_hello, &offset); + if (ret != 0) + return ret; + idx += offset; + } +#else +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + c16toa(HELLO_EXT_SZ, output + idx); + idx += HELLO_EXT_SZ_SZ; + + c16toa(HELLO_EXT_EXTMS, output + idx); + idx += HELLO_EXT_TYPE_SZ; + c16toa(0, output + idx); + /*idx += HELLO_EXT_SZ_SZ;*/ + /* idx is not used after this point. uncomment the line above + * if adding any more extensions in the future. */ + } +#endif +#endif + + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */ + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + } + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "ServerHello"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "ServerHello", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + #endif + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + ssl->buffers.outputBuffer.length += sendSz; + + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + if (ssl->options.groupMessages) + ret = 0; + else + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_SEND); + + return ret; + } + + +#if defined(HAVE_ECC) + + static byte SetCurveId(ecc_key* key) + { + if (key == NULL || key->dp == NULL) { + WOLFSSL_MSG("SetCurveId: Invalid key!"); + return 0; + } + + return (byte)GetCurveByOID(key->dp->oidSum); + } + +#endif /* HAVE_ECC */ + + typedef struct SskeArgs { + byte* output; /* not allocated */ + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + (!defined(NO_DH) && !defined(NO_RSA)) + byte* sigDataBuf; + #endif + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + byte* exportBuf; + #endif + #ifndef NO_RSA + byte* verifySig; + #endif + byte* input; + word32 idx; + word32 tmpSigSz; + word32 length; + word32 sigSz; + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + (!defined(NO_DH) && !defined(NO_RSA)) + word32 sigDataSz; + #endif + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + word32 exportSz; + #endif + #ifdef HAVE_QSH + word32 qshSz; + #endif + int sendSz; + int inputSz; + } SskeArgs; + + static void FreeSskeArgs(WOLFSSL* ssl, void* pArgs) + { + SskeArgs* args = (SskeArgs*)pArgs; + + (void)ssl; + + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + if (args->exportBuf) { + XFREE(args->exportBuf, ssl->heap, DYNAMIC_TYPE_DER); + args->exportBuf = NULL; + } + #endif + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + (!defined(NO_DH) && !defined(NO_RSA)) + if (args->sigDataBuf) { + XFREE(args->sigDataBuf, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->sigDataBuf = NULL; + } + #endif + #ifndef NO_RSA + if (args->verifySig) { + XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->verifySig = NULL; + } + #endif + (void)args; + } + + /* handle generation of server_key_exchange (12) */ + int SendServerKeyExchange(WOLFSSL* ssl) + { + int ret; + #ifdef WOLFSSL_ASYNC_CRYPT + SskeArgs* args = (SskeArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); + #else + SskeArgs args[1]; + #endif + + WOLFSSL_START(WC_FUNC_SERVER_KEY_EXCHANGE_SEND); + WOLFSSL_ENTER("SendServerKeyExchange"); + + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_sske; + } + else + #endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(SskeArgs)); + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeSskeArgs; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent && ssl->options.haveQSH) { + args->qshSz = QSH_KeyGetSize(ssl); + } + #endif + + /* Do some checks / debug msgs */ + switch(ssl->specs.kea) + { + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + WOLFSSL_MSG("Using ephemeral ECDH PSK"); + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + #if defined(HAVE_ECC) + case ecc_diffie_hellman_kea: + { + if (ssl->specs.static_ecdh) { + WOLFSSL_MSG("Using Static ECDH, not sending " + "ServerKeyExchange"); + ERROR_OUT(0, exit_sske); + } + + WOLFSSL_MSG("Using ephemeral ECDH"); + break; + } + #endif /* HAVE_ECC */ + } + + /* Preparing keys */ + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && (!defined(NO_PSK) || !defined(NO_RSA)) + #if !defined(NO_PSK) + case dhe_psk_kea: + #endif + #if !defined(NO_RSA) + case diffie_hellman_kea: + #endif + { + /* Allocate DH key buffers and generate key */ + if (ssl->buffers.serverDH_P.buffer == NULL || + ssl->buffers.serverDH_G.buffer == NULL) { + ERROR_OUT(NO_DH_PARAMS, exit_sske); + } + + if (ssl->buffers.serverDH_Pub.buffer == NULL) { + /* Free'd in SSL_ResourceFree and FreeHandshakeResources */ + ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + OPAQUE16_LEN, + ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ssl->buffers.serverDH_Pub.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + } + + if (ssl->buffers.serverDH_Priv.buffer == NULL) { + /* Free'd in SSL_ResourceFree and FreeHandshakeResources */ + ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + OPAQUE16_LEN, + ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + if (ssl->buffers.serverDH_Priv.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + } + + ssl->options.dhKeySz = + (word16)ssl->buffers.serverDH_P.length; + + ret = AllocKey(ssl, DYNAMIC_TYPE_DH, + (void**)&ssl->buffers.serverDH_Key); + if (ret != 0) { + goto exit_sske; + } + + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \ + !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + if (ssl->options.dhDoKeyTest && + !ssl->options.dhKeyTested) + { + ret = wc_DhSetCheckKey( + ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); + if (ret != 0) { + goto exit_sske; + } + ssl->options.dhKeyTested = 1; + } + else + #endif + { + ret = wc_DhSetKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret != 0) { + goto exit_sske; + } + } + + ret = DhGenKeyPair(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_Priv.buffer, + (word32*)&ssl->buffers.serverDH_Priv.length, + ssl->buffers.serverDH_Pub.buffer, + (word32*)&ssl->buffers.serverDH_Pub.length); + break; + } + #endif /* !NO_DH && (!NO_PSK || !NO_RSA) */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + /* Fall through to create temp ECC key */ + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + /* need ephemeral key now, create it if missing */ + if (ssl->eccTempKey == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->eccTempKey); + if (ret != 0) { + goto exit_sske; + } + } + + if (ssl->eccTempKeyPresent == 0) { + ret = X25519MakeKey(ssl, + (curve25519_key*)ssl->eccTempKey, NULL); + if (ret == 0 || ret == WC_PENDING_E) { + ssl->eccTempKeyPresent = + DYNAMIC_TYPE_CURVE25519; + } + } + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + /* need ephemeral key now, create it if missing */ + if (ssl->eccTempKey == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->eccTempKey); + if (ret != 0) { + goto exit_sske; + } + } + + if (ssl->eccTempKeyPresent == 0) { + ret = X448MakeKey(ssl, + (curve448_key*)ssl->eccTempKey, NULL); + if (ret == 0 || ret == WC_PENDING_E) { + ssl->eccTempKeyPresent = + DYNAMIC_TYPE_CURVE448; + } + } + break; + } + #endif + #ifdef HAVE_ECC + /* need ephemeral key now, create it if missing */ + if (ssl->eccTempKey == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->eccTempKey); + if (ret != 0) { + goto exit_sske; + } + } + + if (ssl->eccTempKeyPresent == 0) { + ret = EccMakeKey(ssl, ssl->eccTempKey, NULL); + if (ret == 0 || ret == WC_PENDING_E) { + ssl->eccTempKeyPresent = DYNAMIC_TYPE_ECC; + } + } + #endif + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + default: + /* Skip ServerKeyExchange */ + goto exit_sske; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + #if (!defined(NO_DH) && !defined(NO_RSA)) || (defined(HAVE_ECC) || \ + defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) + word32 preSigSz, preSigIdx; + #endif + + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + if (ssl->arrays->server_hint[0] == 0) { + ERROR_OUT(0, exit_sske); /* don't send */ + } + + /* include size part */ + args->length = (word32)XSTRLEN(ssl->arrays->server_hint); + if (args->length > MAX_PSK_ID_LEN) { + ERROR_OUT(SERVER_HINT_ERROR, exit_sske); + } + + args->length += HINT_LEN_SZ; + args->sendSz = args->length + HANDSHAKE_HEADER_SZ + + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + args->length += args->qshSz; + args->sendSz += args->qshSz; + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_sske; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(args->output, args->length, + server_key_exchange, ssl); + + /* key data */ + #ifdef HAVE_QSH + c16toa((word16)(args->length - args->qshSz - + HINT_LEN_SZ), args->output + args->idx); + #else + c16toa((word16)(args->length - HINT_LEN_SZ), + args->output + args->idx); + #endif + + args->idx += HINT_LEN_SZ; + XMEMCPY(args->output + args->idx, + ssl->arrays->server_hint, + args->length - HINT_LEN_SZ); + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + word32 hintLen; + + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->length = LENGTH_SZ * 3 + /* p, g, pub */ + ssl->buffers.serverDH_P.length + + ssl->buffers.serverDH_G.length + + ssl->buffers.serverDH_Pub.length; + + /* include size part */ + hintLen = (word32)XSTRLEN(ssl->arrays->server_hint); + if (hintLen > MAX_PSK_ID_LEN) { + ERROR_OUT(SERVER_HINT_ERROR, exit_sske); + } + args->length += hintLen + HINT_LEN_SZ; + args->sendSz = args->length + HANDSHAKE_HEADER_SZ + + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + args->length += args->qshSz; + args->sendSz += args->qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_sske; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(args->output, args->length, + server_key_exchange, ssl); + + /* key data */ + c16toa((word16)hintLen, args->output + args->idx); + args->idx += HINT_LEN_SZ; + XMEMCPY(args->output + args->idx, + ssl->arrays->server_hint, hintLen); + args->idx += hintLen; + + /* add p, g, pub */ + c16toa((word16)ssl->buffers.serverDH_P.length, + args->output + args->idx); + args->idx += LENGTH_SZ; + XMEMCPY(args->output + args->idx, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length); + args->idx += ssl->buffers.serverDH_P.length; + + /* g */ + c16toa((word16)ssl->buffers.serverDH_G.length, + args->output + args->idx); + args->idx += LENGTH_SZ; + XMEMCPY(args->output + args->idx, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + args->idx += ssl->buffers.serverDH_G.length; + + /* pub */ + c16toa((word16)ssl->buffers.serverDH_Pub.length, + args->output + args->idx); + args->idx += LENGTH_SZ; + XMEMCPY(args->output + args->idx, + ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length); + /* No need to update idx, since sizes are already set */ + /* args->idx += ssl->buffers.serverDH_Pub.length; */ + break; + } + #endif /* !defined(NO_DH) && !defined(NO_PSK) */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + word32 hintLen; + + /* curve type, named curve, length(1) */ + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->length = ENUM_LEN + CURVE_LEN + ENUM_LEN; + + args->exportSz = MAX_EXPORT_ECC_SZ; + args->exportBuf = (byte*)XMALLOC(args->exportSz, + ssl->heap, DYNAMIC_TYPE_DER); + if (args->exportBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (wc_curve25519_export_public_ex( + (curve25519_key*)ssl->eccTempKey, + args->exportBuf, &args->exportSz, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } + else + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + if (wc_curve448_export_public_ex( + (curve448_key*)ssl->eccTempKey, + args->exportBuf, &args->exportSz, + EC448_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } + else + #endif + { + if (wc_ecc_export_x963(ssl->eccTempKey, + args->exportBuf, &args->exportSz) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } + args->length += args->exportSz; + + /* include size part */ + hintLen = (word32)XSTRLEN(ssl->arrays->server_hint); + if (hintLen > MAX_PSK_ID_LEN) { + ERROR_OUT(SERVER_HINT_ERROR, exit_sske); + } + args->length += hintLen + HINT_LEN_SZ; + args->sendSz = args->length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + args->length += args->qshSz; + args->sendSz += args->qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_sske; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* key data */ + c16toa((word16)hintLen, args->output + args->idx); + args->idx += HINT_LEN_SZ; + XMEMCPY(args->output + args->idx, + ssl->arrays->server_hint, hintLen); + args->idx += hintLen; + + /* ECC key exchange data */ + args->output[args->idx++] = named_curve; + args->output[args->idx++] = 0x00; /* leading zero */ + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) + args->output[args->idx++] = WOLFSSL_ECC_X25519; + else + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) + args->output[args->idx++] = WOLFSSL_ECC_X448; + else + #endif + { + #ifdef HAVE_ECC + args->output[args->idx++] = + SetCurveId(ssl->eccTempKey); + #endif + } + args->output[args->idx++] = (byte)args->exportSz; + XMEMCPY(args->output + args->idx, args->exportBuf, + args->exportSz); + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + enum wc_HashType hashType; + + /* curve type, named curve, length(1) */ + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->length = ENUM_LEN + CURVE_LEN + ENUM_LEN; + + /* Export temp ECC key and add to length */ + args->exportSz = MAX_EXPORT_ECC_SZ; + args->exportBuf = (byte*)XMALLOC(args->exportSz, + ssl->heap, DYNAMIC_TYPE_DER); + if (args->exportBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + if (wc_curve25519_export_public_ex( + (curve25519_key*)ssl->eccTempKey, + args->exportBuf, &args->exportSz, + EC25519_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } + else + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + if (wc_curve448_export_public_ex( + (curve448_key*)ssl->eccTempKey, + args->exportBuf, &args->exportSz, + EC448_LITTLE_ENDIAN) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + } + else + #endif + { + #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) + if (wc_ecc_export_x963(ssl->eccTempKey, + args->exportBuf, &args->exportSz) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + #endif + } + args->length += args->exportSz; + + preSigSz = args->length; + preSigIdx = args->idx; + + if (ssl->buffers.key == NULL) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + args->tmpSigSz = GetPrivateKeySigSize(ssl); + if (args->tmpSigSz == 0) { + ERROR_OUT(NO_PRIVATE_KEY, exit_sske); + } + } + else + #endif + ERROR_OUT(NO_PRIVATE_KEY, exit_sske); + } + else { + switch(ssl->suites->sigAlgo) { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + word16 keySz; + + ssl->buffers.keyType = rsa_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_sske; + } + + args->tmpSigSz = (word32)keySz; + break; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + { + word16 keySz; + + ssl->buffers.keyType = ecc_dsa_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_sske; + } + /* worst case estimate */ + args->tmpSigSz = keySz; + break; + } + #endif + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + word16 keySz; + + ssl->buffers.keyType = ed25519_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_sske; + } + + /* worst case estimate */ + args->tmpSigSz = ED25519_SIG_SIZE; + break; + } + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ed448_sa_algo: + { + word16 keySz; + + ssl->buffers.keyType = ed448_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_sske; + } + + /* worst case estimate */ + args->tmpSigSz = ED448_SIG_SIZE; + break; + } + #endif /* HAVE_ED448 */ + default: + ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ + } /* switch(ssl->specs.sig_algo) */ + } + + /* sig length */ + args->length += LENGTH_SZ; + args->length += args->tmpSigSz; + + if (IsAtLeastTLSv1_2(ssl)) { + args->length += HASH_SIG_SIZE; + } + + args->sendSz = args->length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + args->length += args->qshSz; + args->sendSz += args->qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + preSigIdx = args->idx; + } + #endif + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_sske; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* record and message headers will be added below, when we're sure + of the sig length */ + + /* key exchange data */ + args->output[args->idx++] = named_curve; + args->output[args->idx++] = 0x00; /* leading zero */ + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) + args->output[args->idx++] = WOLFSSL_ECC_X25519; + else + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) + args->output[args->idx++] = WOLFSSL_ECC_X448; + else + #endif + { + #ifdef HAVE_ECC + args->output[args->idx++] = + SetCurveId(ssl->eccTempKey); + #endif + } + args->output[args->idx++] = (byte)args->exportSz; + XMEMCPY(args->output + args->idx, args->exportBuf, args->exportSz); + args->idx += args->exportSz; + + /* Determine hash type */ + if (IsAtLeastTLSv1_2(ssl)) { + EncodeSigAlg(ssl->suites->hashAlgo, + ssl->suites->sigAlgo, + &args->output[args->idx]); + args->idx += 2; + + hashType = HashAlgoToType(ssl->suites->hashAlgo); + if (hashType == WC_HASH_TYPE_NONE) { + ERROR_OUT(ALGO_ID_E, exit_sske); + } + + } else { + /* only using sha and md5 for rsa */ + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + if (ssl->suites->sigAlgo == rsa_sa_algo) { + hashType = WC_HASH_TYPE_MD5_SHA; + } + #else + ERROR_OUT(ALGO_ID_E, exit_sske); + #endif + } + + /* Signature length will be written later, when we're sure what it is */ + + #ifdef HAVE_FUZZER + if (ssl->fuzzerCb) { + ssl->fuzzerCb(ssl, args->output + preSigIdx, + preSigSz, FUZZ_SIGNATURE, ssl->fuzzerCtx); + } + #endif + + /* Assemble buffer to hash for signature */ + args->sigDataSz = RAN_LEN + RAN_LEN + preSigSz; + args->sigDataBuf = (byte*)XMALLOC(args->sigDataSz, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (args->sigDataBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + XMEMCPY(args->sigDataBuf, ssl->arrays->clientRandom, + RAN_LEN); + XMEMCPY(args->sigDataBuf+RAN_LEN, + ssl->arrays->serverRandom, RAN_LEN); + XMEMCPY(args->sigDataBuf+RAN_LEN+RAN_LEN, + args->output + preSigIdx, preSigSz); + + if (ssl->suites->sigAlgo != ed25519_sa_algo && + ssl->suites->sigAlgo != ed448_sa_algo) { + ssl->buffers.sig.length = + wc_HashGetDigestSize(hashType); + if ((int)ssl->buffers.sig.length < 0) { + ERROR_OUT(HASH_TYPE_E, exit_sske); + } + ssl->buffers.sig.buffer = (byte*)XMALLOC( + ssl->buffers.sig.length, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + /* Perform hash */ + ret = wc_Hash(hashType, args->sigDataBuf, + args->sigDataSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length); + if (ret != 0) { + goto exit_sske; + } + } + + args->sigSz = args->tmpSigSz; + + /* Sign hash to create signature */ + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + /* For TLS 1.2 re-encode signature */ + if (IsAtLeastTLSv1_2(ssl)) { + byte* encodedSig = (byte*)XMALLOC( + MAX_ENCODED_SIG_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + ssl->buffers.sig.length = + wc_EncodeSignature(encodedSig, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + TypeHash(ssl->suites->hashAlgo)); + + /* Replace sig buffer with new one */ + XFREE(ssl->buffers.sig.buffer, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + ssl->buffers.sig.buffer = encodedSig; + } + + /* write sig size here */ + c16toa((word16)args->sigSz, + args->output + args->idx); + args->idx += LENGTH_SZ; + break; + } + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + /* write sig size here */ + c16toa((word16)args->sigSz, + args->output + args->idx); + args->idx += LENGTH_SZ; + break; + #endif + #endif /* !NO_RSA */ + case ecc_dsa_sa_algo: + { + break; + } + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + ret = Ed25519CheckPubKey(ssl); + if (ret != 0) + goto exit_sske; + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ed448_sa_algo: + ret = Ed448CheckPubKey(ssl); + if (ret != 0) + goto exit_sske; + break; + #endif /* HAVE_ED448 */ + } /* switch(ssl->specs.sig_algo) */ + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #if !defined(NO_DH) && !defined(NO_RSA) + case diffie_hellman_kea: + { + enum wc_HashType hashType; + + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->length = LENGTH_SZ * 3; /* p, g, pub */ + args->length += ssl->buffers.serverDH_P.length + + ssl->buffers.serverDH_G.length + + ssl->buffers.serverDH_Pub.length; + + preSigIdx = args->idx; + preSigSz = args->length; + + if (!ssl->options.usingAnon_cipher) { + word16 keySz; + + /* sig length */ + args->length += LENGTH_SZ; + + if (ssl->buffers.key == NULL) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) + keySz = (word32)GetPrivateKeySigSize(ssl); + else + #endif + ERROR_OUT(NO_PRIVATE_KEY, exit_sske); + } + else + { + if (ssl->buffers.keyType == 0) + ssl->buffers.keyType = rsa_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_sske; + } + } + + if (keySz == 0) { /* test if keySz has error */ + ERROR_OUT(keySz, exit_sske); + } + + args->tmpSigSz = (word32)keySz; + args->length += args->tmpSigSz; + + if (IsAtLeastTLSv1_2(ssl)) { + args->length += HASH_SIG_SIZE; + } + } + + args->sendSz = args->length + HANDSHAKE_HEADER_SZ + + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + args->length += args->qshSz; + args->sendSz += args->qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + preSigIdx = args->idx; + } + #endif + + if (IsEncryptionOn(ssl, 1)) { + args->sendSz += MAX_MSG_EXTRA; + } + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_sske; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(args->output, args->length, + server_key_exchange, ssl); + + /* add p, g, pub */ + c16toa((word16)ssl->buffers.serverDH_P.length, + args->output + args->idx); + args->idx += LENGTH_SZ; + XMEMCPY(args->output + args->idx, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length); + args->idx += ssl->buffers.serverDH_P.length; + + /* g */ + c16toa((word16)ssl->buffers.serverDH_G.length, + args->output + args->idx); + args->idx += LENGTH_SZ; + XMEMCPY(args->output + args->idx, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + args->idx += ssl->buffers.serverDH_G.length; + + /* pub */ + c16toa((word16)ssl->buffers.serverDH_Pub.length, + args->output + args->idx); + args->idx += LENGTH_SZ; + XMEMCPY(args->output + args->idx, + ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length); + args->idx += ssl->buffers.serverDH_Pub.length; + + #ifdef HAVE_FUZZER + if (ssl->fuzzerCb) { + ssl->fuzzerCb(ssl, args->output + preSigIdx, + preSigSz, FUZZ_SIGNATURE, ssl->fuzzerCtx); + } + #endif + + if (ssl->options.usingAnon_cipher) { + break; + } + + /* Determine hash type */ + if (IsAtLeastTLSv1_2(ssl)) { + EncodeSigAlg(ssl->suites->hashAlgo, + ssl->suites->sigAlgo, + &args->output[args->idx]); + args->idx += 2; + + hashType = HashAlgoToType(ssl->suites->hashAlgo); + if (hashType == WC_HASH_TYPE_NONE) { + ERROR_OUT(ALGO_ID_E, exit_sske); + } + } else { + /* only using sha and md5 for rsa */ + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + if (ssl->suites->sigAlgo == rsa_sa_algo) { + hashType = WC_HASH_TYPE_MD5_SHA; + } + #else + ERROR_OUT(ALGO_ID_E, exit_sske); + #endif + } + + /* signature size */ + c16toa((word16)args->tmpSigSz, args->output + args->idx); + args->idx += LENGTH_SZ; + + /* Assemble buffer to hash for signature */ + args->sigDataSz = RAN_LEN + RAN_LEN + preSigSz; + args->sigDataBuf = (byte*)XMALLOC(args->sigDataSz, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (args->sigDataBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + XMEMCPY(args->sigDataBuf, ssl->arrays->clientRandom, + RAN_LEN); + XMEMCPY(args->sigDataBuf+RAN_LEN, + ssl->arrays->serverRandom, RAN_LEN); + XMEMCPY(args->sigDataBuf+RAN_LEN+RAN_LEN, + args->output + preSigIdx, preSigSz); + + if (ssl->suites->sigAlgo != ed25519_sa_algo && + ssl->suites->sigAlgo != ed448_sa_algo) { + ssl->buffers.sig.length = + wc_HashGetDigestSize(hashType); + ssl->buffers.sig.buffer = (byte*)XMALLOC( + ssl->buffers.sig.length, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + /* Perform hash */ + ret = wc_Hash(hashType, args->sigDataBuf, + args->sigDataSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length); + if (ret != 0) { + goto exit_sske; + } + } + + args->sigSz = args->tmpSigSz; + + /* Sign hash to create signature */ + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + /* For TLS 1.2 re-encode signature */ + if (IsAtLeastTLSv1_2(ssl)) { + byte* encodedSig = (byte*)XMALLOC( + MAX_ENCODED_SIG_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + ssl->buffers.sig.length = + wc_EncodeSignature(encodedSig, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + TypeHash(ssl->suites->hashAlgo)); + + /* Replace sig buffer with new one */ + XFREE(ssl->buffers.sig.buffer, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + ssl->buffers.sig.buffer = encodedSig; + } + break; + } + #endif /* NO_RSA */ + } /* switch (ssl->suites->sigAlgo) */ + break; + } + #endif /* !defined(NO_DH) && !defined(NO_RSA) */ + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + break; + } + #endif /* !defined(NO_DH) && !defined(NO_PSK) */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + case ecc_diffie_hellman_kea: + { + /* Sign hash to create signature */ + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + RsaKey* key = (RsaKey*)ssl->hsKey; + + ret = RsaSign(ssl, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + args->output + args->idx, + &args->sigSz, + ssl->suites->sigAlgo, ssl->suites->hashAlgo, + key, + ssl->buffers.key + ); + break; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + { + ecc_key* key = (ecc_key*)ssl->hsKey; + + ret = EccSign(ssl, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + args->output + LENGTH_SZ + args->idx, + &args->sigSz, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + break; + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + { + ed25519_key* key = (ed25519_key*)ssl->hsKey; + + ret = Ed25519Sign(ssl, + args->sigDataBuf, args->sigDataSz, + args->output + LENGTH_SZ + args->idx, + &args->sigSz, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + break; + } + #endif + #ifdef HAVE_ED448 + case ed448_sa_algo: + { + ed448_key* key = (ed448_key*)ssl->hsKey; + + ret = Ed448Sign(ssl, + args->sigDataBuf, args->sigDataSz, + args->output + LENGTH_SZ + args->idx, + &args->sigSz, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + break; + } + #endif + } /* switch(ssl->specs.sig_algo) */ + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #if !defined(NO_DH) && !defined(NO_RSA) + case diffie_hellman_kea: + { + /* Sign hash to create signature */ + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + RsaKey* key = (RsaKey*)ssl->hsKey; + + if (ssl->options.usingAnon_cipher) { + break; + } + + ret = RsaSign(ssl, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + args->output + args->idx, + &args->sigSz, + ssl->suites->sigAlgo, ssl->suites->hashAlgo, + key, + ssl->buffers.key + ); + break; + } + #endif /* NO_RSA */ + } /* switch (ssl->suites->sigAlgo) */ + + break; + } + #endif /* !defined(NO_DH) && !defined(NO_RSA) */ + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* !defined(NO_DH) && !defined(NO_PSK) */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + switch(ssl->suites->sigAlgo) + { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + RsaKey* key = (RsaKey*)ssl->hsKey; + + if (args->verifySig == NULL) { + if (args->sigSz == 0) { + ERROR_OUT(BAD_COND_E, exit_sske); + } + args->verifySig = (byte*)XMALLOC( + args->sigSz, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (!args->verifySig) { + ERROR_OUT(MEMORY_E, exit_sske); + } + XMEMCPY(args->verifySig, + args->output + args->idx, args->sigSz); + } + + /* check for signature faults */ + ret = VerifyRsaSign(ssl, + args->verifySig, args->sigSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->suites->sigAlgo, ssl->suites->hashAlgo, + key, ssl->buffers.key + ); + break; + } + #endif + case ecc_dsa_sa_algo: + #ifdef HAVE_ED25519 + case ed25519_sa_algo: + #endif + #ifdef HAVE_ED448 + case ed448_sa_algo: + #endif + { + /* Now that we know the real sig size, write it. */ + c16toa((word16)args->sigSz, + args->output + args->idx); + + /* And adjust length and sendSz from estimates */ + args->length += args->sigSz - args->tmpSigSz; + args->sendSz += args->sigSz - args->tmpSigSz; + break; + } + default: + ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ + } /* switch(ssl->specs.sig_algo) */ + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #if !defined(NO_DH) && !defined(NO_RSA) + case diffie_hellman_kea: + { + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + #ifndef WC_RSA_PSS + case rsa_pss_sa_algo: + #endif + case rsa_sa_algo: + { + RsaKey* key = (RsaKey*)ssl->hsKey; + + if (ssl->options.usingAnon_cipher) { + break; + } + + if (args->verifySig == NULL) { + if (args->sigSz == 0) { + ERROR_OUT(BAD_COND_E, exit_sske); + } + args->verifySig = (byte*)XMALLOC( + args->sigSz, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (!args->verifySig) { + ERROR_OUT(MEMORY_E, exit_sske); + } + XMEMCPY(args->verifySig, + args->output + args->idx, args->sigSz); + } + + /* check for signature faults */ + ret = VerifyRsaSign(ssl, + args->verifySig, args->sigSz, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + ssl->suites->sigAlgo, ssl->suites->hashAlgo, + key, ssl->buffers.key + ); + break; + } + #endif + } /* switch (ssl->suites->sigAlgo) */ + break; + } + #endif /* !defined(NO_DH) && !defined(NO_RSA) */ + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + if (args->qshSz > 0) { + args->idx = args->sendSz - args->qshSz; + if (QSH_KeyExchangeWrite(ssl, 1) != 0) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + /* extension type */ + c16toa(TLSX_QUANTUM_SAFE_HYBRID, + args->output + args->idx); + args->idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, + args->output + args->idx) > + args->qshSz - OPAQUE16_LEN) { + ERROR_OUT(MEMORY_E, exit_sske); + } + } + } + #endif + + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + if (ssl->specs.kea == ecdhe_psk_kea || + ssl->specs.kea == ecc_diffie_hellman_kea) { + /* Check output to make sure it was set */ + if (args->output) { + AddHeaders(args->output, args->length, + server_key_exchange, ssl); + } + else { + ERROR_OUT(BUFFER_ERROR, exit_sske); + } + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + + if (IsEncryptionOn(ssl, 1)) { + args->inputSz = args->length + HANDSHAKE_HEADER_SZ; + /* buildmsg adds rechdr */ + args->input = (byte*)XMALLOC(args->inputSz, ssl->heap, + DYNAMIC_TYPE_IN_BUFFER); + if (args->input == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + if (args->output == NULL) { + ERROR_OUT(BUFFER_ERROR, exit_sske); + } + + XMEMCPY(args->input, args->output + RECORD_HEADER_SZ, + args->inputSz); + ret = BuildMessage(ssl, args->output, args->sendSz, + args->input, args->inputSz, handshake, 1, 0, 0); + XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + args->input = NULL; + /* make sure its not double free'd on cleanup */ + + if (ret >= 0) { + args->sendSz = ret; + ret = 0; + } + } + else { + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, + args->output, args->sendSz)) != 0) { + goto exit_sske; + } + } + + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + + ret = HashOutput(ssl, args->output, args->sendSz, 0); + if (ret != 0) { + goto exit_sske; + } + } + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) { + AddPacketName(ssl, "ServerKeyExchange"); + } + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "ServerKeyExchange", handshake, + args->output, args->sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + ssl->buffers.outputBuffer.length += args->sendSz; + if (!ssl->options.groupMessages) { + ret = SendBuffered(ssl); + } + + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + + exit_sske: + + WOLFSSL_LEAVE("SendServerKeyExchange", ret); + WOLFSSL_END(WC_FUNC_SERVER_KEY_EXCHANGE_SEND); + + #ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) + return ret; + #endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Final cleanup */ + FreeSskeArgs(ssl, args); + FreeKeyExchange(ssl); + + return ret; + } + +#if defined(HAVE_SERVER_RENEGOTIATION_INFO) || defined(HAVE_FALLBACK_SCSV) || \ + defined(OPENSSL_ALL) + + /* search suites for specific one, idx on success, negative on error */ +#ifndef WOLFSSL_TLS13 + static +#endif + int FindSuite(Suites* suites, byte first, byte second) + { + int i; + + if (suites == NULL || suites->suiteSz == 0) { + WOLFSSL_MSG("Suites pointer error or suiteSz 0"); + return SUITES_ERROR; + } + + for (i = 0; i < suites->suiteSz-1; i += SUITE_LEN) { + if (suites->suites[i] == first && + suites->suites[i+1] == second ) + return i; + } + + return MATCH_SUITE_ERROR; + } + +#endif + +#endif /* !WOLFSSL_NO_TLS12 */ + + /* Make sure server cert/key are valid for this suite, true on success */ + static int VerifyServerSuite(WOLFSSL* ssl, word16 idx) + { + int haveRSA = !ssl->options.haveStaticECC; + int havePSK = 0; + byte first; + byte second; + + WOLFSSL_ENTER("VerifyServerSuite"); + + if (ssl->suites == NULL) { + WOLFSSL_MSG("Suites pointer error"); + return 0; + } + + first = ssl->suites->suites[idx]; + second = ssl->suites->suites[idx+1]; + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + + if (ssl->options.haveNTRU) + haveRSA = 0; + + if (CipherRequires(first, second, REQUIRES_RSA)) { + WOLFSSL_MSG("Requires RSA"); + if (haveRSA == 0) { + WOLFSSL_MSG("Don't have RSA"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_DHE)) { + WOLFSSL_MSG("Requires DHE"); + if (ssl->options.haveDH == 0) { + WOLFSSL_MSG("Don't have DHE"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_ECC)) { + WOLFSSL_MSG("Requires ECC"); + if (ssl->options.haveECC == 0) { + WOLFSSL_MSG("Don't have ECC"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) { + WOLFSSL_MSG("Requires static ECC"); + if (ssl->options.haveStaticECC == 0) { + WOLFSSL_MSG("Don't have static ECC"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_PSK)) { + WOLFSSL_MSG("Requires PSK"); + if (havePSK == 0) { + WOLFSSL_MSG("Don't have PSK"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_NTRU)) { + WOLFSSL_MSG("Requires NTRU"); + if (ssl->options.haveNTRU == 0) { + WOLFSSL_MSG("Don't have NTRU"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_RSA_SIG)) { + WOLFSSL_MSG("Requires RSA Signature"); + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.haveECDSAsig == 1) { + WOLFSSL_MSG("Don't have RSA Signature"); + return 0; + } + } + +#if !defined(WOLFSSL_OLDTLS_AEAD_CIPHERSUITES) + if (CipherRequires(first, second, REQUIRES_AEAD)) { + WOLFSSL_MSG("Requires AEAD"); + if (ssl->version.major == SSLv3_MAJOR && + ssl->version.minor < TLSv1_2_MINOR) { + WOLFSSL_MSG("Version of SSL does not support AEAD ciphers"); + return 0; + } + + } +#endif + +#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES) + if (!TLSX_ValidateSupportedCurves(ssl, first, second)) { + WOLFSSL_MSG("Don't have matching curves"); + return 0; + } +#endif + + /* ECCDHE is always supported if ECC on */ + +#ifdef HAVE_QSH + /* need to negotiate a classic suite in addition to TLS_QSH */ + if (first == QSH_BYTE && second == TLS_QSH) { + if (TLSX_SupportExtensions(ssl)) { + ssl->options.haveQSH = 1; /* matched TLS_QSH */ + } + else { + WOLFSSL_MSG("Version of SSL connection does not support " + "TLS_QSH"); + } + return 0; + } +#endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + ssl->options.side == WOLFSSL_SERVER_END) { + /* Try to establish a key share. */ + int ret = TLSX_KeyShare_Establish(ssl); + if (ret == KEY_SHARE_ERROR) + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + else if (ret != 0) + return 0; + } + else if (first == TLS13_BYTE || (first == ECC_BYTE && + (second == TLS_SHA256_SHA256 || second == TLS_SHA384_SHA384))) { + /* Can't negotiate TLS 1.3 cipher suites with lower protocol + * version. */ + return 0; + } +#endif + + return 1; + } + +#ifndef NO_WOLFSSL_SERVER + static int CompareSuites(WOLFSSL* ssl, Suites* peerSuites, word16 i, + word16 j) + { + if (ssl->suites->suites[i] == peerSuites->suites[j] && + ssl->suites->suites[i+1] == peerSuites->suites[j+1] ) { + + if (VerifyServerSuite(ssl, i)) { + int result; + WOLFSSL_MSG("Verified suite validity"); + ssl->options.cipherSuite0 = ssl->suites->suites[i]; + ssl->options.cipherSuite = ssl->suites->suites[i+1]; + result = SetCipherSpecs(ssl); + if (result == 0) { + result = PickHashSigAlgo(ssl, peerSuites->hashSigAlgo, + peerSuites->hashSigAlgoSz); + } + return result; + } + else { + WOLFSSL_MSG("Could not verify suite validity, continue"); + } + } + + return MATCH_SUITE_ERROR; + } + + int MatchSuite(WOLFSSL* ssl, Suites* peerSuites) + { + int ret; + word16 i, j; + + WOLFSSL_ENTER("MatchSuite"); + + /* & 0x1 equivalent % 2 */ + if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1) + return BUFFER_ERROR; + + if (ssl->suites == NULL) + return SUITES_ERROR; + + if (!ssl->options.useClientOrder) { + /* Server order */ + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + for (j = 0; j < peerSuites->suiteSz; j += 2) { + ret = CompareSuites(ssl, peerSuites, i, j); + if (ret != MATCH_SUITE_ERROR) + return ret; + } + } + } + else { + /* Client order */ + for (j = 0; j < peerSuites->suiteSz; j += 2) { + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + ret = CompareSuites(ssl, peerSuites, i, j); + if (ret != MATCH_SUITE_ERROR) + return ret; + } + } + } + + return MATCH_SUITE_ERROR; + } +#endif + +#ifdef OLD_HELLO_ALLOWED + + /* process old style client hello, deprecate? */ + int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 inSz, word16 sz) + { + word32 idx = *inOutIdx; + word16 sessionSz; + word16 randomSz; + word16 i, j; + ProtocolVersion pv; + Suites clSuites; + int ret = -1; + + (void)inSz; + WOLFSSL_MSG("Got old format client hello"); +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) + AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* manually hash input since different format */ +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, input + idx, sz); +#endif +#ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, input + idx, sz); +#endif +#endif +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) { + int shaRet = wc_Sha256Update(&ssl->hsHashes->hashSha256, + input + idx, sz); + if (shaRet != 0) + return shaRet; + } +#endif + + /* does this value mean client_hello? */ + idx++; + + /* version */ + pv.major = input[idx++]; + pv.minor = input[idx++]; + ssl->chVersion = pv; /* store */ + + if (ssl->version.minor > pv.minor) { + byte haveRSA = 0; + byte havePSK = 0; + int keySz = 0; + + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Client trying to connect with lesser version"); + return VERSION_ERROR; + } + if (pv.minor < ssl->options.minDowngrade) { + WOLFSSL_MSG("\tversion below minimum allowed, fatal error"); + return VERSION_ERROR; + } + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + WOLFSSL_MSG("\tdowngrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + WOLFSSL_MSG("\tdowngrading to TLSv1"); + /* turn off tls 1.1+ */ + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + WOLFSSL_MSG("\tdowngrading to TLSv1.1"); + ssl->version.minor = TLSv1_1_MINOR; + } + else if (pv.minor == TLSv1_2_MINOR) { + WOLFSSL_MSG(" downgrading to TLSv1.2"); + ssl->version.minor = TLSv1_2_MINOR; + } +#ifndef NO_RSA + haveRSA = 1; +#endif +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif +#ifndef NO_CERTS + keySz = ssl->buffers.keySz; +#endif + + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + + /* suite size */ + ato16(&input[idx], &clSuites.suiteSz); + idx += OPAQUE16_LEN; + + if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ) + return BUFFER_ERROR; + clSuites.hashSigAlgoSz = 0; + + /* session size */ + ato16(&input[idx], &sessionSz); + idx += OPAQUE16_LEN; + + if (sessionSz > ID_LEN) + return BUFFER_ERROR; + + /* random size */ + ato16(&input[idx], &randomSz); + idx += OPAQUE16_LEN; + + if (randomSz > RAN_LEN) + return BUFFER_ERROR; + + /* suites */ + for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) { + byte first = input[idx++]; + if (!first) { /* implicit: skip sslv2 type */ + XMEMCPY(&clSuites.suites[j], &input[idx], SUITE_LEN); + j += SUITE_LEN; + } + idx += SUITE_LEN; + } + clSuites.suiteSz = j; + + /* session id */ + if (sessionSz) { + XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz); + ssl->arrays->sessionIDSz = (byte)sessionSz; + idx += sessionSz; + ssl->options.resuming = 1; + } + + /* random */ + if (randomSz < RAN_LEN) + XMEMSET(ssl->arrays->clientRandom, 0, RAN_LEN - randomSz); + XMEMCPY(&ssl->arrays->clientRandom[RAN_LEN - randomSz], input + idx, + randomSz); + idx += randomSz; + + if (ssl->options.usingCompression) + ssl->options.usingCompression = 0; /* turn off */ + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->cbmode = SSL_CB_MODE_WRITE; + *inOutIdx = idx; + + ssl->options.haveSessionId = 1; + /* DoClientHello uses same resume code */ + if (ssl->options.resuming) { /* let's try */ + WOLFSSL_SESSION* session = GetSession(ssl, + ssl->arrays->masterSecret, 1); + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket == 1) { + session = &ssl->session; + } + #endif + + if (!session) { + WOLFSSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } else { + #ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(session); + #endif + if (MatchSuite(ssl, &clSuites) < 0) { + WOLFSSL_MSG("Unsupported cipher suite, OldClientHello"); + return UNSUPPORTED_SUITE; + } + + ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, + RAN_LEN); + if (ret != 0) + return ret; + + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + + return ret; + } + } + + ret = MatchSuite(ssl, &clSuites); + if (ret != 0)return ret; + return SanityCheckMsgReceived(ssl, client_hello); + } + +#endif /* OLD_HELLO_ALLOWED */ + +#ifndef WOLFSSL_NO_TLS12 + + int HandleTlsResumption(WOLFSSL* ssl, int bogusID, Suites* clSuites) + { + int ret = 0; + WOLFSSL_SESSION* session; + + (void)bogusID; + + session = GetSession(ssl, ssl->arrays->masterSecret, 1); + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket == 1) { + session = &ssl->session; + } else if (bogusID == 1 && ssl->options.rejectTicket == 0) { + WOLFSSL_MSG("Bogus session ID without session ticket"); + return BUFFER_ERROR; + } + #endif + + if (!session) { + WOLFSSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } + else if (session->haveEMS != ssl->options.haveEMS) { + /* RFC 7627, 5.3, server-side */ + /* if old sess didn't have EMS, but new does, full handshake */ + if (!session->haveEMS && ssl->options.haveEMS) { + WOLFSSL_MSG("Attempting to resume a session that didn't " + "use EMS with a new session with EMS. Do full " + "handshake."); + ssl->options.resuming = 0; + } + /* if old sess used EMS, but new doesn't, MUST abort */ + else if (session->haveEMS && !ssl->options.haveEMS) { + WOLFSSL_MSG("Trying to resume a session with EMS without " + "using EMS"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, handshake_failure); + #endif + return EXT_MASTER_SECRET_NEEDED_E; + } + #ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(session); + #endif + } + else { + #ifndef NO_RESUME_SUITE_CHECK + int j; + + /* Check client suites include the one in session */ + for (j = 0; j < clSuites->suiteSz; j += 2) { + if (clSuites->suites[j] == session->cipherSuite0 && + clSuites->suites[j+1] == session->cipherSuite) { + break; + } + } + if (j == clSuites->suiteSz) { + WOLFSSL_MSG("Prev session's cipher suite not in ClientHello"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, illegal_parameter); + #endif + return UNSUPPORTED_SUITE; + } + #endif + + #ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(session); + #endif + if (MatchSuite(ssl, clSuites) < 0) { + WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); + return UNSUPPORTED_SUITE; + } + + ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, + RAN_LEN); + if (ret != 0) + return ret; + + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + } + + return ret; + } + + + /* handle processing of client_hello (1) */ + int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte b; + byte bogusID = 0; /* flag for a bogus session id */ + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + int ret = 0; +#ifdef WOLFSSL_DTLS + Hmac cookieHmac; + byte peerCookie[MAX_COOKIE_LEN]; + byte peerCookieSz = 0; + byte cookieType; + byte cookieSz = 0; + + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); +#endif /* WOLFSSL_DTLS */ + + WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); + WOLFSSL_ENTER("DoClientHello"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + /* protocol version, random and session id length check */ + if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + ssl->chVersion = pv; /* store */ +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + #if defined(NO_SHA) && defined(NO_SHA256) + #error "DTLS needs either SHA or SHA-256" + #endif /* NO_SHA && NO_SHA256 */ + + #if !defined(NO_SHA) && defined(NO_SHA256) + cookieType = WC_SHA; + cookieSz = WC_SHA_DIGEST_SIZE; + #endif /* NO_SHA */ + #ifndef NO_SHA256 + cookieType = WC_SHA256; + cookieSz = WC_SHA256_DIGEST_SIZE; + #endif /* NO_SHA256 */ + ret = wc_HmacSetKey(&cookieHmac, cookieType, + ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + if (ret != 0) return ret; + ret = wc_HmacUpdate(&cookieHmac, + (const byte*)ssl->buffers.dtlsCtx.peer.sa, + ssl->buffers.dtlsCtx.peer.sz); + if (ret != 0) return ret; + ret = wc_HmacUpdate(&cookieHmac, input + i, OPAQUE16_LEN); + if (ret != 0) return ret; + } +#endif /* WOLFSSL_DTLS */ + i += OPAQUE16_LEN; + + /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */ + if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR) + pv.minor = TLSv1_2_MINOR; + + if ((!ssl->options.dtls && ssl->version.minor > pv.minor) || + (ssl->options.dtls && ssl->version.minor != DTLS_MINOR + && ssl->version.minor != DTLSv1_2_MINOR && pv.minor != DTLS_MINOR + && pv.minor != DTLSv1_2_MINOR)) { + + word16 haveRSA = 0; + word16 havePSK = 0; + int keySz = 0; + + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Client trying to connect with lesser version"); + return VERSION_ERROR; + } + if (pv.minor < ssl->options.minDowngrade) { + WOLFSSL_MSG("\tversion below minimum allowed, fatal error"); + return VERSION_ERROR; + } + + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + WOLFSSL_MSG("\tdowngrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + /* turn off tls 1.1+ */ + WOLFSSL_MSG("\tdowngrading to TLSv1"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + WOLFSSL_MSG("\tdowngrading to TLSv1.1"); + ssl->version.minor = TLSv1_1_MINOR; + } + else if (pv.minor == TLSv1_2_MINOR) { + WOLFSSL_MSG(" downgrading to TLSv1.2"); + ssl->version.minor = TLSv1_2_MINOR; + } +#ifndef NO_RSA + haveRSA = 1; +#endif +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif +#ifndef NO_CERTS + keySz = ssl->buffers.keySz; +#endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + +#ifdef OPENSSL_EXTRA + /* check if option is set to not allow the current version + * set from either wolfSSL_set_options or wolfSSL_CTX_set_options */ + if (!ssl->options.dtls && ssl->options.downgrade && + ssl->options.mask > 0) { + int reset = 0; + if (ssl->version.minor == TLSv1_2_MINOR && + (ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) { + WOLFSSL_MSG("\tOption set to not allow TLSv1.2, Downgrading"); + ssl->version.minor = TLSv1_1_MINOR; + reset = 1; + } + if (ssl->version.minor == TLSv1_1_MINOR && + (ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) { + WOLFSSL_MSG("\tOption set to not allow TLSv1.1, Downgrading"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + reset = 1; + } + if (ssl->version.minor == TLSv1_MINOR && + (ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) { + WOLFSSL_MSG("\tOption set to not allow TLSv1, Downgrading"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + reset = 1; + } + if (ssl->version.minor == SSLv3_MINOR && + (ssl->options.mask & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) { + WOLFSSL_MSG("\tError, option set to not allow SSLv3"); + return VERSION_ERROR; + } + + if (ssl->version.minor < ssl->options.minDowngrade) { + WOLFSSL_MSG("\tversion below minimum allowed, fatal error"); + return VERSION_ERROR; + } + + if (reset) { + word16 haveRSA = 0; + word16 havePSK = 0; + int keySz = 0; + + #ifndef NO_RSA + haveRSA = 1; + #endif + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + + /* reset cipher suites to account for TLS version change */ + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + } +#endif + + /* random */ + XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN); + if (ret != 0) return ret; + } +#endif /* WOLFSSL_DTLS */ + i += RAN_LEN; + +#ifdef SHOW_SECRETS + { + int j; + printf("client random: "); + for (j = 0; j < RAN_LEN; j++) + printf("%02x", ssl->arrays->clientRandom[j]); + printf("\n"); + } +#endif + + /* session id */ + b = input[i++]; + +#ifdef HAVE_SESSION_TICKET + if (b > 0 && b < ID_LEN) { + bogusID = 1; + WOLFSSL_MSG("Client sent bogus session id, let's allow for echo"); + } +#endif + + if (b == ID_LEN || bogusID) { + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->sessionID, input + i, b); +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1); + if (ret != 0) return ret; + } +#endif /* WOLFSSL_DTLS */ + ssl->arrays->sessionIDSz = b; + i += b; + ssl->options.resuming = 1; /* client wants to resume */ + WOLFSSL_MSG("Client wants to resume session"); + } + else if (b) { + WOLFSSL_MSG("Invalid session ID size"); + return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } + + #ifdef WOLFSSL_DTLS + /* cookie */ + if (ssl->options.dtls) { + + if ((i - begin) + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + peerCookieSz = input[i++]; + + if (peerCookieSz) { + if (peerCookieSz > MAX_COOKIE_LEN) + return BUFFER_ERROR; + + if ((i - begin) + peerCookieSz > helloSz) + return BUFFER_ERROR; + + XMEMCPY(peerCookie, input + i, peerCookieSz); + + i += peerCookieSz; + } + } + #endif + + /* suites */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &clSuites.suiteSz); + i += OPAQUE16_LEN; + + /* suites and compression length check */ + if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ) + return BUFFER_ERROR; + + XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); + +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */ + if (FindSuite(&clSuites, 0, TLS_EMPTY_RENEGOTIATION_INFO_SCSV) >= 0) { + TLSX* extension; + + /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */ + ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (extension) { + ssl->secure_renegotiation = + (SecureRenegotiation*)extension->data; + ssl->secure_renegotiation->enabled = 1; + } + } +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ +#if defined(HAVE_FALLBACK_SCSV) || defined(OPENSSL_ALL) + /* check for TLS_FALLBACK_SCSV suite */ + if (FindSuite(&clSuites, TLS_FALLBACK_SCSV, 0) >= 0) { + WOLFSSL_MSG("Found Fallback SCSV"); + if (ssl->ctx->method->version.minor > pv.minor) { + WOLFSSL_MSG("Client trying to connect with lesser version"); + SendAlert(ssl, alert_fatal, inappropriate_fallback); + return VERSION_ERROR; + } + } +#endif + +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + ret = wc_HmacUpdate(&cookieHmac, + input + i - OPAQUE16_LEN, + clSuites.suiteSz + OPAQUE16_LEN); + if (ret != 0) return ret; + } +#endif /* WOLFSSL_DTLS */ + i += clSuites.suiteSz; + clSuites.hashSigAlgoSz = 0; + + /* compression length */ + b = input[i++]; + + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + + if (b == 0) { + WOLFSSL_MSG("No compression types in list"); +#ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, decode_error); +#endif + return COMPRESSION_ERROR; + } + +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + byte newCookie[MAX_COOKIE_LEN]; + + ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1); + if (ret != 0) return ret; + ret = wc_HmacFinal(&cookieHmac, newCookie); + if (ret != 0) return ret; + + /* If a cookie callback is set, call it to overwrite the cookie. + * This should be deprecated. The code now calculates the cookie + * using an HMAC as expected. */ + if (ssl->ctx->CBIOCookie != NULL && + ssl->ctx->CBIOCookie(ssl, newCookie, cookieSz, + ssl->IOCB_CookieCtx) != cookieSz) { + return COOKIE_ERROR; + } + + /* Check the cookie, see if we progress the state machine. */ + if (peerCookieSz != cookieSz || + XMEMCMP(peerCookie, newCookie, cookieSz) != 0) { + + /* Send newCookie to client in a HelloVerifyRequest message + * and let the state machine alone. */ + ssl->msgsReceived.got_client_hello = 0; + ssl->keys.dtls_handshake_number = 0; + ssl->keys.dtls_expected_peer_handshake_number = 0; + *inOutIdx += helloSz; + return SendHelloVerifyRequest(ssl, newCookie, cookieSz); + } + + /* This was skipped in the DTLS case so we could handle the hello + * verify request. */ + ret = HashInput(ssl, input + *inOutIdx, helloSz); + if (ret != 0) return ret; + } +#endif /* WOLFSSL_DTLS */ + + { + /* compression match types */ + int matchNo = 0; + int matchZlib = 0; + + while (b--) { + byte comp = input[i++]; + + if (comp == NO_COMPRESSION) { + matchNo = 1; + } + if (comp == ZLIB_COMPRESSION) { + matchZlib = 1; + } + } + + if (ssl->options.usingCompression == 0 && matchNo) { + WOLFSSL_MSG("Matched No Compression"); + } else if (ssl->options.usingCompression && matchZlib) { + WOLFSSL_MSG("Matched zlib Compression"); + } else if (ssl->options.usingCompression && matchNo) { + WOLFSSL_MSG("Could only match no compression, turning off"); + ssl->options.usingCompression = 0; /* turn off */ + } else { + WOLFSSL_MSG("Could not match compression"); +#ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, illegal_parameter); +#endif + return COMPRESSION_ERROR; + } + } + + *inOutIdx = i; + + /* tls extensions */ + if ((i - begin) < helloSz) { +#ifdef HAVE_TLS_EXTENSIONS + #ifdef HAVE_QSH + QSH_Init(ssl); + #endif + if (TLSX_SupportExtensions(ssl)) +#else + if (IsAtLeastTLSv1_2(ssl)) +#endif + { + /* Process the hello extension. Skip unsupported. */ + word16 totalExtSz; + +#ifdef HAVE_TLS_EXTENSIONS + /* auto populate extensions supported unless user defined */ + if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) + return ret; +#endif + + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + +#ifdef HAVE_TLS_EXTENSIONS + /* tls extensions */ + if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, + client_hello, &clSuites))) + return ret; + #ifdef WOLFSSL_TLS13 + if (TLSX_Find(ssl->extensions, + TLSX_SUPPORTED_VERSIONS) != NULL) { + WOLFSSL_MSG( + "Client attempting to connect with higher version"); + return VERSION_ERROR; + } + #endif + #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + if((ret=SNI_Callback(ssl))) + return ret; + ssl->options.side = WOLFSSL_SERVER_END; + #endif + + i += totalExtSz; +#else + while (totalExtSz) { + word16 extId, extSz; + + if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz) + return BUFFER_ERROR; + + ato16(&input[i], &extId); + i += OPAQUE16_LEN; + ato16(&input[i], &extSz); + i += OPAQUE16_LEN; + + if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz) + return BUFFER_ERROR; + + if (extId == HELLO_EXT_SIG_ALGO) { + word16 hashSigAlgoSz; + + ato16(&input[i], &hashSigAlgoSz); + i += OPAQUE16_LEN; + + if (OPAQUE16_LEN + hashSigAlgoSz > extSz) + return BUFFER_ERROR; + + clSuites.hashSigAlgoSz = hashSigAlgoSz; + if (clSuites.hashSigAlgoSz > WOLFSSL_MAX_SIGALGO) { + WOLFSSL_MSG("ClientHello SigAlgo list exceeds max, " + "truncating"); + clSuites.hashSigAlgoSz = WOLFSSL_MAX_SIGALGO; + } + + XMEMCPY(clSuites.hashSigAlgo, &input[i], + clSuites.hashSigAlgoSz); + + i += hashSigAlgoSz; + } +#ifdef HAVE_EXTENDED_MASTER + else if (extId == HELLO_EXT_EXTMS) + ssl->options.haveEMS = 1; +#endif + else + i += extSz; + + totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz; + } +#endif + *inOutIdx = i; + } + else + *inOutIdx = begin + helloSz; /* skip extensions */ + } + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.haveSessionId = 1; + + /* ProcessOld uses same resume code */ + if (ssl->options.resuming) { + ret = HandleTlsResumption(ssl, bogusID, &clSuites); + if (ret != 0) + return ret; + + #ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->enabled && + IsEncryptionOn(ssl, 0)) + ssl->secure_renegotiation->startScr = 1; + #endif + + if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) { + WOLFSSL_LEAVE("DoClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); + + return ret; + } + } + +#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_DH_DEFAULT_PARAMS) + #if defined(HAVE_FFDHE) && defined(HAVE_SUPPORTED_CURVES) + if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS) != NULL) { + /* Set FFDHE parameters or clear DHE parameters if FFDH parameters + * present and no matches in the server's list. */ + ret = TLSX_SupportedFFDHE_Set(ssl); + if (ret != 0) + return ret; + } + #endif +#endif + + ret = MatchSuite(ssl, &clSuites); +#ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_ERROR) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret < 0) + SendAlert(ssl, alert_fatal, handshake_failure); +#endif + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled && + IsEncryptionOn(ssl, 0)) { + ssl->secure_renegotiation->startScr = 1; + } +#endif + WOLFSSL_LEAVE("DoClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); + + return ret; + } + + +#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448)) && !defined(WOLFSSL_NO_CLIENT_AUTH) + + typedef struct DcvArgs { + byte* output; /* not allocated */ + word32 sendSz; + word16 sz; + word32 sigSz; + word32 idx; + word32 begin; + byte hashAlgo; + byte sigAlgo; + } DcvArgs; + + static void FreeDcvArgs(WOLFSSL* ssl, void* pArgs) + { + DcvArgs* args = (DcvArgs*)pArgs; + + (void)ssl; + (void)args; + } + + /* handle processing of certificate_verify (15) */ + static int DoCertificateVerify(WOLFSSL* ssl, byte* input, + word32* inOutIdx, word32 size) + { + int ret = 0; + #ifdef WOLFSSL_ASYNC_CRYPT + DcvArgs* args = (DcvArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); + #else + DcvArgs args[1]; + #endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_DO); + WOLFSSL_ENTER("DoCertificateVerify"); + + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_dcv; + } + else + #endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(DcvArgs)); + args->hashAlgo = sha_mac; + args->sigAlgo = anonymous_sa_algo; + args->idx = *inOutIdx; + args->begin = *inOutIdx; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeDcvArgs; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateVerify"); + if (ssl->toInfoOn) + AddLateName("CertificateVerify", &ssl->timeoutInfo); + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + if (IsAtLeastTLSv1_2(ssl)) { + if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + + DecodeSigAlg(&input[args->idx], &args->hashAlgo, + &args->sigAlgo); + args->idx += 2; + } + #ifndef NO_RSA + else if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) + args->sigAlgo = rsa_sa_algo; + #endif + #ifdef HAVE_ECC + else if (ssl->peerEccDsaKeyPresent) + args->sigAlgo = ecc_dsa_sa_algo; + #endif + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) + else if (ssl->peerEd25519KeyPresent) + args->sigAlgo = ed25519_sa_algo; + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ + #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH) + else if (ssl->peerEd448KeyPresent) + args->sigAlgo = ed448_sa_algo; + #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */ + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + + ato16(input + args->idx, &args->sz); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + args->sz > size || + args->sz > ENCRYPT_LEN) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + + WOLFSSL_MSG("Doing ECC peer cert verify"); + + /* make sure a default is defined */ + #if !defined(NO_SHA) + SetDigest(ssl, sha_mac); + #elif !defined(NO_SHA256) + SetDigest(ssl, sha256_mac); + #elif defined(WOLFSSL_SHA384) + SetDigest(ssl, sha384_mac); + #elif defined(WOLFSSL_SHA512) + SetDigest(ssl, sha512_mac); + #else + #error No digest enabled for ECC sig verify + #endif + + if (IsAtLeastTLSv1_2(ssl)) { + if (args->sigAlgo != ecc_dsa_sa_algo) { + WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); + } + + SetDigest(ssl, args->hashAlgo); + } + } + #endif /* HAVE_ECC */ + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + if (IsAtLeastTLSv1_2(ssl) && + args->sigAlgo != ed25519_sa_algo) { + WOLFSSL_MSG( + "Oops, peer sent ED25519 key but not in verify"); + } + } + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ + #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH) + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + if (IsAtLeastTLSv1_2(ssl) && + args->sigAlgo != ed448_sa_algo) { + WOLFSSL_MSG( + "Oops, peer sent ED448 key but not in verify"); + } + } + #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + WOLFSSL_MSG("Doing RSA peer cert verify"); + + ret = RsaVerify(ssl, + input + args->idx, + args->sz, + &args->output, + args->sigAlgo, args->hashAlgo, + ssl->peerRsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerRsaKey + #else + NULL + #endif + ); + if (ret >= 0) { + if (args->sigAlgo == rsa_sa_algo) + args->sendSz = ret; + else { + args->sigSz = ret; + args->sendSz = ssl->buffers.digest.length; + } + ret = 0; + } + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Doing ECC peer cert verify"); + + ret = EccVerify(ssl, + input + args->idx, args->sz, + ssl->buffers.digest.buffer, ssl->buffers.digest.length, + ssl->peerEccDsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEccDsaKey + #else + NULL + #endif + ); + } + #endif /* HAVE_ECC */ + #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH) + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing Ed25519 peer cert verify"); + + ret = Ed25519Verify(ssl, + input + args->idx, args->sz, + ssl->hsHashes->messages, ssl->hsHashes->prevLen, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd25519Key + #else + NULL + #endif + ); + } + #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */ + #if defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH) + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing Ed448 peer cert verify"); + + ret = Ed448Verify(ssl, + input + args->idx, args->sz, + ssl->hsHashes->messages, ssl->hsHashes->prevLen, + ssl->peerEd448Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd448Key + #else + NULL + #endif + ); + } + #endif /* HAVE_ED448 && !NO_ED448_CLIENT_AUTH */ + + #ifdef WOLFSSL_ASYNC_CRYPT + /* handle async pending */ + if (ret == WC_PENDING_E) + goto exit_dcv; + #endif + + /* Check for error */ + if (ret != 0) { + ret = SIG_VERIFY_E; + goto exit_dcv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + if (IsAtLeastTLSv1_2(ssl)) { + #ifdef WC_RSA_PSS + if (args->sigAlgo == rsa_pss_sa_algo) { + SetDigest(ssl, args->hashAlgo); + + #ifdef HAVE_SELFTEST + ret = wc_RsaPSS_CheckPadding( + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + args->output, args->sigSz, + HashAlgoToType(args->hashAlgo)); + #else + ret = wc_RsaPSS_CheckPadding_ex( + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + args->output, args->sigSz, + HashAlgoToType(args->hashAlgo), -1, + mp_count_bits(&ssl->peerRsaKey->n)); + #endif + if (ret != 0) { + ret = SIG_VERIFY_E; + goto exit_dcv; + } + } + else + #endif + { + #ifdef WOLFSSL_SMALL_STACK + byte* encodedSig; + #else + byte encodedSig[MAX_ENCODED_SIG_SZ]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, + ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + #endif + + if (args->sigAlgo != rsa_sa_algo) { + WOLFSSL_MSG("Oops, peer sent RSA key but not " + "in verify"); + } + + SetDigest(ssl, args->hashAlgo); + + args->sigSz = wc_EncodeSignature(encodedSig, + ssl->buffers.digest.buffer, + ssl->buffers.digest.length, + TypeHash(args->hashAlgo)); + + if (args->sendSz != args->sigSz || !args->output || + XMEMCMP(args->output, encodedSig, + min(args->sigSz, MAX_ENCODED_SIG_SZ)) != 0) { + ret = VERIFY_CERT_ERROR; + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(encodedSig, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + #endif + } + } + else { + if (args->sendSz != FINISHED_SZ || !args->output || + XMEMCMP(args->output, + &ssl->hsHashes->certHashes, FINISHED_SZ) != 0) { + ret = VERIFY_CERT_ERROR; + } + } + } + #endif /* !NO_RSA */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + if (IsEncryptionOn(ssl, 0)) { + args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + args->idx += MacSize(ssl); + #endif + } + + ssl->options.havePeerVerify = 1; + + /* Set final index */ + args->idx += args->sz; + *inOutIdx = args->idx; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + + case TLS_ASYNC_END: + { + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + + exit_dcv: + + WOLFSSL_LEAVE("DoCertificateVerify", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_DO); + + #ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + /* Mark message as not received so it can process again */ + ssl->msgsReceived.got_certificate_verify = 0; + + return ret; + } + #endif /* WOLFSSL_ASYNC_CRYPT */ + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_ERROR) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == SIG_VERIFY_E) + SendAlert(ssl, alert_fatal, decrypt_error); + else if (ret != 0) + SendAlert(ssl, alert_fatal, bad_certificate); + #endif + /* Digest is not allocated, so do this to prevent free */ + ssl->buffers.digest.buffer = NULL; + ssl->buffers.digest.length = 0; + + /* Final cleanup */ + FreeDcvArgs(ssl, args); + FreeKeyExchange(ssl); + + return ret; + } + +#endif /* (!NO_RSA || ECC || ED25519 || ED448) && !WOLFSSL_NO_CLIENT_AUTH */ + + /* handle generation of server_hello_done (14) */ + int SendServerHelloDone(WOLFSSL* ssl) + { + byte* output; + int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int ret; + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_DONE_SEND); + WOLFSSL_ENTER("SendServerHelloDone"); + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + + if (IsEncryptionOn(ssl, 1)) + sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, 0, server_hello_done, ssl); + + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = HANDSHAKE_HEADER_SZ; /* build msg adds rec hdr */ + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } else { + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); + #endif + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + } + + #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "ServerHelloDone"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "ServerHelloDone", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + #endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendServerHelloDone", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_DONE_SEND); + + return ret; + } + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef HAVE_SESSION_TICKET + +#define WOLFSSL_TICKET_FIXED_SZ (WOLFSSL_TICKET_NAME_SZ + \ + WOLFSSL_TICKET_IV_SZ + WOLFSSL_TICKET_MAC_SZ + LENGTH_SZ) +#define WOLFSSL_TICKET_ENC_SZ (SESSION_TICKET_LEN - WOLFSSL_TICKET_FIXED_SZ) + + /* our ticket format */ + typedef struct InternalTicket { + ProtocolVersion pv; /* version when ticket created */ + byte suite[SUITE_LEN]; /* cipher suite when created */ + byte msecret[SECRET_LEN]; /* master secret */ + word32 timestamp; /* born on */ + word16 haveEMS; /* have extended master secret */ +#ifdef WOLFSSL_TLS13 + word32 ageAdd; /* Obfuscation of age */ + word16 namedGroup; /* Named group used */ + #ifndef WOLFSSL_TLS13_DRAFT_18 + TicketNonce ticketNonce; /* Ticket nonce */ + #endif + #ifdef WOLFSSL_EARLY_DATA + word32 maxEarlyDataSz; /* Max size of early data */ + #endif +#endif + } InternalTicket; + + /* fit within SESSION_TICKET_LEN */ + typedef struct ExternalTicket { + byte key_name[WOLFSSL_TICKET_NAME_SZ]; /* key context name */ + byte iv[WOLFSSL_TICKET_IV_SZ]; /* this ticket's iv */ + byte enc_len[LENGTH_SZ]; /* encrypted length */ + byte enc_ticket[WOLFSSL_TICKET_ENC_SZ]; /* encrypted internal ticket */ + byte mac[WOLFSSL_TICKET_MAC_SZ]; /* total mac */ + /* !! if add to structure, add to TICKET_FIXED_SZ !! */ + } ExternalTicket; + + /* create a new session ticket, 0 on success */ + int CreateTicket(WOLFSSL* ssl) + { + InternalTicket it; + ExternalTicket* et = (ExternalTicket*)ssl->session.ticket; + int encLen; + int ret; + byte zeros[WOLFSSL_TICKET_MAC_SZ]; /* biggest cmp size */ + + XMEMSET(&it, 0, sizeof(it)); + + /* build internal */ + it.pv.major = ssl->version.major; + it.pv.minor = ssl->version.minor; + + it.suite[0] = ssl->options.cipherSuite0; + it.suite[1] = ssl->options.cipherSuite; + + #ifdef WOLFSSL_EARLY_DATA + it.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + #endif + + if (!ssl->options.tls1_3) { + XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN); + c32toa(LowResTimer(), (byte*)&it.timestamp); + it.haveEMS = ssl->options.haveEMS; + } + else { +#ifdef WOLFSSL_TLS13 + /* Client adds to ticket age to obfuscate. */ + ret = wc_RNG_GenerateBlock(ssl->rng, (byte*)&it.ageAdd, + sizeof(it.ageAdd)); + if (ret != 0) + return BAD_TICKET_ENCRYPT; + ssl->session.ticketAdd = it.ageAdd; + it.namedGroup = ssl->session.namedGroup; + it.timestamp = TimeNowInMilliseconds(); + /* Resumption master secret. */ + XMEMCPY(it.msecret, ssl->session.masterSecret, SECRET_LEN); + #ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(&it.ticketNonce, &ssl->session.ticketNonce, + sizeof(TicketNonce)); + #endif +#endif + } + + /* build external */ + XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket)); + + /* encrypt */ + encLen = WOLFSSL_TICKET_ENC_SZ; /* max size user can use */ + if (ssl->ctx->ticketEncCb == NULL) { + ret = WOLFSSL_TICKET_RET_FATAL; + } + else { + ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, et->mac, 1, + et->enc_ticket, sizeof(InternalTicket), + &encLen, ssl->ctx->ticketEncCtx); + } + if (ret == WOLFSSL_TICKET_RET_OK) { + if (encLen < (int)sizeof(InternalTicket) || + encLen > WOLFSSL_TICKET_ENC_SZ) { + WOLFSSL_MSG("Bad user ticket encrypt size"); + return BAD_TICKET_KEY_CB_SZ; + } + + /* sanity checks on encrypt callback */ + + /* internal ticket can't be the same if encrypted */ + if (XMEMCMP(et->enc_ticket, &it, sizeof(InternalTicket)) == 0) { + WOLFSSL_MSG("User ticket encrypt didn't encrypt"); + return BAD_TICKET_ENCRYPT; + } + + XMEMSET(zeros, 0, sizeof(zeros)); + + /* name */ + if (XMEMCMP(et->key_name, zeros, WOLFSSL_TICKET_NAME_SZ) == 0) { + WOLFSSL_MSG("User ticket encrypt didn't set name"); + return BAD_TICKET_ENCRYPT; + } + + /* iv */ + if (XMEMCMP(et->iv, zeros, WOLFSSL_TICKET_IV_SZ) == 0) { + WOLFSSL_MSG("User ticket encrypt didn't set iv"); + return BAD_TICKET_ENCRYPT; + } + + /* mac */ + if (XMEMCMP(et->mac, zeros, WOLFSSL_TICKET_MAC_SZ) == 0) { + WOLFSSL_MSG("User ticket encrypt didn't set mac"); + return BAD_TICKET_ENCRYPT; + } + + /* set size */ + c16toa((word16)encLen, et->enc_len); + ssl->session.ticketLen = (word16)(encLen + WOLFSSL_TICKET_FIXED_SZ); + if (encLen < WOLFSSL_TICKET_ENC_SZ) { + /* move mac up since whole enc buffer not used */ + XMEMMOVE(et->enc_ticket +encLen, et->mac,WOLFSSL_TICKET_MAC_SZ); + } + } + + return ret; + } + + + /* Parse ticket sent by client, returns callback return value */ + int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len) + { + ExternalTicket* et; + InternalTicket* it; + int ret; + int outLen; + word16 inLen; + + WOLFSSL_START(WC_FUNC_TICKET_DO); + WOLFSSL_ENTER("DoClientTicket"); + + if (len > SESSION_TICKET_LEN || + len < (word32)(sizeof(InternalTicket) + WOLFSSL_TICKET_FIXED_SZ)) { + return BAD_TICKET_MSG_SZ; + } + + et = (ExternalTicket*)input; + it = (InternalTicket*)et->enc_ticket; + + /* decrypt */ + ato16(et->enc_len, &inLen); + if (inLen > (word16)(len - WOLFSSL_TICKET_FIXED_SZ)) { + return BAD_TICKET_MSG_SZ; + } + outLen = inLen; /* may be reduced by user padding */ + + if (ssl->ctx->ticketEncCb == NULL) { + ret = WOLFSSL_TICKET_RET_FATAL; + } + else { + ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, + et->enc_ticket + inLen, 0, + et->enc_ticket, inLen, &outLen, + ssl->ctx->ticketEncCtx); + } + if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) return ret; + if (outLen > (int)inLen || outLen < (int)sizeof(InternalTicket)) { + WOLFSSL_MSG("Bad user ticket decrypt len"); + return BAD_TICKET_KEY_CB_SZ; + } + + /* get master secret */ + if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) { + if (ssl->version.minor < it->pv.minor) { + WOLFSSL_MSG("Ticket has greater version"); + return VERSION_ERROR; + } + else if (ssl->version.minor > it->pv.minor) { + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Ticket has lesser version"); + return VERSION_ERROR; + } + + WOLFSSL_MSG("Downgrading protocol due to ticket"); + + if (it->pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + ssl->version.minor = it->pv.minor; + } + + + if (!IsAtLeastTLSv1_3(ssl->version)) { + XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN); + /* Copy the haveExtendedMasterSecret property from the ticket to + * the saved session, so the property may be checked later. */ + ssl->session.haveEMS = it->haveEMS; + #ifndef NO_RESUME_SUITE_CHECK + ssl->session.cipherSuite0 = it->suite[0]; + ssl->session.cipherSuite = it->suite[1]; + #endif + } + else { +#ifdef WOLFSSL_TLS13 + /* Restore information to renegotiate. */ + ssl->session.ticketSeen = it->timestamp; + ssl->session.ticketAdd = it->ageAdd; + ssl->session.cipherSuite0 = it->suite[0]; + ssl->session.cipherSuite = it->suite[1]; + #ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = it->maxEarlyDataSz; + #endif + /* Resumption master secret. */ + XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN); + #ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(&ssl->session.ticketNonce, &it->ticketNonce, + sizeof(TicketNonce)); + #endif + ssl->session.namedGroup = it->namedGroup; +#endif + } + } + + WOLFSSL_LEAVE("DoClientTicket", ret); + WOLFSSL_END(WC_FUNC_TICKET_DO); + + return ret; + } + + + /* send Session Ticket */ + int SendTicket(WOLFSSL* ssl) + { + byte* output; + int ret; + int sendSz; + word32 length = SESSION_HINT_SZ + LENGTH_SZ; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + WOLFSSL_START(WC_FUNC_TICKET_SEND); + WOLFSSL_ENTER("SendTicket"); + + if (ssl->options.createTicket) { + ret = CreateTicket(ssl); + if (ret != 0) return ret; + } + + length += ssl->session.ticketLen; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + if (!ssl->options.dtls) { + if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) + sendSz += MAX_MSG_EXTRA; + } + else { + #ifdef WOLFSSL_DTLS + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + } + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, session_ticket, ssl); + + /* hint */ + c32toa(ssl->ctx->ticketHint, output + idx); + idx += SESSION_HINT_SZ; + + /* length */ + c16toa(ssl->session.ticketLen, output + idx); + idx += LENGTH_SZ; + + /* ticket */ + XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen); + idx += ssl->session.ticketLen; + + if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) { + byte* input; + int inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */ + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 1, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } + else { + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) + return ret; + + DtlsSEQIncrement(ssl, CUR_ORDER); + } + #endif + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + } + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTicket", ret); + WOLFSSL_END(WC_FUNC_TICKET_SEND); + + return ret; + } + +#endif /* HAVE_SESSION_TICKET */ + +#ifndef WOLFSSL_NO_TLS12 + +#if defined(HAVE_SECURE_RENEGOTIATION) && \ + defined(HAVE_SERVER_RENEGOTIATION_INFO) && \ + !defined(WOLFSSL_NO_SERVER) + + /* handle generation of server's hello_request (0) */ + int SendHelloRequest(WOLFSSL* ssl) + { + byte* output; + int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int ret; + + WOLFSSL_START(WC_FUNC_HELLO_REQUEST_SEND); + WOLFSSL_ENTER("SendHelloRequest"); + + if (IsEncryptionOn(ssl, 1)) + sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, 0, hello_request, ssl); + + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = HANDSHAKE_HEADER_SZ; /* build msg adds rec hdr */ + + input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (input == NULL) + return MEMORY_E; + + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 0, 0, 0); + XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + + if (sendSz < 0) + return sendSz; + } + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendHelloRequest", ret); + WOLFSSL_END(WC_FUNC_HELLO_REQUEST_SEND); + + return ret; + } + +#endif /* HAVE_SECURE_RENEGOTIATION && HAVE_SERVER_RENEGOTIATION_INFO */ + +#ifdef WOLFSSL_DTLS + /* handle generation of DTLS hello_verify_request (3) */ + static int SendHelloVerifyRequest(WOLFSSL* ssl, + const byte* cookie, byte cookieSz) + { + byte* output; + int length = VERSION_SZ + ENUM_LEN + cookieSz; + int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; + int sendSz = length + idx; + int ret; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Hello Verify Request should use the same sequence number as the + * Client Hello. */ + ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi; + ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo; + AddHeaders(output, length, hello_verify_request, ssl); + +#ifdef OPENSSL_EXTRA + output[idx++] = DTLS_MAJOR; + output[idx++] = DTLS_MINOR; +#else + output[idx++] = ssl->version.major; + output[idx++] = ssl->version.minor; +#endif + + output[idx++] = cookieSz; + if (cookie == NULL || cookieSz == 0) + return COOKIE_ERROR; + + XMEMCPY(output + idx, cookie, cookieSz); + +#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) + if (ssl->hsInfoOn) + AddPacketName(ssl, "HelloVerifyRequest"); + if (ssl->toInfoOn) + AddPacketInfo(ssl, "HelloVerifyRequest", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } +#endif /* WOLFSSL_DTLS */ + + typedef struct DckeArgs { + byte* output; /* not allocated */ + word32 length; + word32 idx; + word32 begin; + word32 sigSz; + #ifndef NO_RSA + int lastErr; + #endif + } DckeArgs; + + static void FreeDckeArgs(WOLFSSL* ssl, void* pArgs) + { + DckeArgs* args = (DckeArgs*)pArgs; + + (void)ssl; + (void)args; + } + + /* handle processing client_key_exchange (16) */ + static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 size) + { + int ret; + #ifdef WOLFSSL_ASYNC_CRYPT + DckeArgs* args = (DckeArgs*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); + #else + DckeArgs args[1]; + #endif + + (void)size; + (void)input; + + WOLFSSL_START(WC_FUNC_CLIENT_KEY_EXCHANGE_DO); + WOLFSSL_ENTER("DoClientKeyExchange"); + + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_dcke; + } + else + #endif /* WOLFSSL_ASYNC_CRYPT */ + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(DckeArgs)); + args->idx = *inOutIdx; + args->begin = *inOutIdx; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeDckeArgs; + #endif + } + + /* Do Client Key Exchange State Machine */ + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + /* Sanity checks */ + if (ssl->options.side != WOLFSSL_SERVER_END) { + WOLFSSL_MSG("Client received client keyexchange, attack?"); + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + ERROR_OUT(WOLFSSL_FATAL_ERROR, exit_dcke); + } + + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Client sending keyexchange at wrong time"); + SendAlert(ssl, alert_fatal, unexpected_message); + ERROR_OUT(OUT_OF_ORDER_E, exit_dcke); + } + + #ifndef NO_CERTS + if (ssl->options.verifyPeer && ssl->options.failNoCert) { + if (!ssl->options.havePeerCert) { + WOLFSSL_MSG("client didn't present peer cert"); + ERROR_OUT(NO_PEER_CERT, exit_dcke); + } + } + + if (ssl->options.verifyPeer && ssl->options.failNoCertxPSK) { + if (!ssl->options.havePeerCert && + !ssl->options.usingPSK_cipher) { + WOLFSSL_MSG("client didn't present peer cert"); + return NO_PEER_CERT; + } + } + #endif /* !NO_CERTS */ + + #if defined(WOLFSSL_CALLBACKS) + if (ssl->hsInfoOn) { + AddPacketName(ssl, "ClientKeyExchange"); + } + if (ssl->toInfoOn) { + AddLateName("ClientKeyExchange", &ssl->timeoutInfo); + } + #endif + + if (ssl->arrays->preMasterSecret == NULL) { + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, + ssl->heap, DYNAMIC_TYPE_SECRET); + if (ssl->arrays->preMasterSecret == NULL) { + ERROR_OUT(MEMORY_E, exit_dcke); + } + XMEMSET(ssl->arrays->preMasterSecret, 0, ENCRYPT_LEN); + } + + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + /* sanity check that PSK server callback has been set */ + if (ssl->options.server_psk_cb == NULL) { + WOLFSSL_MSG("No server PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + break; + } + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + /* make sure private key exists */ + if (ssl->buffers.key == NULL || + ssl->buffers.key->buffer == NULL) { + ERROR_OUT(NO_PRIVATE_KEY, exit_dcke); + } + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #ifndef NO_DH + case diffie_hellman_kea: + { + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + /* sanity check that PSK server callback has been set */ + if (ssl->options.server_psk_cb == NULL) { + WOLFSSL_MSG("No server PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + /* sanity check that PSK server callback has been set */ + if (ssl->options.server_psk_cb == NULL) { + WOLFSSL_MSG("No server PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + default: + WOLFSSL_MSG("Bad kea type"); + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + word16 keySz; + + ssl->buffers.keyType = rsa_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_dcke; + } + args->length = (word32)keySz; + ssl->arrays->preMasterSz = SECRET_LEN; + + if (ssl->options.tls) { + word16 check; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &check); + args->idx += OPAQUE16_LEN; + + if ((word32)check != args->length) { + WOLFSSL_MSG("RSA explicit size doesn't match"); + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, bad_record_mac); + #endif + ERROR_OUT(RSA_PRIVATE_ERROR, exit_dcke); + } + } + + if ((args->idx - args->begin) + args->length > size) { + WOLFSSL_MSG("RSA message too big"); + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + /* pre-load PreMasterSecret with RNG data */ + ret = wc_RNG_GenerateBlock(ssl->rng, + &ssl->arrays->preMasterSecret[VERSION_SZ], + SECRET_LEN - VERSION_SZ); + if (ret != 0) { + goto exit_dcke; + } + + args->output = NULL; + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + word16 ci_sz; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &ci_sz); + args->idx += OPAQUE16_LEN; + + if (ci_sz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_dcke); + } + + if ((args->idx - args->begin) + ci_sz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + XMEMCPY(ssl->arrays->client_identity, + input + args->idx, ci_sz); + args->idx += ci_sz; + + ssl->arrays->client_identity[ci_sz] = '\0'; /* null term */ + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMSET(pms, 0, ssl->arrays->psk_keySz); + pms += ssl->arrays->psk_keySz; + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz = + (ssl->arrays->psk_keySz * 2) + (OPAQUE16_LEN * 2); + break; + } + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + word16 cipherLen; + word16 plainLen = ENCRYPT_LEN; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &cipherLen); + args->idx += OPAQUE16_LEN; + + if (cipherLen > MAX_NTRU_ENCRYPT_SZ) { + ERROR_OUT(NTRU_KEY_ERROR, exit_dcke); + } + + if ((args->idx - args->begin) + cipherLen > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + if (NTRU_OK != ntru_crypto_ntru_decrypt( + (word16) ssl->buffers.key->length, + ssl->buffers.key->buffer, cipherLen, + input + args->idx, &plainLen, + ssl->arrays->preMasterSecret)) { + ERROR_OUT(NTRU_DECRYPT_ERROR, exit_dcke); + } + + if (plainLen != SECRET_LEN) { + ERROR_OUT(NTRU_DECRYPT_ERROR, exit_dcke); + } + + args->idx += cipherLen; + ssl->arrays->preMasterSz = plainLen; + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + #ifdef HAVE_ECC + ecc_key* private_key = ssl->eccTempKey; + + /* handle static private key */ + if (ssl->specs.static_ecdh && + ssl->ecdhCurveOID != ECC_X25519_OID && + ssl->ecdhCurveOID != ECC_X448_OID) { + word16 keySz; + + ssl->buffers.keyType = ecc_dsa_sa_algo; + ret = DecodePrivateKey(ssl, &keySz); + if (ret != 0) { + goto exit_dcke; + } + private_key = (ecc_key*)ssl->hsKey; + } + #endif + + /* import peer ECC key */ + if ((args->idx - args->begin) + OPAQUE8_LEN > size) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, decode_error); + #endif + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + args->length = input[args->idx++]; + + if ((args->idx - args->begin) + args->length > size) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, decode_error); + #endif + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + if (ssl->peerX25519Key == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerX25519KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if ((ret = wc_curve25519_check_public( + input + args->idx, args->length, + EC25519_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, + illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + if (wc_curve25519_import_public_ex( + input + args->idx, args->length, + ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN)) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, illegal_parameter); + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->arrays->preMasterSz = CURVE25519_KEYSIZE; + + ssl->peerX25519KeyPresent = 1; + + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X448SharedSecretCb != NULL) { + break; + } + #endif + if (ssl->peerX448Key == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerX448KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE448, + ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if ((ret = wc_curve448_check_public( + input + args->idx, args->length, + EC448_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, + illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + if (wc_curve448_import_public_ex( + input + args->idx, args->length, + ssl->peerX448Key, + EC448_LITTLE_ENDIAN)) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, illegal_parameter); + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->arrays->preMasterSz = CURVE448_KEY_SIZE; + + ssl->peerX448KeyPresent = 1; + + break; + } + #endif + #ifdef HAVE_ECC + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->EccSharedSecretCb != NULL) { + break; + } + #endif + + if (!ssl->specs.static_ecdh && + ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG("Ecc ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + + if (ssl->peerEccKey == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if (wc_ecc_import_x963_ex(input + args->idx, + args->length, ssl->peerEccKey, + private_key->dp->id)) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, illegal_parameter); + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->arrays->preMasterSz = private_key->dp->size; + + ssl->peerEccKeyPresent = 1; + #endif /* HAVE_ECC */ + + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #ifndef NO_DH + case diffie_hellman_kea: + { + word16 clientPubSz; + + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &clientPubSz); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + clientPubSz > size) { + #ifdef WOLFSSL_EXTRA_ALERTS + SendAlert(ssl, alert_fatal, decode_error); + #endif + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + args->sigSz = clientPubSz; + + ret = AllocKey(ssl, DYNAMIC_TYPE_DH, + (void**)&ssl->buffers.serverDH_Key); + if (ret != 0) { + goto exit_dcke; + } + + ret = wc_DhSetKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + + /* set the max agree result size */ + ssl->arrays->preMasterSz = ENCRYPT_LEN; + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + word16 clientSz; + + /* Read in the PSK hint */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &clientSz); + args->idx += OPAQUE16_LEN; + if (clientSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_dcke); + } + + if ((args->idx - args->begin) + clientSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + XMEMCPY(ssl->arrays->client_identity, input + args->idx, + clientSz); + args->idx += clientSz; + ssl->arrays->client_identity[clientSz] = '\0'; /* null term */ + + /* Read in the DHE business */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &clientSz); + args->idx += OPAQUE16_LEN; + + if ((args->idx - args->begin) + clientSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + args->sigSz = clientSz; + + ret = AllocKey(ssl, DYNAMIC_TYPE_DH, + (void**)&ssl->buffers.serverDH_Key); + if (ret != 0) { + goto exit_dcke; + } + + ret = wc_DhSetKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + word16 clientSz; + + /* Read in the PSK hint */ + if ((args->idx - args->begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + args->idx, &clientSz); + args->idx += OPAQUE16_LEN; + if (clientSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_dcke); + } + if ((args->idx - args->begin) + clientSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + XMEMCPY(ssl->arrays->client_identity, + input + args->idx, clientSz); + args->idx += clientSz; + ssl->arrays->client_identity[clientSz] = '\0'; /* null term */ + + /* import peer ECC key */ + if ((args->idx - args->begin) + OPAQUE8_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + args->length = input[args->idx++]; + + if ((args->idx - args->begin) + args->length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + args->sigSz = ENCRYPT_LEN - OPAQUE16_LEN; + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X25519SharedSecretCb != NULL) { + break; + } + #endif + + if (ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG( + "X25519 ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + + if (ssl->peerX25519Key == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerX25519KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519, + ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if ((ret = wc_curve25519_check_public( + input + args->idx, args->length, + EC25519_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, + illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + if (wc_curve25519_import_public_ex( + input + args->idx, args->length, + ssl->peerX25519Key, + EC25519_LITTLE_ENDIAN)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->peerX25519KeyPresent = 1; + + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->X448SharedSecretCb != NULL) { + break; + } + #endif + + if (ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG( + "X448 ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + + if (ssl->peerX448Key == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + if (ret != 0) { + goto exit_dcke; + } + } else if (ssl->peerX448KeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE448, + ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + + if ((ret = wc_curve448_check_public( + input + args->idx, args->length, + EC448_LITTLE_ENDIAN)) != 0) { + #ifdef WOLFSSL_EXTRA_ALERTS + if (ret == BUFFER_E) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == ECC_OUT_OF_RANGE_E) + SendAlert(ssl, alert_fatal, bad_record_mac); + else { + SendAlert(ssl, alert_fatal, + illegal_parameter); + } + #endif + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + if (wc_curve448_import_public_ex( + input + args->idx, args->length, + ssl->peerX448Key, + EC448_LITTLE_ENDIAN)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->peerX448KeyPresent = 1; + + break; + } + #endif + #ifdef HAVE_PK_CALLBACKS + /* if callback then use it for shared secret */ + if (ssl->ctx->EccSharedSecretCb != NULL) { + break; + } + #endif + + if (ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG("Ecc ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + + if (ssl->peerEccKey == NULL) { + /* alloc/init on demand */ + ret = AllocKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + if (ret != 0) { + goto exit_dcke; + } + } + else if (ssl->peerEccKeyPresent) { + ret = ReuseKey(ssl, DYNAMIC_TYPE_ECC, + ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + if (ret != 0) { + goto exit_dcke; + } + } + if (wc_ecc_import_x963_ex(input + args->idx, + args->length, ssl->peerEccKey, + ssl->eccTempKey->dp->id)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + ssl->peerEccKeyPresent = 1; + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + default: + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + RsaKey* key = (RsaKey*)ssl->hsKey; + + ret = RsaDec(ssl, + input + args->idx, + args->length, + &args->output, + &args->sigSz, + key, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + + /* Errors that can occur here that should be + * indistinguishable: + * RSA_BUFFER_E, RSA_PAD_E and RSA_PRIVATE_ERROR + */ + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + goto exit_dcke; + #endif + if (ret == BAD_FUNC_ARG) + goto exit_dcke; + + args->lastErr = ret - (SECRET_LEN - args->sigSz); + ret = 0; + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + break; + } + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + void* private_key = ssl->eccTempKey; + (void)private_key; + + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)private_key, + ssl->peerX25519Key, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_SERVER_END + ); + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + ret = X448SharedSecret(ssl, + (curve448_key*)private_key, + ssl->peerX448Key, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_SERVER_END + ); + break; + } + #endif + #ifdef HAVE_ECC + if (ssl->specs.static_ecdh) { + private_key = ssl->hsKey; + } + + /* Generate shared secret */ + ret = EccSharedSecret(ssl, + (ecc_key*)private_key, ssl->peerEccKey, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + WOLFSSL_SERVER_END + ); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + } + #endif + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #ifndef NO_DH + case diffie_hellman_kea: + { + ret = DhAgree(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_Priv.buffer, + ssl->buffers.serverDH_Priv.length, + input + args->idx, + (word16)args->sigSz, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz); + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + ret = DhAgree(ssl, ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_Priv.buffer, + ssl->buffers.serverDH_Priv.length, + input + args->idx, + (word16)args->sigSz, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->arrays->preMasterSz); + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + #ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID) { + ret = X25519SharedSecret(ssl, + (curve25519_key*)ssl->eccTempKey, + ssl->peerX25519Key, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &args->sigSz, + WOLFSSL_SERVER_END + ); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, + (void**)&ssl->peerX25519Key); + ssl->peerX25519KeyPresent = 0; + } + break; + } + #endif + #ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID) { + ret = X448SharedSecret(ssl, + (curve448_key*)ssl->eccTempKey, + ssl->peerX448Key, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &args->sigSz, + WOLFSSL_SERVER_END + ); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret != WC_PENDING_E) + #endif + { + FreeKey(ssl, DYNAMIC_TYPE_CURVE448, + (void**)&ssl->peerX448Key); + ssl->peerX448KeyPresent = 0; + } + break; + } + #endif + /* Generate shared secret */ + ret = EccSharedSecret(ssl, + ssl->eccTempKey, ssl->peerEccKey, + input + args->idx, &args->length, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &args->sigSz, + WOLFSSL_SERVER_END + ); + if (!ssl->specs.static_ecdh + #ifdef WOLFSSL_ASYNC_CRYPT + && ret != WC_PENDING_E + #endif + ) { + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + } + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + default: + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + byte mask; + int i; + + /* Add the signature length to idx */ + args->idx += args->length; + + #ifdef DEBUG_WOLFSSL + /* check version (debug warning message only) */ + if (args->output != NULL) { + if (args->output[0] != ssl->chVersion.major || + args->output[1] != ssl->chVersion.minor) { + WOLFSSL_MSG("preMasterSecret version mismatch"); + } + } + #endif + + /* RFC5246 7.4.7.1: + * Treat incorrectly formatted message blocks and/or + * mismatched version numbers in a manner + * indistinguishable from correctly formatted RSA blocks + */ + + ret = args->lastErr; + args->lastErr = 0; /* reset */ + /* On error 'ret' will be negative - top bit set */ + mask = ((unsigned int)ret >> + ((sizeof(ret) * 8) - 1)) - 1; + + /* build PreMasterSecret */ + ssl->arrays->preMasterSecret[0] = ssl->chVersion.major; + ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor; + + if (args->output != NULL) { + /* Use random secret on error */ + for (i = VERSION_SZ; i < SECRET_LEN; i++) { + ssl->arrays->preMasterSecret[i] = + ctMaskSel(mask, args->output[i], + ssl->arrays->preMasterSecret[i]); + } + } + /* preMasterSecret has RNG and version set + * return proper length and ignore error + * error will be caught as decryption error + */ + args->sigSz = SECRET_LEN; + ret = 0; + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + break; + } + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + break; + } + #endif /* HAVE_NTRU */ + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + case ecc_diffie_hellman_kea: + { + /* skip past the imported peer key */ + args->idx += args->length; + break; + } + #endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + #ifndef NO_DH + case diffie_hellman_kea: + { + args->idx += (word16)args->sigSz; + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + word16 clientSz = (word16)args->sigSz; + + args->idx += clientSz; + c16toa((word16)ssl->arrays->preMasterSz, pms); + ssl->arrays->preMasterSz += OPAQUE16_LEN; + pms += ssl->arrays->preMasterSz; + + /* Use the PSK hint to look up the PSK and add it to the + * preMasterSecret here. */ + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, + ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz += ssl->arrays->psk_keySz + + OPAQUE16_LEN; + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + word16 clientSz = (word16)args->sigSz; + + /* skip past the imported peer key */ + args->idx += args->length; + + /* Add preMasterSecret */ + c16toa(clientSz, pms); + ssl->arrays->preMasterSz = OPAQUE16_LEN + clientSz; + pms += ssl->arrays->preMasterSz; + + /* Use the PSK hint to look up the PSK and add it to the + * preMasterSecret here. */ + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz += + ssl->arrays->psk_keySz + OPAQUE16_LEN; + break; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && !NO_PSK */ + default: + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + if (IsEncryptionOn(ssl, 0)) { + args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + args->idx += MacSize(ssl); + #endif + } + + #ifdef HAVE_QSH + word16 name; + + if (ssl->options.haveQSH) { + /* extension name */ + ato16(input + args->idx, &name); + args->idx += OPAQUE16_LEN; + + if (name == TLSX_QUANTUM_SAFE_HYBRID) { + int qshSz; + /* if qshSz is larger than 0 it is the + length of buffer used */ + if ((qshSz = TLSX_QSHCipher_Parse(ssl, + input + args->idx, + size - args->idx + args->begin, 1)) < 0) { + ERROR_OUT(qshSz, exit_dcke); + } + args->idx += qshSz; + } + else { + /* unknown extension sent client ignored handshake */ + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + } + #endif /* HAVE_QSH */ + ret = MakeMasterSecret(ssl); + + /* Check for error */ + if (ret != 0) { + goto exit_dcke; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + /* Set final index */ + *inOutIdx = args->idx; + + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + #ifndef NO_CERTS + if (ssl->options.verifyPeer) { + ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes); + } + #endif + break; + } /* TLS_ASYNC_END */ + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + + exit_dcke: + + WOLFSSL_LEAVE("DoClientKeyExchange", ret); + WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_DO); + + #ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + /* Mark message as not received so it can process again */ + ssl->msgsReceived.got_client_key_exchange = 0; + + return ret; + } + #endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Cleanup PMS */ + if (ssl->arrays->preMasterSecret != NULL) { + ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); + } + ssl->arrays->preMasterSz = 0; + + /* Final cleanup */ + FreeDckeArgs(ssl, args); + FreeKeyExchange(ssl); + + return ret; + } + +#endif /* !WOLFSSL_NO_TLS12 */ + +#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) + int SNI_Callback(WOLFSSL* ssl) + { + /* Stunnel supports a custom sni callback to switch an SSL's ctx + * when SNI is received. Call it now if exists */ + if(ssl && ssl->ctx && ssl->ctx->sniRecvCb) { + WOLFSSL_MSG("Calling custom sni callback"); + if(ssl->ctx->sniRecvCb(ssl, NULL, ssl->ctx->sniRecvCbArg) + == alert_fatal) { + WOLFSSL_MSG("Error in custom sni callback. Fatal alert"); + SendAlert(ssl, alert_fatal, unrecognized_name); + return FATAL_ERROR; + } + } + return 0; + } +#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#endif /* NO_WOLFSSL_SERVER */ + + +#ifdef WOLFSSL_ASYNC_CRYPT +int wolfSSL_AsyncPop(WOLFSSL* ssl, byte* state) +{ + int ret = 0; + WC_ASYNC_DEV* asyncDev; + WOLF_EVENT* event; + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + /* check for pending async */ + asyncDev = ssl->async.dev; + if (asyncDev) { + /* grab event pointer */ + event = &asyncDev->event; + + ret = wolfAsync_EventPop(event, WOLF_EVENT_TYPE_ASYNC_WOLFSSL); + if (ret != WC_NOT_PENDING_E && ret != WC_PENDING_E) { + + /* advance key share state if doesn't need called again */ + if (state && (asyncDev->event.flags & WC_ASYNC_FLAG_CALL_AGAIN) == 0) { + (*state)++; + } + + /* clear event */ + XMEMSET(&asyncDev->event, 0, sizeof(WOLF_EVENT)); + + /* clear async dev */ + ssl->async.dev = NULL; + } + } + else { + ret = WC_NOT_PENDING_E; + } + + WOLFSSL_LEAVE("wolfSSL_AsyncPop", ret); + + return ret; +} + +int wolfSSL_AsyncInit(WOLFSSL* ssl, WC_ASYNC_DEV* asyncDev, word32 flags) +{ + int ret; + WOLF_EVENT* event; + + if (ssl == NULL || asyncDev == NULL) { + return BAD_FUNC_ARG; + } + + /* grab event pointer */ + event = &asyncDev->event; + + /* init event */ + ret = wolfAsync_EventInit(event, WOLF_EVENT_TYPE_ASYNC_WOLFSSL, ssl, flags); + + WOLFSSL_LEAVE("wolfSSL_AsyncInit", ret); + + return ret; +} + +int wolfSSL_AsyncPush(WOLFSSL* ssl, WC_ASYNC_DEV* asyncDev) +{ + int ret; + WOLF_EVENT* event; + + if (ssl == NULL || asyncDev == NULL) { + return BAD_FUNC_ARG; + } + + /* grab event pointer */ + event = &asyncDev->event; + + /* store reference to active async operation */ + ssl->async.dev = asyncDev; + + /* place event into queue */ + ret = wolfAsync_EventQueuePush(&ssl->ctx->event_queue, event); + + /* success means return WC_PENDING_E */ + if (ret == 0) { + ret = WC_PENDING_E; + } + + WOLFSSL_LEAVE("wolfSSL_AsyncPush", ret); + + return ret; +} + +#endif /* WOLFSSL_ASYNC_CRYPT */ + + +/* return the max record size */ +int wolfSSL_GetMaxRecordSize(WOLFSSL* ssl, int maxFragment) +{ + (void) ssl; /* Avoid compiler warnings */ + + if (maxFragment > MAX_RECORD_SIZE) { + maxFragment = MAX_RECORD_SIZE; + } + +#ifdef HAVE_MAX_FRAGMENT + if ((ssl->max_fragment != 0) && ((word16)maxFragment > ssl->max_fragment)) { + maxFragment = ssl->max_fragment; + } +#endif /* HAVE_MAX_FRAGMENT */ +#ifdef WOLFSSL_DTLS + if ((ssl->options.dtls) && (maxFragment > MAX_UDP_SIZE)) { + maxFragment = MAX_UDP_SIZE; + } +#endif + + return maxFragment; +} + + +#undef ERROR_OUT + +#endif /* WOLFCRYPT_ONLY */ diff --git a/client/wolfssl/src/keys.c b/client/wolfssl/src/keys.c new file mode 100644 index 0000000..55b2d9b --- /dev/null +++ b/client/wolfssl/src/keys.c @@ -0,0 +1,3607 @@ +/* keys.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +/* Name change compatibility layer no longer needs to be included here */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY + +#include +#include +#if defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST) + #ifndef NO_STDIO_FILESYSTEM + #include + #endif +#endif + +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + int tsip_useable(const WOLFSSL *ssl); +#endif +int SetCipherSpecs(WOLFSSL* ssl) +{ +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* server side verified before SetCipherSpecs call */ + if (VerifyClientSuite(ssl) != 1) { + WOLFSSL_MSG("SetCipherSpecs() client has an unusable suite"); + return UNSUPPORTED_SUITE; + } + } +#endif /* NO_WOLFSSL_CLIENT */ + + /* Chacha extensions, 0xcc */ + if (ssl->options.cipherSuite0 == CHACHA_BYTE) { + + switch (ssl->options.cipherSuite) { +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 1; /* use old poly1305 padding */ + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 1; /* use old poly1305 padding */ + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 1; /* use old poly1305 padding */ + + break; +#endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ + + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 + case TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + + ssl->options.oldPoly = 0; /* use recent padding RFC */ + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 + case TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecdhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + + ssl->options.oldPoly = 0; /* use recent padding RFC */ + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 + case TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + + ssl->options.oldPoly = 0; /* use recent padding RFC */ + ssl->options.usingPSK_cipher = 1; + break; +#endif + default: + WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs ChaCha"); + return UNSUPPORTED_SUITE; + } + } + + /* ECC extensions, AES-CCM or TLS 1.3 Integrity-only */ + if (ssl->options.cipherSuite0 == ECC_BYTE) { + + switch (ssl->options.cipherSuite) { + +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + case TLS_ECDHE_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256 + case TLS_ECDHE_PSK_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecdhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecdhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ + +#if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && defined(HAVE_ED25519)) \ + || (defined(HAVE_CURVE448) && defined(HAVE_ED448)) + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA + case TLS_ECDHE_ECDSA_WITH_NULL_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + break; +#endif + +#endif /* HAVE_ECC || (CURVE25519 && ED25519) || (CURVE448 && ED448) */ + +#if defined(HAVE_ECC) + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + case TLS_ECDH_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#endif /* HAVE_ECC */ + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + case TLS_RSA_WITH_AES_128_CCM_8 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + case TLS_RSA_WITH_AES_256_CCM_8 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + case TLS_PSK_WITH_AES_128_CCM_8 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + case TLS_PSK_WITH_AES_256_CCM_8 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM + case TLS_PSK_WITH_AES_128_CCM : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM + case TLS_PSK_WITH_AES_256_CCM : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM + case TLS_DHE_PSK_WITH_AES_128_CCM : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM + case TLS_DHE_PSK_WITH_AES_256_CCM : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#if defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) + #ifdef BUILD_TLS_SHA256_SHA256 + case TLS_SHA256_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = WC_SHA256_DIGEST_SIZE / 2; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HMAC_NONCE_SZ; + ssl->specs.aead_mac_size = WC_SHA256_DIGEST_SIZE; + + break; + #endif + + #ifdef BUILD_TLS_SHA384_SHA384 + case TLS_SHA384_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = WC_SHA384_DIGEST_SIZE / 2; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HMAC_NONCE_SZ; + ssl->specs.aead_mac_size = WC_SHA384_DIGEST_SIZE; + + break; + #endif +#endif + + default: + WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs ECC"); + return UNSUPPORTED_SUITE; + } /* switch */ + } /* if */ + + /* TLSi v1.3 cipher suites, 0x13 */ + if (ssl->options.cipherSuite0 == TLS13_BYTE) { + switch (ssl->options.cipherSuite) { + +#ifdef WOLFSSL_TLS13 + #ifdef BUILD_TLS_AES_128_GCM_SHA256 + case TLS_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; + #endif + + #ifdef BUILD_TLS_AES_256_GCM_SHA384 + case TLS_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; + #endif + + #ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + case TLS_CHACHA20_POLY1305_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ + + break; + #endif + + #ifdef BUILD_TLS_AES_128_CCM_SHA256 + case TLS_AES_128_CCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + break; + #endif + + #ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + case TLS_AES_128_CCM_8_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; + #endif +#endif /* WOLFSSL_TLS13 */ + } + } + + if (ssl->options.cipherSuite0 != ECC_BYTE && + ssl->options.cipherSuite0 != CHACHA_BYTE && + ssl->options.cipherSuite0 != TLS13_BYTE) { /* normal suites */ + switch (ssl->options.cipherSuite) { + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + case SSL_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + case TLS_NTRU_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + case SSL_RSA_WITH_RC4_128_MD5 : + ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + case SSL_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + case TLS_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 + case TLS_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_MD5 + case TLS_RSA_WITH_NULL_MD5 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + case TLS_RSA_WITH_NULL_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 + case TLS_RSA_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + case TLS_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 + case TLS_RSA_WITH_AES_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256 + case TLS_PSK_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384 + case TLS_PSK_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384 + case TLS_DH_anon_WITH_AES_256_GCM_SHA384: + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + ssl->options.usingAnon_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 + case TLS_PSK_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384 + case TLS_PSK_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + case TLS_PSK_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + case TLS_PSK_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 + case TLS_PSK_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384 + case TLS_PSK_WITH_NULL_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + case TLS_PSK_WITH_NULL_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256 + case TLS_DHE_PSK_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384 + case TLS_DHE_PSK_WITH_NULL_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = dhe_psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + case TLS_RSA_WITH_HC_128_MD5 : + ssl->specs.bulk_cipher_algorithm = wolfssl_hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + case TLS_RSA_WITH_HC_128_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + case TLS_RSA_WITH_RABBIT_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_rabbit; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RABBIT_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = RABBIT_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA + case TLS_DH_anon_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingAnon_cipher = 1; + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + case SSL_RSA_WITH_IDEA_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_idea; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = WC_SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = IDEA_KEY_SIZE; + ssl->specs.block_size = IDEA_BLOCK_SIZE; + ssl->specs.iv_size = IDEA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_WDM_WITH_NULL_SHA256 + case WDM_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = no_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + + break; +#endif + + default: + WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs"); + return UNSUPPORTED_SUITE; + } /* switch */ + } /* if ECC / Normal suites else */ + + /* set TLS if it hasn't been turned off */ + if (ssl->version.major == 3 && ssl->version.minor >= 1) { +#ifndef NO_TLS + ssl->options.tls = 1; + #if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) + ssl->hmac = TLS_hmac; + #endif + if (ssl->version.minor >= 2) { + ssl->options.tls1_1 = 1; + if (ssl->version.minor >= 4) + ssl->options.tls1_3 = 1; + } +#endif + } + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (IsAtLeastTLSv1_3(ssl->version) || ssl->specs.cipher_type != block) + ssl->options.encThenMac = 0; +#endif + +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.dtls) + ssl->hmac = TLS_hmac; +#endif + + return 0; +} + + +enum KeyStuff { + MASTER_ROUNDS = 3, + PREFIX = 3, /* up to three letters for master prefix */ + KEY_PREFIX = 9 /* up to 9 prefix letters for key rounds */ + + +}; + +#ifndef NO_OLD_TLS +/* true or false, zero for error */ +static int SetPrefix(byte* sha_input, int idx) +{ + switch (idx) { + case 0: + XMEMCPY(sha_input, "A", 1); + break; + case 1: + XMEMCPY(sha_input, "BB", 2); + break; + case 2: + XMEMCPY(sha_input, "CCC", 3); + break; + case 3: + XMEMCPY(sha_input, "DDDD", 4); + break; + case 4: + XMEMCPY(sha_input, "EEEEE", 5); + break; + case 5: + XMEMCPY(sha_input, "FFFFFF", 6); + break; + case 6: + XMEMCPY(sha_input, "GGGGGGG", 7); + break; + case 7: + XMEMCPY(sha_input, "HHHHHHHH", 8); + break; + case 8: + XMEMCPY(sha_input, "IIIIIIIII", 9); + break; + default: + WOLFSSL_MSG("Set Prefix error, bad input"); + return 0; + } + return 1; +} +#endif + + +static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, + int side, void* heap, int devId, WC_RNG* rng, int tls13) +{ + (void)rng; + (void)tls13; + +#ifdef BUILD_ARC4 + if (specs->bulk_cipher_algorithm == wolfssl_rc4) { + word32 sz = specs->key_size; + if (enc && enc->arc4 == NULL) { + enc->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER); + if (enc->arc4 == NULL) + return MEMORY_E; + } + if (dec && dec->arc4 == NULL) { + dec->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER); + if (dec->arc4 == NULL) + return MEMORY_E; + } + + if (enc) { + if (wc_Arc4Init(enc->arc4, heap, devId) != 0) { + WOLFSSL_MSG("Arc4Init failed in SetKeys"); + return ASYNC_INIT_E; + } + } + if (dec) { + if (wc_Arc4Init(dec->arc4, heap, devId) != 0) { + WOLFSSL_MSG("Arc4Init failed in SetKeys"); + return ASYNC_INIT_E; + } + } + + if (side == WOLFSSL_CLIENT_END) { + if (enc) + wc_Arc4SetKey(enc->arc4, keys->client_write_key, sz); + if (dec) + wc_Arc4SetKey(dec->arc4, keys->server_write_key, sz); + } + else { + if (enc) + wc_Arc4SetKey(enc->arc4, keys->server_write_key, sz); + if (dec) + wc_Arc4SetKey(dec->arc4, keys->client_write_key, sz); + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* BUILD_ARC4 */ + + +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + /* Check that the max implicit iv size is suffecient */ + #if (AEAD_MAX_IMP_SZ < 12) /* CHACHA20_IMP_IV_SZ */ + #error AEAD_MAX_IMP_SZ is too small for ChaCha20 + #endif + #if (MAX_WRITE_IV_SZ < 12) /* CHACHA20_IMP_IV_SZ */ + #error MAX_WRITE_IV_SZ is too small for ChaCha20 + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_chacha) { + int chachaRet; + if (enc && enc->chacha == NULL) + enc->chacha = + (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER); + if (enc && enc->chacha == NULL) + return MEMORY_E; + if (dec && dec->chacha == NULL) + dec->chacha = + (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER); + if (dec && dec->chacha == NULL) + return MEMORY_E; + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + chachaRet = wc_Chacha_SetKey(enc->chacha, keys->client_write_key, + specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV, + CHACHA20_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + } + if (dec) { + chachaRet = wc_Chacha_SetKey(dec->chacha, keys->server_write_key, + specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV, + CHACHA20_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + } + } + else { + if (enc) { + chachaRet = wc_Chacha_SetKey(enc->chacha, keys->server_write_key, + specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV, + CHACHA20_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + } + if (dec) { + chachaRet = wc_Chacha_SetKey(dec->chacha, keys->client_write_key, + specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV, + CHACHA20_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + } + } + + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* HAVE_CHACHA && HAVE_POLY1305 */ + + +#ifdef HAVE_HC128 + /* check that buffer sizes are sufficient */ + #if (MAX_WRITE_IV_SZ < 16) /* HC_128_IV_SIZE */ + #error MAX_WRITE_IV_SZ too small for HC128 + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_hc128) { + int hcRet; + if (enc && enc->hc128 == NULL) + enc->hc128 = + (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER); + if (enc && enc->hc128 == NULL) + return MEMORY_E; + if (dec && dec->hc128 == NULL) + dec->hc128 = + (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER); + if (dec && dec->hc128 == NULL) + return MEMORY_E; + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + hcRet = wc_Hc128_SetKey(enc->hc128, keys->client_write_key, + keys->client_write_IV); + if (hcRet != 0) return hcRet; + } + if (dec) { + hcRet = wc_Hc128_SetKey(dec->hc128, keys->server_write_key, + keys->server_write_IV); + if (hcRet != 0) return hcRet; + } + } + else { + if (enc) { + hcRet = wc_Hc128_SetKey(enc->hc128, keys->server_write_key, + keys->server_write_IV); + if (hcRet != 0) return hcRet; + } + if (dec) { + hcRet = wc_Hc128_SetKey(dec->hc128, keys->client_write_key, + keys->client_write_IV); + if (hcRet != 0) return hcRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* HAVE_HC128 */ + +#ifdef BUILD_RABBIT + /* check that buffer sizes are sufficient */ + #if (MAX_WRITE_IV_SZ < 8) /* RABBIT_IV_SIZE */ + #error MAX_WRITE_IV_SZ too small for RABBIT + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_rabbit) { + int rabRet; + if (enc && enc->rabbit == NULL) + enc->rabbit = + (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER); + if (enc && enc->rabbit == NULL) + return MEMORY_E; + if (dec && dec->rabbit == NULL) + dec->rabbit = + (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER); + if (dec && dec->rabbit == NULL) + return MEMORY_E; + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + rabRet = wc_RabbitSetKey(enc->rabbit, keys->client_write_key, + keys->client_write_IV); + if (rabRet != 0) return rabRet; + } + if (dec) { + rabRet = wc_RabbitSetKey(dec->rabbit, keys->server_write_key, + keys->server_write_IV); + if (rabRet != 0) return rabRet; + } + } + else { + if (enc) { + rabRet = wc_RabbitSetKey(enc->rabbit, keys->server_write_key, + keys->server_write_IV); + if (rabRet != 0) return rabRet; + } + if (dec) { + rabRet = wc_RabbitSetKey(dec->rabbit, keys->client_write_key, + keys->client_write_IV); + if (rabRet != 0) return rabRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* BUILD_RABBIT */ + +#ifdef BUILD_DES3 + /* check that buffer sizes are sufficient */ + #if (MAX_WRITE_IV_SZ < 8) /* DES_IV_SIZE */ + #error MAX_WRITE_IV_SZ too small for 3DES + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_triple_des) { + int desRet = 0; + + if (enc) { + if (enc->des3 == NULL) + enc->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER); + if (enc->des3 == NULL) + return MEMORY_E; + XMEMSET(enc->des3, 0, sizeof(Des3)); + } + if (dec) { + if (dec->des3 == NULL) + dec->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER); + if (dec->des3 == NULL) + return MEMORY_E; + XMEMSET(dec->des3, 0, sizeof(Des3)); + } + + if (enc) { + if (wc_Des3Init(enc->des3, heap, devId) != 0) { + WOLFSSL_MSG("Des3Init failed in SetKeys"); + return ASYNC_INIT_E; + } + } + if (dec) { + if (wc_Des3Init(dec->des3, heap, devId) != 0) { + WOLFSSL_MSG("Des3Init failed in SetKeys"); + return ASYNC_INIT_E; + } + } + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + desRet = wc_Des3_SetKey(enc->des3, keys->client_write_key, + keys->client_write_IV, DES_ENCRYPTION); + if (desRet != 0) return desRet; + } + if (dec) { + desRet = wc_Des3_SetKey(dec->des3, keys->server_write_key, + keys->server_write_IV, DES_DECRYPTION); + if (desRet != 0) return desRet; + } + } + else { + if (enc) { + desRet = wc_Des3_SetKey(enc->des3, keys->server_write_key, + keys->server_write_IV, DES_ENCRYPTION); + if (desRet != 0) return desRet; + } + if (dec) { + desRet = wc_Des3_SetKey(dec->des3, keys->client_write_key, + keys->client_write_IV, DES_DECRYPTION); + if (desRet != 0) return desRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* BUILD_DES3 */ + +#ifdef BUILD_AES + /* check that buffer sizes are sufficient */ + #if (MAX_WRITE_IV_SZ < 16) /* AES_IV_SIZE */ + #error MAX_WRITE_IV_SZ too small for AES + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_aes) { + int aesRet = 0; + + if (enc) { + if (enc->aes == NULL) + enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (enc->aes == NULL) + return MEMORY_E; + XMEMSET(enc->aes, 0, sizeof(Aes)); + } + if (dec) { + if (dec->aes == NULL) + dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (dec->aes == NULL) + return MEMORY_E; + XMEMSET(dec->aes, 0, sizeof(Aes)); + } + if (enc) { + if (wc_AesInit(enc->aes, heap, devId) != 0) { + WOLFSSL_MSG("AesInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + if (dec) { + if (wc_AesInit(dec->aes, heap, devId) != 0) { + WOLFSSL_MSG("AesInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + aesRet = wc_AesSetKey(enc->aes, keys->client_write_key, + specs->key_size, keys->client_write_IV, + AES_ENCRYPTION); + if (aesRet != 0) return aesRet; + } + if (dec) { + aesRet = wc_AesSetKey(dec->aes, keys->server_write_key, + specs->key_size, keys->server_write_IV, + AES_DECRYPTION); + if (aesRet != 0) return aesRet; + } + } + else { + if (enc) { + aesRet = wc_AesSetKey(enc->aes, keys->server_write_key, + specs->key_size, keys->server_write_IV, + AES_ENCRYPTION); + if (aesRet != 0) return aesRet; + } + if (dec) { + aesRet = wc_AesSetKey(dec->aes, keys->client_write_key, + specs->key_size, keys->client_write_IV, + AES_DECRYPTION); + if (aesRet != 0) return aesRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* BUILD_AES */ + +#ifdef BUILD_AESGCM + /* check that buffer sizes are sufficient */ + #if (AEAD_MAX_IMP_SZ < 4) /* AESGCM_IMP_IV_SZ */ + #error AEAD_MAX_IMP_SZ too small for AESGCM + #endif + #if (AEAD_MAX_EXP_SZ < 8) /* AESGCM_EXP_IV_SZ */ + #error AEAD_MAX_EXP_SZ too small for AESGCM + #endif + #if (MAX_WRITE_IV_SZ < 4) /* AESGCM_IMP_IV_SZ */ + #error MAX_WRITE_IV_SZ too small for AESGCM + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_aes_gcm) { + int gcmRet; + + if (enc) { + if (enc->aes == NULL) + enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (enc->aes == NULL) + return MEMORY_E; + XMEMSET(enc->aes, 0, sizeof(Aes)); + } + if (dec) { + if (dec->aes == NULL) + dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (dec->aes == NULL) + return MEMORY_E; + XMEMSET(dec->aes, 0, sizeof(Aes)); + } + + if (enc) { + if (wc_AesInit(enc->aes, heap, devId) != 0) { + WOLFSSL_MSG("AesInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + if (dec) { + if (wc_AesInit(dec->aes, heap, devId) != 0) { + WOLFSSL_MSG("AesInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + gcmRet = wc_AesGcmSetKey(enc->aes, keys->client_write_key, + specs->key_size); + if (gcmRet != 0) return gcmRet; + XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV, + AEAD_MAX_IMP_SZ); +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + if (!tls13) { + gcmRet = wc_AesGcmSetIV(enc->aes, AESGCM_NONCE_SZ, + keys->client_write_IV, AESGCM_IMP_IV_SZ, rng); + if (gcmRet != 0) return gcmRet; + } +#endif + } + if (dec) { + gcmRet = wc_AesGcmSetKey(dec->aes, keys->server_write_key, + specs->key_size); + if (gcmRet != 0) return gcmRet; + XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV, + AEAD_MAX_IMP_SZ); + } + } + else { + if (enc) { + gcmRet = wc_AesGcmSetKey(enc->aes, keys->server_write_key, + specs->key_size); + if (gcmRet != 0) return gcmRet; + XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV, + AEAD_MAX_IMP_SZ); +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + if (!tls13) { + gcmRet = wc_AesGcmSetIV(enc->aes, AESGCM_NONCE_SZ, + keys->server_write_IV, AESGCM_IMP_IV_SZ, rng); + if (gcmRet != 0) return gcmRet; + } +#endif + } + if (dec) { + gcmRet = wc_AesGcmSetKey(dec->aes, keys->client_write_key, + specs->key_size); + if (gcmRet != 0) return gcmRet; + XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV, + AEAD_MAX_IMP_SZ); + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* BUILD_AESGCM */ + +#ifdef HAVE_AESCCM + /* check that buffer sizes are sufficient (CCM is same size as GCM) */ + #if (AEAD_MAX_IMP_SZ < 4) /* AESGCM_IMP_IV_SZ */ + #error AEAD_MAX_IMP_SZ too small for AESCCM + #endif + #if (AEAD_MAX_EXP_SZ < 8) /* AESGCM_EXP_IV_SZ */ + #error AEAD_MAX_EXP_SZ too small for AESCCM + #endif + #if (MAX_WRITE_IV_SZ < 4) /* AESGCM_IMP_IV_SZ */ + #error MAX_WRITE_IV_SZ too small for AESCCM + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_aes_ccm) { + int CcmRet; + + if (enc) { + if (enc->aes == NULL) + enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (enc->aes == NULL) + return MEMORY_E; + XMEMSET(enc->aes, 0, sizeof(Aes)); + } + if (dec) { + if (dec->aes == NULL) + dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (dec->aes == NULL) + return MEMORY_E; + XMEMSET(dec->aes, 0, sizeof(Aes)); + } + + if (enc) { + if (wc_AesInit(enc->aes, heap, devId) != 0) { + WOLFSSL_MSG("AesInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + if (dec) { + if (wc_AesInit(dec->aes, heap, devId) != 0) { + WOLFSSL_MSG("AesInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + CcmRet = wc_AesCcmSetKey(enc->aes, keys->client_write_key, + specs->key_size); + if (CcmRet != 0) { + return CcmRet; + } + XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV, + AEAD_MAX_IMP_SZ); +#if !defined(NO_PUBLIC_CCM_SET_NONCE) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + if (!tls13) { + CcmRet = wc_AesCcmSetNonce(enc->aes, keys->client_write_IV, + AEAD_MAX_IMP_SZ); + if (CcmRet != 0) return CcmRet; + } +#endif + } + if (dec) { + CcmRet = wc_AesCcmSetKey(dec->aes, keys->server_write_key, + specs->key_size); + if (CcmRet != 0) { + return CcmRet; + } + XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV, + AEAD_MAX_IMP_SZ); + } + } + else { + if (enc) { + CcmRet = wc_AesCcmSetKey(enc->aes, keys->server_write_key, + specs->key_size); + if (CcmRet != 0) { + return CcmRet; + } + XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV, + AEAD_MAX_IMP_SZ); +#if !defined(NO_PUBLIC_CCM_SET_NONCE) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + if (!tls13) { + CcmRet = wc_AesCcmSetNonce(enc->aes, keys->server_write_IV, + AEAD_MAX_IMP_SZ); + if (CcmRet != 0) return CcmRet; + } +#endif + } + if (dec) { + CcmRet = wc_AesCcmSetKey(dec->aes, keys->client_write_key, + specs->key_size); + if (CcmRet != 0) { + return CcmRet; + } + XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV, + AEAD_MAX_IMP_SZ); + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* HAVE_AESCCM */ + +#ifdef HAVE_CAMELLIA + /* check that buffer sizes are sufficient */ + #if (MAX_WRITE_IV_SZ < 16) /* CAMELLIA_IV_SIZE */ + #error MAX_WRITE_IV_SZ too small for CAMELLIA + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_camellia) { + int camRet; + + if (enc && enc->cam == NULL) + enc->cam = + (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER); + if (enc && enc->cam == NULL) + return MEMORY_E; + + if (dec && dec->cam == NULL) + dec->cam = + (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER); + if (dec && dec->cam == NULL) + return MEMORY_E; + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + camRet = wc_CamelliaSetKey(enc->cam, keys->client_write_key, + specs->key_size, keys->client_write_IV); + if (camRet != 0) return camRet; + } + if (dec) { + camRet = wc_CamelliaSetKey(dec->cam, keys->server_write_key, + specs->key_size, keys->server_write_IV); + if (camRet != 0) return camRet; + } + } + else { + if (enc) { + camRet = wc_CamelliaSetKey(enc->cam, keys->server_write_key, + specs->key_size, keys->server_write_IV); + if (camRet != 0) return camRet; + } + if (dec) { + camRet = wc_CamelliaSetKey(dec->cam, keys->client_write_key, + specs->key_size, keys->client_write_IV); + if (camRet != 0) return camRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* HAVE_CAMELLIA */ + +#ifdef HAVE_IDEA + /* check that buffer sizes are sufficient */ + #if (MAX_WRITE_IV_SZ < 8) /* IDEA_IV_SIZE */ + #error MAX_WRITE_IV_SZ too small for IDEA + #endif + + if (specs->bulk_cipher_algorithm == wolfssl_idea) { + int ideaRet; + + if (enc && enc->idea == NULL) + enc->idea = (Idea*)XMALLOC(sizeof(Idea), heap, DYNAMIC_TYPE_CIPHER); + if (enc && enc->idea == NULL) + return MEMORY_E; + + if (dec && dec->idea == NULL) + dec->idea = (Idea*)XMALLOC(sizeof(Idea), heap, DYNAMIC_TYPE_CIPHER); + if (dec && dec->idea == NULL) + return MEMORY_E; + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + ideaRet = wc_IdeaSetKey(enc->idea, keys->client_write_key, + specs->key_size, keys->client_write_IV, + IDEA_ENCRYPTION); + if (ideaRet != 0) return ideaRet; + } + if (dec) { + ideaRet = wc_IdeaSetKey(dec->idea, keys->server_write_key, + specs->key_size, keys->server_write_IV, + IDEA_DECRYPTION); + if (ideaRet != 0) return ideaRet; + } + } + else { + if (enc) { + ideaRet = wc_IdeaSetKey(enc->idea, keys->server_write_key, + specs->key_size, keys->server_write_IV, + IDEA_ENCRYPTION); + if (ideaRet != 0) return ideaRet; + } + if (dec) { + ideaRet = wc_IdeaSetKey(dec->idea, keys->client_write_key, + specs->key_size, keys->client_write_IV, + IDEA_DECRYPTION); + if (ideaRet != 0) return ideaRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif /* HAVE_IDEA */ + +#ifdef HAVE_NULL_CIPHER + if (specs->bulk_cipher_algorithm == wolfssl_cipher_null) { + #ifdef WOLFSSL_TLS13 + if (tls13) { + int hmacRet; + int hashType = WC_HASH_TYPE_NONE; + + switch (specs->mac_algorithm) { + case sha256_mac: + hashType = WC_SHA256; + break; + case sha384_mac: + hashType = WC_SHA384; + break; + default: + break; + } + + if (enc && enc->hmac == NULL) { + enc->hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, + DYNAMIC_TYPE_CIPHER); + if (enc->hmac == NULL) + return MEMORY_E; + } + + if (dec && dec->hmac == NULL) { + dec->hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, + DYNAMIC_TYPE_CIPHER); + if (dec->hmac == NULL) + return MEMORY_E; + } + + if (enc) { + if (wc_HmacInit(enc->hmac, heap, devId) != 0) { + WOLFSSL_MSG("HmacInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + if (dec) { + if (wc_HmacInit(dec->hmac, heap, devId) != 0) { + WOLFSSL_MSG("HmacInit failed in SetKeys"); + return ASYNC_INIT_E; + } + } + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + hmacRet = wc_HmacSetKey(enc->hmac, hashType, + keys->client_write_key, specs->key_size); + if (hmacRet != 0) return hmacRet; + } + if (dec) { + hmacRet = wc_HmacSetKey(dec->hmac, hashType, + keys->server_write_key, specs->key_size); + if (hmacRet != 0) return hmacRet; + } + } + else { + if (enc) { + hmacRet = wc_HmacSetKey(enc->hmac, hashType, + keys->server_write_key, specs->key_size); + if (hmacRet != 0) return hmacRet; + } + if (dec) { + hmacRet = wc_HmacSetKey(dec->hmac, hashType, + keys->client_write_key, specs->key_size); + if (hmacRet != 0) return hmacRet; + } + } + } + #endif + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif + + if (enc) { + keys->sequence_number_hi = 0; + keys->sequence_number_lo = 0; + } + if (dec) { + keys->peer_sequence_number_hi = 0; + keys->peer_sequence_number_lo = 0; + } + (void)side; + (void)heap; + (void)enc; + (void)dec; + (void)specs; + (void)devId; + + return 0; +} + + +#ifdef HAVE_ONE_TIME_AUTH +/* set one time authentication keys */ +static int SetAuthKeys(OneTimeAuth* authentication, Keys* keys, + CipherSpecs* specs, void* heap, int devId) +{ + +#ifdef HAVE_POLY1305 + /* set up memory space for poly1305 */ + if (authentication && authentication->poly1305 == NULL) + authentication->poly1305 = + (Poly1305*)XMALLOC(sizeof(Poly1305), heap, DYNAMIC_TYPE_CIPHER); + if (authentication && authentication->poly1305 == NULL) + return MEMORY_E; + if (authentication) + authentication->setup = 1; +#endif + (void)authentication; + (void)heap; + (void)keys; + (void)specs; + (void)devId; + + return 0; +} +#endif /* HAVE_ONE_TIME_AUTH */ + +#ifdef HAVE_SECURE_RENEGOTIATION +/* function name is for cache_status++ + * This function was added because of error incrementing enum type when + * compiling with a C++ compiler. + */ +static void CacheStatusPP(SecureRenegotiation* cache) +{ + switch (cache->cache_status) { + case SCR_CACHE_NULL: + cache->cache_status = SCR_CACHE_NEEDED; + break; + + case SCR_CACHE_NEEDED: + cache->cache_status = SCR_CACHE_COPY; + break; + + case SCR_CACHE_COPY: + cache->cache_status = SCR_CACHE_PARTIAL; + break; + + case SCR_CACHE_PARTIAL: + cache->cache_status = SCR_CACHE_COMPLETE; + break; + + case SCR_CACHE_COMPLETE: + WOLFSSL_MSG("SCR Cache state Complete"); + break; + + default: + WOLFSSL_MSG("Unknown cache state!!"); + } +} +#endif /* HAVE_SECURE_RENEGOTIATION */ + + +/* Set wc_encrypt/wc_decrypt or both sides of key setup + * note: use wc_encrypt to avoid shadowing global encrypt + * declared in unistd.h + */ +int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) +{ + int ret, copy = 0; + Ciphers* wc_encrypt = NULL; + Ciphers* wc_decrypt = NULL; + Keys* keys = &ssl->keys; + + (void)copy; + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status) { + keys = &ssl->secure_renegotiation->tmp_keys; + copy = 1; + } +#endif /* HAVE_SECURE_RENEGOTIATION */ + + switch (side) { + case ENCRYPT_SIDE_ONLY: +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning ENCRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.client_write_key, ssl->specs.key_size); + } + else { + WOLFSSL_BUFFER(ssl->keys.server_write_key, ssl->specs.key_size); + } +#endif + wc_encrypt = &ssl->encrypt; + break; + + case DECRYPT_SIDE_ONLY: +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning DECRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.server_write_key, ssl->specs.key_size); + } + else { + WOLFSSL_BUFFER(ssl->keys.client_write_key, ssl->specs.key_size); + } +#endif + wc_decrypt = &ssl->decrypt; + break; + + case ENCRYPT_AND_DECRYPT_SIDE: +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning ENCRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.client_write_key, ssl->specs.key_size); + } + else { + WOLFSSL_BUFFER(ssl->keys.server_write_key, ssl->specs.key_size); + } + WOLFSSL_MSG("Provisioning DECRYPT key"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_BUFFER(ssl->keys.server_write_key, ssl->specs.key_size); + } + else { + WOLFSSL_BUFFER(ssl->keys.client_write_key, ssl->specs.key_size); + } +#endif + wc_encrypt = &ssl->encrypt; + wc_decrypt = &ssl->decrypt; + break; + + default: + return BAD_FUNC_ARG; + } + +#ifdef HAVE_ONE_TIME_AUTH + if (!ssl->auth.setup && ssl->specs.bulk_cipher_algorithm == wolfssl_chacha){ + ret = SetAuthKeys(&ssl->auth, keys, &ssl->specs, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + } +#endif + +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + /* check if keys for TSIP has been created */ + if (tsip_useable(ssl) == 1) + ret = 0; + else +#endif + ret = SetKeys(wc_encrypt, wc_decrypt, keys, &ssl->specs, ssl->options.side, + ssl->heap, ssl->devId, ssl->rng, ssl->options.tls1_3); + +#ifdef HAVE_SECURE_RENEGOTIATION + if (copy) { + int clientCopy = 0; + + if (ssl->options.side == WOLFSSL_CLIENT_END && wc_encrypt) + clientCopy = 1; + else if (ssl->options.side == WOLFSSL_SERVER_END && wc_decrypt) + clientCopy = 1; + + if (clientCopy) { + #ifndef WOLFSSL_AEAD_ONLY + XMEMCPY(ssl->keys.client_write_MAC_secret, + keys->client_write_MAC_secret, WC_MAX_DIGEST_SIZE); + #endif + XMEMCPY(ssl->keys.client_write_key, + keys->client_write_key, AES_256_KEY_SIZE); + XMEMCPY(ssl->keys.client_write_IV, + keys->client_write_IV, MAX_WRITE_IV_SZ); + } else { + #ifndef WOLFSSL_AEAD_ONLY + XMEMCPY(ssl->keys.server_write_MAC_secret, + keys->server_write_MAC_secret, WC_MAX_DIGEST_SIZE); + #endif + XMEMCPY(ssl->keys.server_write_key, + keys->server_write_key, AES_256_KEY_SIZE); + XMEMCPY(ssl->keys.server_write_IV, + keys->server_write_IV, MAX_WRITE_IV_SZ); + } + if (wc_encrypt) { + ssl->keys.sequence_number_hi = keys->sequence_number_hi; + ssl->keys.sequence_number_lo = keys->sequence_number_lo; + #ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + /* Initialize the AES-GCM/CCM explicit IV to a zero. */ + XMEMCPY(ssl->keys.aead_exp_IV, keys->aead_exp_IV, + AEAD_MAX_EXP_SZ); + + /* Initialize encrypt implicit IV by encrypt side */ + if (ssl->options.side == WOLFSSL_CLIENT_END) { + XMEMCPY(ssl->keys.aead_enc_imp_IV, + keys->client_write_IV, AEAD_MAX_IMP_SZ); + } else { + XMEMCPY(ssl->keys.aead_enc_imp_IV, + keys->server_write_IV, AEAD_MAX_IMP_SZ); + } + } + #endif + } + if (wc_decrypt) { + ssl->keys.peer_sequence_number_hi = keys->peer_sequence_number_hi; + ssl->keys.peer_sequence_number_lo = keys->peer_sequence_number_lo; + #ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + /* Initialize decrypt implicit IV by decrypt side */ + if (ssl->options.side == WOLFSSL_SERVER_END) { + XMEMCPY(ssl->keys.aead_dec_imp_IV, + keys->client_write_IV, AEAD_MAX_IMP_SZ); + } else { + XMEMCPY(ssl->keys.aead_dec_imp_IV, + keys->server_write_IV, AEAD_MAX_IMP_SZ); + } + } + #endif + } + CacheStatusPP(ssl->secure_renegotiation); + } +#endif /* HAVE_SECURE_RENEGOTIATION */ + + return ret; +} + + +/* TLS can call too */ +int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side) +{ + int sz, i = 0; + Keys* keys = &ssl->keys; + +#ifdef HAVE_SECURE_RENEGOTIATION + if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status == + SCR_CACHE_NEEDED) { + keys = &ssl->secure_renegotiation->tmp_keys; + CacheStatusPP(ssl->secure_renegotiation); + } +#endif /* HAVE_SECURE_RENEGOTIATION */ + +#ifdef WOLFSSL_MULTICAST + if (ssl->options.haveMcast) { + /* Use the same keys for encrypt and decrypt. */ + if (ssl->specs.cipher_type != aead) { + sz = ssl->specs.hash_size; + #ifndef WOLFSSL_AEAD_ONLY + XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz); + XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz); + #endif + i += sz; + } + sz = ssl->specs.key_size; + XMEMCPY(keys->client_write_key, &keyData[i], sz); + XMEMCPY(keys->server_write_key, &keyData[i], sz); + i += sz; + + sz = ssl->specs.iv_size; + XMEMCPY(keys->client_write_IV, &keyData[i], sz); + XMEMCPY(keys->server_write_IV, &keyData[i], sz); + +#ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + /* Initialize the AES-GCM/CCM explicit IV to a zero. */ + XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ); + } +#endif /* HAVE_AEAD */ + + return 0; + } +#endif /* WOLFSSL_MULTICAST */ + + if (ssl->specs.cipher_type != aead) { + sz = ssl->specs.hash_size; + if (side & PROVISION_CLIENT) { + #ifndef WOLFSSL_AEAD_ONLY + XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz); + #endif + i += sz; + } + if (side & PROVISION_SERVER) { + #ifndef WOLFSSL_AEAD_ONLY + XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz); + #endif + i += sz; + } + } + sz = ssl->specs.key_size; + if (side & PROVISION_CLIENT) { + XMEMCPY(keys->client_write_key, &keyData[i], sz); + i += sz; + } + if (side & PROVISION_SERVER) { + XMEMCPY(keys->server_write_key, &keyData[i], sz); + i += sz; + } + + sz = ssl->specs.iv_size; + if (side & PROVISION_CLIENT) { + XMEMCPY(keys->client_write_IV, &keyData[i], sz); + i += sz; + } + if (side & PROVISION_SERVER) + XMEMCPY(keys->server_write_IV, &keyData[i], sz); + +#ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + /* Initialize the AES-GCM/CCM explicit IV to a zero. */ + XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ); + } +#endif + + return 0; +} + +#ifndef NO_OLD_TLS +int DeriveKeys(WOLFSSL* ssl) +{ + int length = 2 * ssl->specs.hash_size + + 2 * ssl->specs.key_size + + 2 * ssl->specs.iv_size; + int rounds = (length + WC_MD5_DIGEST_SIZE - 1 ) / WC_MD5_DIGEST_SIZE, i; + int ret = 0; + +#ifdef WOLFSSL_SMALL_STACK + byte* shaOutput; + byte* md5Input; + byte* shaInput; + byte* keyData; + wc_Md5* md5; + wc_Sha* sha; +#else + byte shaOutput[WC_SHA_DIGEST_SIZE]; + byte md5Input[SECRET_LEN + WC_SHA_DIGEST_SIZE]; + byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; + byte keyData[KEY_PREFIX * WC_MD5_DIGEST_SIZE]; + wc_Md5 md5[1]; + wc_Sha sha[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + shaOutput = (byte*)XMALLOC(WC_SHA_DIGEST_SIZE, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + md5Input = (byte*)XMALLOC(SECRET_LEN + WC_SHA_DIGEST_SIZE, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + shaInput = (byte*)XMALLOC(KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + keyData = (byte*)XMALLOC(KEY_PREFIX * WC_MD5_DIGEST_SIZE, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + md5 = (wc_Md5*)XMALLOC(sizeof(wc_Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER); + sha = (wc_Sha*)XMALLOC(sizeof(wc_Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (shaOutput == NULL || md5Input == NULL || shaInput == NULL || + keyData == NULL || md5 == NULL || sha == NULL) { + if (shaOutput) XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (md5Input) XFREE(md5Input, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (shaInput) XFREE(shaInput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (keyData) XFREE(keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (md5) XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sha) XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return MEMORY_E; + } +#endif + + ret = wc_InitMd5(md5); + if (ret == 0) { + ret = wc_InitSha(sha); + } + if (ret == 0) { + XMEMCPY(md5Input, ssl->arrays->masterSecret, SECRET_LEN); + + for (i = 0; i < rounds; ++i) { + int j = i + 1; + int idx = j; + + if (!SetPrefix(shaInput, i)) { + ret = PREFIX_ERROR; + break; + } + + XMEMCPY(shaInput + idx, ssl->arrays->masterSecret, SECRET_LEN); + idx += SECRET_LEN; + XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN); + idx += RAN_LEN; + XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN); + if (ret == 0) { + ret = wc_ShaUpdate(sha, shaInput, + (KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN) - KEY_PREFIX + j); + } + if (ret == 0) { + ret = wc_ShaFinal(sha, shaOutput); + } + + XMEMCPY(md5Input + SECRET_LEN, shaOutput, WC_SHA_DIGEST_SIZE); + if (ret == 0) { + ret = wc_Md5Update(md5, md5Input, SECRET_LEN + WC_SHA_DIGEST_SIZE); + } + if (ret == 0) { + ret = wc_Md5Final(md5, keyData + i * WC_MD5_DIGEST_SIZE); + } + } + + if (ret == 0) + ret = StoreKeys(ssl, keyData, PROVISION_CLIENT_SERVER); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(md5Input, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(shaInput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +static int CleanPreMaster(WOLFSSL* ssl) +{ + int i, ret, sz = ssl->arrays->preMasterSz; + + for (i = 0; i < sz; i++) + ssl->arrays->preMasterSecret[i] = 0; + + ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, sz); + if (ret != 0) + return ret; + + for (i = 0; i < sz; i++) + ssl->arrays->preMasterSecret[i] = 0; + + XFREE(ssl->arrays->preMasterSecret, ssl->heap, DYNAMIC_TYPE_SECRET); + ssl->arrays->preMasterSecret = NULL; + ssl->arrays->preMasterSz = 0; + + return 0; +} + + +/* Create and store the master secret see page 32, 6.1 */ +static int MakeSslMasterSecret(WOLFSSL* ssl) +{ + int i, ret; + word32 idx; + word32 pmsSz = ssl->arrays->preMasterSz; + +#ifdef WOLFSSL_SMALL_STACK + byte* shaOutput; + byte* md5Input; + byte* shaInput; + wc_Md5* md5; + wc_Sha* sha; +#else + byte shaOutput[WC_SHA_DIGEST_SIZE]; + byte md5Input[ENCRYPT_LEN + WC_SHA_DIGEST_SIZE]; + byte shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN]; + wc_Md5 md5[1]; + wc_Sha sha[1]; +#endif + +#ifdef SHOW_SECRETS + { + word32 j; + printf("pre master secret: "); + for (j = 0; j < pmsSz; j++) + printf("%02x", ssl->arrays->preMasterSecret[j]); + printf("\n"); + } +#endif + +#ifdef WOLFSSL_SMALL_STACK + shaOutput = (byte*)XMALLOC(WC_SHA_DIGEST_SIZE, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + md5Input = (byte*)XMALLOC(ENCRYPT_LEN + WC_SHA_DIGEST_SIZE, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + shaInput = (byte*)XMALLOC(PREFIX + ENCRYPT_LEN + 2 * RAN_LEN, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + md5 = (wc_Md5*)XMALLOC(sizeof(wc_Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER); + sha = (wc_Sha*)XMALLOC(sizeof(wc_Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (shaOutput == NULL || md5Input == NULL || shaInput == NULL || + md5 == NULL || sha == NULL) { + if (shaOutput) XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (md5Input) XFREE(md5Input, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (shaInput) XFREE(shaInput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (md5) XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sha) XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return MEMORY_E; + } +#endif + + ret = wc_InitMd5(md5); + if (ret == 0) { + ret = wc_InitSha(sha); + } + if (ret == 0) { + XMEMCPY(md5Input, ssl->arrays->preMasterSecret, pmsSz); + + for (i = 0; i < MASTER_ROUNDS; ++i) { + byte prefix[KEY_PREFIX]; /* only need PREFIX bytes but static */ + if (!SetPrefix(prefix, i)) { /* analysis thinks will overrun */ + ret = PREFIX_ERROR; + break; + } + + idx = 0; + XMEMCPY(shaInput, prefix, i + 1); + idx += i + 1; + + XMEMCPY(shaInput + idx, ssl->arrays->preMasterSecret, pmsSz); + idx += pmsSz; + XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN); + idx += RAN_LEN; + XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN); + idx += RAN_LEN; + if (ret == 0) { + ret = wc_ShaUpdate(sha, shaInput, idx); + } + if (ret == 0) { + ret = wc_ShaFinal(sha, shaOutput); + } + idx = pmsSz; /* preSz */ + XMEMCPY(md5Input + idx, shaOutput, WC_SHA_DIGEST_SIZE); + idx += WC_SHA_DIGEST_SIZE; + if (ret == 0) { + ret = wc_Md5Update(md5, md5Input, idx); + } + if (ret == 0) { + ret = wc_Md5Final(md5, + &ssl->arrays->masterSecret[i * WC_MD5_DIGEST_SIZE]); + } + } + +#ifdef SHOW_SECRETS + { + word32 j; + printf("master secret: "); + for (j = 0; j < SECRET_LEN; j++) + printf("%02x", ssl->arrays->masterSecret[j]); + printf("\n"); + } +#endif + + if (ret == 0) + ret = DeriveKeys(ssl); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(md5Input, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(shaInput, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (ret == 0) + ret = CleanPreMaster(ssl); + else + CleanPreMaster(ssl); + + return ret; +} +#endif + + +/* Master wrapper, doesn't use SSL stack space in TLS mode */ +int MakeMasterSecret(WOLFSSL* ssl) +{ + /* append secret to premaster : premaster | SerSi | CliSi */ +#ifdef HAVE_QSH + word32 offset = 0; + + if (ssl->peerQSHKeyPresent) { + offset += ssl->arrays->preMasterSz; + ssl->arrays->preMasterSz += ssl->QSH_secret->CliSi->length + + ssl->QSH_secret->SerSi->length; + /* test and set flag if QSH has been used */ + if (ssl->QSH_secret->CliSi->length > 0 || + ssl->QSH_secret->SerSi->length > 0) + ssl->isQSH = 1; + + /* append secrets to the premaster */ + if (ssl->QSH_secret->SerSi != NULL) { + XMEMCPY(ssl->arrays->preMasterSecret + offset, + ssl->QSH_secret->SerSi->buffer, ssl->QSH_secret->SerSi->length); + } + offset += ssl->QSH_secret->SerSi->length; + if (ssl->QSH_secret->CliSi != NULL) { + XMEMCPY(ssl->arrays->preMasterSecret + offset, + ssl->QSH_secret->CliSi->buffer, ssl->QSH_secret->CliSi->length); + } + + /* show secret SerSi and CliSi */ + #ifdef SHOW_SECRETS + { + word32 j; + printf("QSH generated secret material\n"); + printf("SerSi : "); + for (j = 0; j < ssl->QSH_secret->SerSi->length; j++) { + printf("%02x", ssl->QSH_secret->SerSi->buffer[j]); + } + printf("\n"); + printf("CliSi : "); + for (j = 0; j < ssl->QSH_secret->CliSi->length; j++) { + printf("%02x", ssl->QSH_secret->CliSi->buffer[j]); + } + printf("\n"); + } + #endif + } +#endif + +#ifndef NO_OLD_TLS + if (ssl->options.tls) return MakeTlsMasterSecret(ssl); + return MakeSslMasterSecret(ssl); +#elif !defined(WOLFSSL_NO_TLS12) + return MakeTlsMasterSecret(ssl); +#else + (void)ssl; + return 0; +#endif +} + +#endif /* WOLFCRYPT_ONLY */ diff --git a/client/wolfssl/src/ocsp.c b/client/wolfssl/src/ocsp.c new file mode 100644 index 0000000..b5a2719 --- /dev/null +++ b/client/wolfssl/src/ocsp.c @@ -0,0 +1,1100 @@ +/* ocsp.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + /* Name change compatibility layer no longer needs to be included here */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY +#ifdef HAVE_OCSP + +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + + +int InitOCSP(WOLFSSL_OCSP* ocsp, WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("InitOCSP"); + + ForceZero(ocsp, sizeof(WOLFSSL_OCSP)); + + if (wc_InitMutex(&ocsp->ocspLock) != 0) + return BAD_MUTEX_E; + + ocsp->cm = cm; + + return 0; +} + + +static int InitOcspEntry(OcspEntry* entry, OcspRequest* request) +{ + WOLFSSL_ENTER("InitOcspEntry"); + + ForceZero(entry, sizeof(OcspEntry)); + + XMEMCPY(entry->issuerHash, request->issuerHash, OCSP_DIGEST_SIZE); + XMEMCPY(entry->issuerKeyHash, request->issuerKeyHash, OCSP_DIGEST_SIZE); + + return 0; +} + + +static void FreeOcspEntry(OcspEntry* entry, void* heap) +{ + CertStatus *status, *next; + + WOLFSSL_ENTER("FreeOcspEntry"); + + for (status = entry->status; status; status = next) { + next = status->next; + + if (status->rawOcspResponse) + XFREE(status->rawOcspResponse, heap, DYNAMIC_TYPE_OCSP_STATUS); + + XFREE(status, heap, DYNAMIC_TYPE_OCSP_STATUS); + } + + (void)heap; +} + + +void FreeOCSP(WOLFSSL_OCSP* ocsp, int dynamic) +{ + OcspEntry *entry, *next; + + WOLFSSL_ENTER("FreeOCSP"); + + for (entry = ocsp->ocspList; entry; entry = next) { + next = entry->next; + FreeOcspEntry(entry, ocsp->cm->heap); + XFREE(entry, ocsp->cm->heap, DYNAMIC_TYPE_OCSP_ENTRY); + } + + wc_FreeMutex(&ocsp->ocspLock); + + if (dynamic) + XFREE(ocsp, ocsp->cm->heap, DYNAMIC_TYPE_OCSP); + +} + + +static int xstat2err(int st) +{ + switch (st) { + case CERT_GOOD: + return 0; + case CERT_REVOKED: + return OCSP_CERT_REVOKED; + default: + return OCSP_CERT_UNKNOWN; + } +} + +int CheckCertOCSP_ex(WOLFSSL_OCSP* ocsp, DecodedCert* cert, buffer* responseBuffer, WOLFSSL* ssl) +{ + int ret = OCSP_LOOKUP_FAIL; + +#ifdef WOLFSSL_SMALL_STACK + OcspRequest* ocspRequest; +#else + OcspRequest ocspRequest[1]; +#endif + + WOLFSSL_ENTER("CheckCertOCSP"); + + +#ifdef WOLFSSL_SMALL_STACK + ocspRequest = (OcspRequest*)XMALLOC(sizeof(OcspRequest), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (ocspRequest == NULL) { + WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); + return MEMORY_E; + } +#endif + + if (InitOcspRequest(ocspRequest, cert, ocsp->cm->ocspSendNonce, + ocsp->cm->heap) == 0) { + ocspRequest->ssl = ssl; + ret = CheckOcspRequest(ocsp, ocspRequest, responseBuffer); + + FreeOcspRequest(ocspRequest); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(ocspRequest, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + WOLFSSL_LEAVE("CheckCertOCSP", ret); + return ret; +} +int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert, buffer* responseBuffer) +{ + return CheckCertOCSP_ex(ocsp, cert, responseBuffer, NULL); +} + +static int GetOcspEntry(WOLFSSL_OCSP* ocsp, OcspRequest* request, + OcspEntry** entry) +{ + WOLFSSL_ENTER("GetOcspEntry"); + + *entry = NULL; + + if (wc_LockMutex(&ocsp->ocspLock) != 0) { + WOLFSSL_LEAVE("CheckCertOCSP", BAD_MUTEX_E); + return BAD_MUTEX_E; + } + + for (*entry = ocsp->ocspList; *entry; *entry = (*entry)->next) + if (XMEMCMP((*entry)->issuerHash, request->issuerHash, + OCSP_DIGEST_SIZE) == 0 + && XMEMCMP((*entry)->issuerKeyHash, request->issuerKeyHash, + OCSP_DIGEST_SIZE) == 0) + break; + + if (*entry == NULL) { + *entry = (OcspEntry*)XMALLOC(sizeof(OcspEntry), + ocsp->cm->heap, DYNAMIC_TYPE_OCSP_ENTRY); + if (*entry) { + InitOcspEntry(*entry, request); + (*entry)->next = ocsp->ocspList; + ocsp->ocspList = *entry; + } + } + + wc_UnLockMutex(&ocsp->ocspLock); + + return *entry ? 0 : MEMORY_ERROR; +} + + +/* Mallocs responseBuffer->buffer and is up to caller to free on success + * + * Returns OCSP status + */ +static int GetOcspStatus(WOLFSSL_OCSP* ocsp, OcspRequest* request, + OcspEntry* entry, CertStatus** status, buffer* responseBuffer) +{ + int ret = OCSP_INVALID_STATUS; + + WOLFSSL_ENTER("GetOcspStatus"); + + *status = NULL; + + if (wc_LockMutex(&ocsp->ocspLock) != 0) { + WOLFSSL_LEAVE("CheckCertOCSP", BAD_MUTEX_E); + return BAD_MUTEX_E; + } + + for (*status = entry->status; *status; *status = (*status)->next) + if ((*status)->serialSz == request->serialSz + && !XMEMCMP((*status)->serial, request->serial, (*status)->serialSz)) + break; + + if (responseBuffer && *status && !(*status)->rawOcspResponse) { + /* force fetching again */ + ret = OCSP_INVALID_STATUS; + } + else if (*status) { +#ifndef NO_ASN_TIME + if (XVALIDATE_DATE((*status)->thisDate, + (*status)->thisDateFormat, BEFORE) + && ((*status)->nextDate[0] != 0) + && XVALIDATE_DATE((*status)->nextDate, + (*status)->nextDateFormat, AFTER)) +#endif + { + ret = xstat2err((*status)->status); + + if (responseBuffer) { + responseBuffer->buffer = (byte*)XMALLOC( + (*status)->rawOcspResponseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (responseBuffer->buffer) { + responseBuffer->length = (*status)->rawOcspResponseSz; + XMEMCPY(responseBuffer->buffer, + (*status)->rawOcspResponse, + (*status)->rawOcspResponseSz); + } + } + } + } + + wc_UnLockMutex(&ocsp->ocspLock); + + return ret; +} + +/* Check that the response for validity. Store result in status. + * + * ocsp Context object for OCSP status. + * response OCSP response message data. + * responseSz Length of OCSP response message data. + * reponseBuffer Buffer object to return the response with. + * status The certificate status object. + * entry The OCSP entry for this certificate. + * returns OCSP_LOOKUP_FAIL when the response is bad and 0 otherwise. + */ +WOLFSSL_LOCAL int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int responseSz, + WOLFSSL_BUFFER_INFO *responseBuffer, CertStatus *status, + OcspEntry *entry, OcspRequest *ocspRequest) +{ +#ifdef WOLFSSL_SMALL_STACK + CertStatus* newStatus; + OcspResponse* ocspResponse; +#else + CertStatus newStatus[1]; + OcspResponse ocspResponse[1]; +#endif + int ret; + int validated = 0; /* ocsp validation flag */ + +#ifdef WOLFSSL_SMALL_STACK + newStatus = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ocspResponse = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (newStatus == NULL || ocspResponse == NULL) { + if (newStatus) XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (ocspResponse) XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); + return MEMORY_E; + } +#endif + XMEMSET(newStatus, 0, sizeof(CertStatus)); + + InitOcspResponse(ocspResponse, newStatus, response, responseSz); + ret = OcspResponseDecode(ocspResponse, ocsp->cm, ocsp->cm->heap, 0); + if (ret != 0) { + ocsp->error = ret; + WOLFSSL_LEAVE("OcspResponseDecode failed", ocsp->error); + goto end; + } + + if (ocspResponse->responseStatus != OCSP_SUCCESSFUL) { + WOLFSSL_MSG("OcspResponse status bad"); + goto end; + } + if (ocspRequest != NULL) { + ret = CompareOcspReqResp(ocspRequest, ocspResponse); + if (ret != 0) { + goto end; + } + } + + if (responseBuffer) { + responseBuffer->buffer = (byte*)XMALLOC(responseSz, ocsp->cm->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (responseBuffer->buffer) { + responseBuffer->length = responseSz; + XMEMCPY(responseBuffer->buffer, response, responseSz); + } + } + + ret = xstat2err(ocspResponse->status->status); + if (ret == 0) { + validated = 1; + } + + if (wc_LockMutex(&ocsp->ocspLock) != 0) { + ret = BAD_MUTEX_E; + goto end; + } + + if (status != NULL) { + if (status->rawOcspResponse) { + XFREE(status->rawOcspResponse, ocsp->cm->heap, + DYNAMIC_TYPE_OCSP_STATUS); + } + + /* Replace existing certificate entry with updated */ + newStatus->next = status->next; + XMEMCPY(status, newStatus, sizeof(CertStatus)); + } + else { + /* Save new certificate entry */ + status = (CertStatus*)XMALLOC(sizeof(CertStatus), + ocsp->cm->heap, DYNAMIC_TYPE_OCSP_STATUS); + if (status != NULL) { + XMEMCPY(status, newStatus, sizeof(CertStatus)); + status->next = entry->status; + entry->status = status; + entry->totalStatus++; + } + } + + if (status && responseBuffer && responseBuffer->buffer) { + status->rawOcspResponse = (byte*)XMALLOC(responseBuffer->length, + ocsp->cm->heap, + DYNAMIC_TYPE_OCSP_STATUS); + + if (status->rawOcspResponse) { + status->rawOcspResponseSz = responseBuffer->length; + XMEMCPY(status->rawOcspResponse, responseBuffer->buffer, + responseBuffer->length); + } + } + + wc_UnLockMutex(&ocsp->ocspLock); + +end: + if (ret == 0 && validated == 1) { + WOLFSSL_MSG("New OcspResponse validated"); + } else if (ret != OCSP_CERT_REVOKED) { + ret = OCSP_LOOKUP_FAIL; + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; +} + +/* 0 on success */ +int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest, + buffer* responseBuffer) +{ + OcspEntry* entry = NULL; + CertStatus* status = NULL; + byte* request = NULL; + int requestSz = 2048; + int responseSz = 0; + byte* response = NULL; + const char* url = NULL; + int urlSz = 0; + int ret = -1; + WOLFSSL* ssl; + void* ioCtx; + + WOLFSSL_ENTER("CheckOcspRequest"); + + if (ocsp == NULL || ocspRequest == NULL) + return BAD_FUNC_ARG; + + if (responseBuffer) { + responseBuffer->buffer = NULL; + responseBuffer->length = 0; + } + + ret = GetOcspEntry(ocsp, ocspRequest, &entry); + if (ret != 0) + return ret; + + ret = GetOcspStatus(ocsp, ocspRequest, entry, &status, responseBuffer); + if (ret != OCSP_INVALID_STATUS) + return ret; + + /* get SSL and IOCtx */ + ssl = (WOLFSSL*)ocspRequest->ssl; + ioCtx = (ssl && ssl->ocspIOCtx != NULL) ? + ssl->ocspIOCtx : ocsp->cm->ocspIOCtx; + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + if (ocsp->statusCb != NULL && ssl != NULL) { + ret = ocsp->statusCb(ssl, ioCtx); + if (ret == 0) { + ret = wolfSSL_get_ocsp_response(ssl, &response); + ret = CheckOcspResponse(ocsp, response, ret, responseBuffer, status, + entry, NULL); + if (response != NULL) + XFREE(response, NULL, DYNAMIC_TYPE_OPENSSL); + return ret; + } + WOLFSSL_LEAVE("CheckOcspRequest", ocsp->error); + return OCSP_LOOKUP_FAIL; + } +#endif + + if (ocsp->cm->ocspUseOverrideURL) { + url = ocsp->cm->ocspOverrideURL; + if (url != NULL && url[0] != '\0') + urlSz = (int)XSTRLEN(url); + else + return OCSP_NEED_URL; + } + else if (ocspRequest->urlSz != 0 && ocspRequest->url != NULL) { + url = (const char *)ocspRequest->url; + urlSz = ocspRequest->urlSz; + } + else { + /* cert doesn't have extAuthInfo, assuming CERT_GOOD */ + return 0; + } + + request = (byte*)XMALLOC(requestSz, ocsp->cm->heap, DYNAMIC_TYPE_OCSP); + if (request == NULL) { + WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); + if (responseBuffer) { + XFREE(responseBuffer->buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + responseBuffer->buffer = NULL; + } + return MEMORY_ERROR; + } + + requestSz = EncodeOcspRequest(ocspRequest, request, requestSz); + if (requestSz > 0 && ocsp->cm->ocspIOCb) { + responseSz = ocsp->cm->ocspIOCb(ioCtx, url, urlSz, + request, requestSz, &response); + } + if (responseSz == WOLFSSL_CBIO_ERR_WANT_READ) { + ret = OCSP_WANT_READ; + } + + XFREE(request, ocsp->cm->heap, DYNAMIC_TYPE_OCSP); + + if (responseSz >= 0 && response) { + ret = CheckOcspResponse(ocsp, response, responseSz, responseBuffer, status, + entry, ocspRequest); + } + + if (response != NULL && ocsp->cm->ocspRespFreeCb) + ocsp->cm->ocspRespFreeCb(ioCtx, response); + + /* Keep responseBuffer in the case of getting to response check. Caller + * should free responseBuffer after checking OCSP return value in "ret" */ + WOLFSSL_LEAVE("CheckOcspRequest", ret); + return ret; +} + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_APACHE_HTTPD) + +int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs, + WOLFSSL_OCSP_CERTID* id, int* status, int* reason, + WOLFSSL_ASN1_TIME** revtime, WOLFSSL_ASN1_TIME** thisupd, + WOLFSSL_ASN1_TIME** nextupd) +{ + if (bs == NULL || id == NULL) + return WOLFSSL_FAILURE; + + /* Only supporting one certificate status in asn.c. */ + if (CompareOcspReqResp(id, bs) != 0) + return WOLFSSL_FAILURE; + + if (status != NULL) + *status = bs->status->status; + if (thisupd != NULL) + *thisupd = &bs->status->thisDateParsed; + if (nextupd != NULL) + *nextupd = &bs->status->nextDateParsed; + + /* TODO: Not needed for Nginx. */ + if (reason != NULL) + *reason = 0; + if (revtime != NULL) + *revtime = NULL; + + return WOLFSSL_SUCCESS; +} + +const char *wolfSSL_OCSP_cert_status_str(long s) +{ + switch (s) { + case CERT_GOOD: + return "good"; + case CERT_REVOKED: + return "revoked"; + case CERT_UNKNOWN: + return "unknown"; + default: + return "(UNKNOWN)"; + } +} + +int wolfSSL_OCSP_check_validity(WOLFSSL_ASN1_TIME* thisupd, + WOLFSSL_ASN1_TIME* nextupd, long sec, long maxsec) +{ + (void)thisupd; + (void)nextupd; + (void)sec; + (void)maxsec; + /* Dates validated in DecodeSingleResponse. */ + return WOLFSSL_SUCCESS; +} + +void wolfSSL_OCSP_CERTID_free(WOLFSSL_OCSP_CERTID* certId) +{ + FreeOcspRequest(certId); + XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); +} + +WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_cert_to_id( + const WOLFSSL_EVP_MD *dgst, const WOLFSSL_X509 *subject, + const WOLFSSL_X509 *issuer) +{ + WOLFSSL_OCSP_CERTID* certId; + DecodedCert cert; + WOLFSSL_CERT_MANAGER* cm; + int ret; + DerBuffer* derCert = NULL; + + (void)dgst; + + cm = wolfSSL_CertManagerNew(); + if (cm == NULL) + return NULL; + + ret = AllocDer(&derCert, issuer->derCert->length, + issuer->derCert->type, NULL); + if (ret == 0) { + /* AddCA() frees the buffer. */ + XMEMCPY(derCert->buffer, issuer->derCert->buffer, + issuer->derCert->length); + AddCA(cm, &derCert, WOLFSSL_USER_CA, 1); + } + + certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), NULL, + DYNAMIC_TYPE_OPENSSL); + if (certId != NULL) { + InitDecodedCert(&cert, subject->derCert->buffer, + subject->derCert->length, NULL); + if (ParseCertRelative(&cert, CERT_TYPE, VERIFY_OCSP, cm) != 0) { + XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); + certId = NULL; + } + else { + ret = InitOcspRequest(certId, &cert, 0, NULL); + if (ret != 0) { + XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); + certId = NULL; + } + } + FreeDecodedCert(&cert); + } + + wolfSSL_CertManagerFree(cm); + + return certId; +} + +void wolfSSL_OCSP_BASICRESP_free(WOLFSSL_OCSP_BASICRESP* basicResponse) +{ + wolfSSL_OCSP_RESPONSE_free(basicResponse); +} + +/* Signature verified in DecodeBasicOcspResponse. + * But no store available to verify certificate. */ +int wolfSSL_OCSP_basic_verify(WOLFSSL_OCSP_BASICRESP *bs, + WOLF_STACK_OF(WOLFSSL_X509) *certs, WOLFSSL_X509_STORE *st, unsigned long flags) +{ + DecodedCert cert; + int ret = WOLFSSL_SUCCESS; + + (void)certs; + + if (flags & OCSP_NOVERIFY) + return WOLFSSL_SUCCESS; + +#ifdef OPENSSL_EXTRA + if (bs->verifyError != OCSP_VERIFY_ERROR_NONE) + return WOLFSSL_FAILURE; +#endif + + InitDecodedCert(&cert, bs->cert, bs->certSz, NULL); + if (ParseCertRelative(&cert, CERT_TYPE, VERIFY, st->cm) < 0) + ret = WOLFSSL_FAILURE; + FreeDecodedCert(&cert); + + return ret; +} + +void wolfSSL_OCSP_RESPONSE_free(OcspResponse* response) +{ + if (response->status != NULL) + XFREE(response->status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (response->source != NULL) + XFREE(response->source, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(response, NULL, DYNAMIC_TYPE_OPENSSL); +} + +OcspResponse* wolfSSL_d2i_OCSP_RESPONSE_bio(WOLFSSL_BIO* bio, + OcspResponse** response) +{ + byte* data; + byte* p; + int len; + int dataAlloced = 0; + OcspResponse* ret = NULL; + + if (bio == NULL) + return NULL; + + if (bio->type == WOLFSSL_BIO_MEMORY) { + len = wolfSSL_BIO_get_mem_data(bio, &data); + if (len <= 0 || data == NULL) { + return NULL; + } + } +#ifndef NO_FILESYSTEM + else if (bio->type == WOLFSSL_BIO_FILE) { + long fcur; + long flen; + + if (bio->ptr == NULL) + return NULL; + + fcur = XFTELL((XFILE)bio->ptr); + if (fcur < 0) + return NULL; + if(XFSEEK((XFILE)bio->ptr, 0, SEEK_END) != 0) + return NULL; + flen = XFTELL((XFILE)bio->ptr); + if (flen < 0) + return NULL; + if (XFSEEK((XFILE)bio->ptr, fcur, SEEK_SET) != 0) + return NULL; + + /* check calculated length */ + fcur = flen - fcur; + if (fcur > MAX_WOLFSSL_FILE_SIZE || fcur <= 0) + return NULL; + + data = (byte*)XMALLOC(fcur, 0, DYNAMIC_TYPE_TMP_BUFFER); + if (data == NULL) + return NULL; + dataAlloced = 1; + + len = wolfSSL_BIO_read(bio, (char *)data, (int)flen); + } +#endif + else + return NULL; + + if (len > 0) { + p = data; + ret = wolfSSL_d2i_OCSP_RESPONSE(response, (const unsigned char **)&p, + len); + } + + if (dataAlloced) + XFREE(data, 0, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, + const unsigned char** data, int len) +{ + OcspResponse *resp = NULL; + word32 idx = 0; + int length = 0; + + if (data == NULL) + return NULL; + + if (response != NULL) + resp = *response; + if (resp == NULL) { + resp = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, + DYNAMIC_TYPE_OPENSSL); + if (resp == NULL) + return NULL; + XMEMSET(resp, 0, sizeof(OcspResponse)); + } + + resp->source = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (resp->source == NULL) { + XFREE(resp, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + resp->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (resp->status == NULL) { + XFREE(resp->source, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(resp, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + XMEMCPY(resp->source, *data, len); + resp->maxIdx = len; + + if (OcspResponseDecode(resp, NULL, NULL, 1) != 0) { + wolfSSL_OCSP_RESPONSE_free(resp); + return NULL; + } + + if (GetSequence(*data, &idx, &length, len) >= 0) + (*data) += idx + length; + + return resp; +} + +int wolfSSL_i2d_OCSP_RESPONSE(OcspResponse* response, + unsigned char** data) +{ + if (data == NULL) + return response->maxIdx; + + XMEMCPY(*data, response->source, response->maxIdx); + return response->maxIdx; +} + +int wolfSSL_OCSP_response_status(OcspResponse *response) +{ + return response->responseStatus; +} + +const char *wolfSSL_OCSP_response_status_str(long s) +{ + switch (s) { + case OCSP_SUCCESSFUL: + return "successful"; + case OCSP_MALFORMED_REQUEST: + return "malformedrequest"; + case OCSP_INTERNAL_ERROR: + return "internalerror"; + case OCSP_TRY_LATER: + return "trylater"; + case OCSP_SIG_REQUIRED: + return "sigrequired"; + case OCSP_UNAUTHROIZED: + return "unauthorized"; + default: + return "(UNKNOWN)"; + } +} + +WOLFSSL_OCSP_BASICRESP* wolfSSL_OCSP_response_get1_basic(OcspResponse* response) +{ + WOLFSSL_OCSP_BASICRESP* bs; + + bs = (WOLFSSL_OCSP_BASICRESP*)XMALLOC(sizeof(WOLFSSL_OCSP_BASICRESP), NULL, + DYNAMIC_TYPE_OPENSSL); + if (bs == NULL) + return NULL; + + XMEMCPY(bs, response, sizeof(OcspResponse)); + bs->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + bs->source = (byte*)XMALLOC(bs->maxIdx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (bs->status == NULL || bs->source == NULL) { + if (bs->status) XFREE(bs->status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (bs->source) XFREE(bs->source, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_OCSP_RESPONSE_free(bs); + bs = NULL; + } + else { + XMEMCPY(bs->status, response->status, sizeof(CertStatus)); + XMEMCPY(bs->source, response->source, response->maxIdx); + } + return bs; +} + +OcspRequest* wolfSSL_OCSP_REQUEST_new(void) +{ + OcspRequest* request; + + request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), NULL, + DYNAMIC_TYPE_OPENSSL); + if (request != NULL) + XMEMSET(request, 0, sizeof(OcspRequest)); + + return request; +} + +void wolfSSL_OCSP_REQUEST_free(OcspRequest* request) +{ + FreeOcspRequest(request); + XFREE(request, NULL, DYNAMIC_TYPE_OPENSSL); +} + +int wolfSSL_i2d_OCSP_REQUEST(OcspRequest* request, unsigned char** data) +{ + int size; + + size = EncodeOcspRequest(request, NULL, 0); + if (size <= 0 || data == NULL) + return size; + + return EncodeOcspRequest(request, *data, size); +} + +WOLFSSL_OCSP_ONEREQ* wolfSSL_OCSP_request_add0_id(OcspRequest *req, + WOLFSSL_OCSP_CERTID *cid) +{ + if (req == NULL || cid == NULL) + return NULL; + + FreeOcspRequest(req); + XMEMCPY(req, cid, sizeof(OcspRequest)); + + if (cid->serial != NULL) { + req->serial = (byte*)XMALLOC(cid->serialSz, NULL, + DYNAMIC_TYPE_OCSP_REQUEST); + req->url = (byte*)XMALLOC(cid->urlSz, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + if (req->serial == NULL || req->url == NULL) { + FreeOcspRequest(req); + return NULL; + } + + XMEMCPY(req->serial, cid->serial, cid->serialSz); + XMEMCPY(req->url, cid->url, cid->urlSz); + } + + wolfSSL_OCSP_REQUEST_free(cid); + + return req; +} + +WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_CERTID_dup(WOLFSSL_OCSP_CERTID* id) +{ + WOLFSSL_OCSP_CERTID* certId; + + if (id == NULL) { + return NULL; + } + + certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), + id->heap, DYNAMIC_TYPE_OPENSSL); + if (certId) { + XMEMCPY(certId, id, sizeof(WOLFSSL_OCSP_CERTID)); + } + return certId; +} +#endif + +#if defined(OPENSSL_ALL) || defined(APACHE_HTTPD) +int wolfSSL_i2d_OCSP_REQUEST_bio(WOLFSSL_BIO* out, + WOLFSSL_OCSP_REQUEST *req) +{ + int size = -1; + unsigned char* data = NULL; + + WOLFSSL_ENTER("wolfSSL_i2d_OCSP_REQUEST_bio"); + if (out == NULL || req == NULL) + return WOLFSSL_FAILURE; + + size = wolfSSL_i2d_OCSP_REQUEST(req, NULL); + if (size > 0) { + data = (unsigned char*) XMALLOC(size, out->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } + + if (data != NULL) { + size = wolfSSL_i2d_OCSP_REQUEST(req, &data); + } + + if (size <= 0) { + XFREE(data, out->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(out, data, size) == (int)size) { + XFREE(data, out->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } + + XFREE(data, out->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; +} +#endif /* OPENSSL_ALL || APACHE_HTTPD */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_WOLFSSL_STUB +int wolfSSL_OCSP_REQUEST_add_ext(OcspRequest* req, WOLFSSL_X509_EXTENSION* ext, + int idx) +{ + WOLFSSL_STUB("wolfSSL_OCSP_REQUEST_add_ext"); + (void)req; + (void)ext; + (void)idx; + return WOLFSSL_FATAL_ERROR; +} +#endif + +#ifndef NO_WOLFSSL_STUB +OcspResponse* wolfSSL_OCSP_response_create(int status, + WOLFSSL_OCSP_BASICRESP* bs) +{ + WOLFSSL_STUB("wolfSSL_OCSP_response_create"); + (void)status; + (void)bs; + return NULL; +} +#endif + +#ifndef NO_WOLFSSL_STUB +const char* wolfSSL_OCSP_crl_reason_str(long s) +{ + WOLFSSL_STUB("wolfSSL_OCSP_crl_reason_str"); + (void)s; + return NULL; +} +#endif + +/* Returns elements of an OCSP_CERTID struct. Currently only supports + * returning the serial number, and returns an error if user requests + * any of name, pmd, and/or keyHash. + * Return 1 on success, 0 on failure */ +int wolfSSL_OCSP_id_get0_info(WOLFSSL_ASN1_STRING **name, + WOLFSSL_ASN1_OBJECT **pmd, WOLFSSL_ASN1_STRING **keyHash, + WOLFSSL_ASN1_INTEGER **serial, WOLFSSL_OCSP_CERTID *cid) +{ + int i = 0; + WOLFSSL_ASN1_INTEGER* ser; + + WOLFSSL_ENTER("wolfSSL_OCSP_id_get0_info"); + + if (cid == NULL) + return 0; + + /* build up ASN1_INTEGER for serial */ + if (serial != NULL) { + ser = wolfSSL_ASN1_INTEGER_new(); + if (ser == NULL) + return 0; + + if (cid->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) { + /* allocate data buffer, +2 for type and length */ + ser->data = (unsigned char*)XMALLOC(cid->serialSz + 2, NULL, + DYNAMIC_TYPE_OPENSSL); + if (ser->data == NULL) { + wolfSSL_ASN1_INTEGER_free(ser); + return 0; + } + ser->dataMax = cid->serialSz + 2; + ser->isDynamic = 1; + } else { + /* Use array instead of dynamic memory */ + ser->data = ser->intData; + ser->dataMax = WOLFSSL_ASN1_INTEGER_MAX; + } + + #ifdef WOLFSSL_QT + /* Serial number starts at 0 index of ser->data */ + XMEMCPY(&ser->data[i], cid->serial, cid->serialSz); + ser->length = cid->serialSz; + #else + ser->data[i++] = ASN_INTEGER; + i += SetLength(cid->serialSz, ser->data + i); + XMEMCPY(&ser->data[i], cid->serial, cid->serialSz); + #endif + + cid->serialInt = ser; + *serial = cid->serialInt; + } + + /* Not needed for Apache, return error if user is requesting */ + if (name != NULL || pmd != NULL || keyHash != NULL) { + if (name != NULL) + *name = NULL; + + if (pmd != NULL) + *pmd = NULL; + + if (keyHash != NULL) + *keyHash = NULL; + return 0; + } + + return 1; +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_OCSP_request_add1_nonce(OcspRequest* req, unsigned char* val, + int sz) +{ + WOLFSSL_STUB("wolfSSL_OCSP_request_add1_nonce"); + (void)req; + (void)val; + (void)sz; + return WOLFSSL_FATAL_ERROR; +} +#endif + +/* Returns result of OCSP nonce comparison. Return values: + * 1 - nonces are both present and equal + * 2 - both nonces are absent + * 3 - nonce only present in response + * -1 - nonce only present in request + * 0 - both nonces present and equal + */ +int wolfSSL_OCSP_check_nonce(OcspRequest* req, WOLFSSL_OCSP_BASICRESP* bs) +{ + byte* reqNonce = NULL; + byte* rspNonce = NULL; + int reqNonceSz = 0; + int rspNonceSz = 0; + + WOLFSSL_ENTER("wolfSSL_OCSP_check_nonce"); + + if (req != NULL) { + reqNonce = req->nonce; + reqNonceSz = req->nonceSz; + } + + if (bs != NULL) { + rspNonce = bs->nonce; + rspNonceSz = bs->nonceSz; + } + + /* nonce absent in both req and rsp */ + if (reqNonce == NULL && rspNonce == NULL) + return 2; + + /* nonce present in rsp only */ + if (reqNonce == NULL && rspNonce != NULL) + return 3; + + /* nonce present in req only */ + if (reqNonce != NULL && rspNonce == NULL) + return -1; + + /* nonces are present and equal, return 1. Extra NULL check for fixing + scan-build warning. */ + if (reqNonceSz == rspNonceSz && reqNonce && rspNonce) { + if (XMEMCMP(reqNonce, rspNonce, reqNonceSz) == 0) + return 1; + } + + /* nonces are present but not equal */ + return 0; +} +#endif /* OPENSSL_EXTRA */ + +#else /* HAVE_OCSP */ + + +#ifdef _MSC_VER + /* 4206 warning for blank file */ + #pragma warning(disable: 4206) +#endif + + +#endif /* HAVE_OCSP */ +#endif /* WOLFCRYPT_ONLY */ diff --git a/client/wolfssl/src/sniffer.c b/client/wolfssl/src/sniffer.c new file mode 100644 index 0000000..9087148 --- /dev/null +++ b/client/wolfssl/src/sniffer.c @@ -0,0 +1,4611 @@ +/* sniffer.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY +#ifdef WOLFSSL_SNIFFER + +#include +#include + +#ifndef _WIN32 + #include +#else + #include +#endif + +#ifdef _WIN32 + #define SNPRINTF _snprintf +#else + #define SNPRINTF snprintf +#endif + +#include +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#ifdef WOLF_CRYPTO_CB + #include + #ifdef HAVE_INTEL_QA_SYNC + #include + #endif + #ifdef HAVE_CAVIUM_OCTEON_SYNC + #include + #endif +#endif + + +#ifndef WOLFSSL_SNIFFER_TIMEOUT + #define WOLFSSL_SNIFFER_TIMEOUT 900 + /* Cache unclosed Sessions for 15 minutes since last used */ +#endif + +/* Misc constants */ +enum { + MAX_SERVER_ADDRESS = 128, /* maximum server address length */ + MAX_SERVER_NAME = 128, /* maximum server name length */ + MAX_ERROR_LEN = 80, /* maximum error length */ + ETHER_IF_ADDR_LEN = 6, /* ethernet interface address length */ + LOCAL_IF_ADDR_LEN = 4, /* localhost interface address length, !windows */ + TCP_PROTO = 6, /* TCP_PROTOCOL */ + IP_HDR_SZ = 20, /* IPv4 header length, min */ + IP6_HDR_SZ = 40, /* IPv6 header length, min */ + TCP_HDR_SZ = 20, /* TCP header length, min */ + IPV4 = 4, /* IP version 4 */ + IPV6 = 6, /* IP version 6 */ + TCP_PROTOCOL = 6, /* TCP Protocol id */ + NO_NEXT_HEADER = 59, /* IPv6 no headers follow */ + TRACE_MSG_SZ = 80, /* Trace Message buffer size */ + HASH_SIZE = 499, /* Session Hash Table Rows */ + PSEUDO_HDR_SZ = 12, /* TCP Pseudo Header size in bytes */ + FATAL_ERROR_STATE = 1, /* SnifferSession fatal error state */ + TICKET_HINT_LEN = 4, /* Session Ticket Hint length */ + EXT_TYPE_SZ = 2, /* Extension length */ + MAX_INPUT_SZ = MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA + + MTU_EXTRA, /* Max input sz of reassembly */ + EXT_MASTER_SECRET = 0x17, /* Extended Master Secret Extension ID */ + TICKET_EXT_ID = 0x23 /* Session Ticket Extension ID */ +}; + + +#ifdef _WIN32 + +static HMODULE dllModule; /* for error string resources */ + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + static int didInit = 0; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + if (didInit == 0) { + dllModule = hModule; + ssl_InitSniffer(); + didInit = 1; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + if (didInit) { + ssl_FreeSniffer(); + didInit = 0; + } + break; + } + return TRUE; +} + +#endif /* _WIN32 */ + + +static WOLFSSL_GLOBAL int TraceOn = 0; /* Trace is off by default */ +static WOLFSSL_GLOBAL FILE* TraceFile = 0; + + +/* windows uses .rc table for this */ +#ifndef _WIN32 + +static const char* const msgTable[] = +{ + /* 1 */ + "Out of Memory", + "New SSL Sniffer Server Registered", + "Checking IP Header", + "SSL Sniffer Server Not Registered", + "Checking TCP Header", + + /* 6 */ + "SSL Sniffer Server Port Not Registered", + "RSA Private Decrypt Error", + "RSA Private Decode Error", + "Set Cipher Spec Error", + "Server Hello Input Malformed", + + /* 11 */ + "Couldn't Resume Session Error", + "Server Did Resumption", + "Client Hello Input Malformed", + "Client Trying to Resume", + "Handshake Input Malformed", + + /* 16 */ + "Got Hello Verify msg", + "Got Server Hello msg", + "Got Cert Request msg", + "Got Server Key Exchange msg", + "Got Cert msg", + + /* 21 */ + "Got Server Hello Done msg", + "Got Finished msg", + "Got Client Hello msg", + "Got Client Key Exchange msg", + "Got Cert Verify msg", + + /* 26 */ + "Got Unknown Handshake msg", + "New SSL Sniffer Session created", + "Couldn't create new SSL", + "Got a Packet to decode", + "No data present", + + /* 31 */ + "Session Not Found", + "Got an Old Client Hello msg", + "Old Client Hello Input Malformed", + "Old Client Hello OK", + "Bad Old Client Hello", + + /* 36 */ + "Bad Record Header", + "Record Header Input Malformed", + "Got a HandShake msg", + "Bad HandShake msg", + "Got a Change Cipher Spec msg", + + /* 41 */ + "Got Application Data msg", + "Bad Application Data", + "Got an Alert msg", + "Another msg to Process", + "Removing Session From Table", + + /* 46 */ + "Bad Key File", + "Wrong IP Version", + "Wrong Protocol type", + "Packet Short for header processing", + "Got Unknown Record Type", + + /* 51 */ + "Can't Open Trace File", + "Session in Fatal Error State", + "Partial SSL record received", + "Buffer Error, malformed input", + "Added to Partial Input", + + /* 56 */ + "Received a Duplicate Packet", + "Received an Out of Order Packet", + "Received an Overlap Duplicate Packet", + "Received an Overlap Reassembly Begin Duplicate Packet", + "Received an Overlap Reassembly End Duplicate Packet", + + /* 61 */ + "Missed the Client Hello Entirely", + "Got Hello Request msg", + "Got Session Ticket msg", + "Bad Input", + "Bad Decrypt Type", + + /* 66 */ + "Bad Finished Message Processing", + "Bad Compression Type", + "Bad DeriveKeys Error", + "Saw ACK for Missing Packet Error", + "Bad Decrypt Operation", + + /* 71 */ + "Decrypt Keys Not Set Up", + "Late Key Load Error", + "Got Certificate Status msg", + "RSA Key Missing Error", + "Secure Renegotiation Not Supported", + + /* 76 */ + "Get Session Stats Failure", + "Reassembly Buffer Size Exceeded", + "Dropping Lost Fragment", + "Dropping Partial Record", + "Clear ACK Fault", + + /* 81 */ + "Bad Decrypt Size", + "Extended Master Secret Hash Error", + "Handshake Message Split Across TLS Records", + "ECC Private Decode Error", + "ECC Public Decode Error", + + /* 86 */ + "Watch callback not set", + "Watch hash failed", + "Watch callback failed", + "Bad Certificate Message", + "Store data callback not set", + + /* 91 */ + "No data destination Error", + "Store data callback failed", + "Loading chain input" +}; + + +/* *nix version uses table above */ +static void GetError(int idx, char* str) +{ + XSTRNCPY(str, msgTable[idx - 1], MAX_ERROR_LEN-1); + str[MAX_ERROR_LEN-1] = '\0'; +} + + +#else /* _WIN32 */ + + +/* Windows version uses .rc table */ +static void GetError(int idx, char* buffer) +{ + if (!LoadStringA(dllModule, idx, buffer, MAX_ERROR_LEN)) + buffer[0] = 0; +} + + +#endif /* _WIN32 */ + + +/* Packet Buffer for reassembly list and ready list */ +typedef struct PacketBuffer { + word32 begin; /* relative sequence begin */ + word32 end; /* relative sequence end */ + byte* data; /* actual data */ + struct PacketBuffer* next; /* next on reassembly list or ready list */ +} PacketBuffer; + + +#ifdef HAVE_SNI + +/* NamedKey maps a SNI name to a specific private key */ +typedef struct NamedKey { + char name[MAX_SERVER_NAME]; /* server DNS name */ + word32 nameSz; /* size of server DNS name */ + byte* key; /* DER private key */ + word32 keySz; /* size of DER private key */ + struct NamedKey* next; /* for list */ +} NamedKey; + +#endif + + +typedef struct IpAddrInfo { + int version; + union { + word32 ip4; + byte ip6[16]; + }; +} IpAddrInfo; + + +/* Sniffer Server holds info for each server/port monitored */ +typedef struct SnifferServer { + SSL_CTX* ctx; /* SSL context */ + char address[MAX_SERVER_ADDRESS]; /* passed in server address */ + IpAddrInfo server; /* network order address */ + int port; /* server port */ +#ifdef HAVE_SNI + NamedKey* namedKeys; /* mapping of names and keys */ + wolfSSL_Mutex namedKeysMutex; /* mutex for namedKey list */ +#endif + struct SnifferServer* next; /* for list */ +} SnifferServer; + + +/* Session Flags */ +typedef struct Flags { + byte side; /* which end is current packet headed */ + byte serverCipherOn; /* indicates whether cipher is active */ + byte clientCipherOn; /* indicates whether cipher is active */ + byte resuming; /* did this session come from resumption */ + byte cached; /* have we cached this session yet */ + byte clientHello; /* processed client hello yet, for SSLv2 */ + byte finCount; /* get both FINs before removing */ + byte fatalError; /* fatal error state */ + byte cliAckFault; /* client acked unseen data from server */ + byte srvAckFault; /* server acked unseen data from client */ + byte cliSkipPartial; /* client skips partial data to catch up */ + byte srvSkipPartial; /* server skips partial data to catch up */ +#ifdef HAVE_EXTENDED_MASTER + byte expectEms; /* expect extended master secret */ +#endif +} Flags; + + +/* Out of Order FIN capture */ +typedef struct FinCaputre { + word32 cliFinSeq; /* client relative sequence FIN 0 is no */ + word32 srvFinSeq; /* server relative sequence FIN, 0 is no */ + byte cliCounted; /* did we count yet, detects duplicates */ + byte srvCounted; /* did we count yet, detects duplicates */ +} FinCaputre; + + +typedef struct HsHashes { +#ifndef NO_OLD_TLS +#ifndef NO_SHA + wc_Sha hashSha; +#endif +#ifndef NO_MD5 + wc_Md5 hashMd5; +#endif +#endif +#ifndef NO_SHA256 + wc_Sha256 hashSha256; +#endif +#ifdef WOLFSSL_SHA384 + wc_Sha384 hashSha384; +#endif +} HsHashes; + + +/* Sniffer Session holds info for each client/server SSL/TLS session */ +typedef struct SnifferSession { + SnifferServer* context; /* server context */ + SSL* sslServer; /* SSL server side decode */ + SSL* sslClient; /* SSL client side decode */ + IpAddrInfo server; /* server address in network byte order */ + IpAddrInfo client; /* client address in network byte order */ + word16 srvPort; /* server port */ + word16 cliPort; /* client port */ + word32 cliSeqStart; /* client start sequence */ + word32 srvSeqStart; /* server start sequence */ + word32 cliExpected; /* client expected sequence (relative) */ + word32 srvExpected; /* server expected sequence (relative) */ + FinCaputre finCaputre; /* retain out of order FIN s */ + Flags flags; /* session flags */ + time_t lastUsed; /* last used ticks */ + word32 keySz; /* size of the private key */ + PacketBuffer* cliReassemblyList; /* client out of order packets */ + PacketBuffer* srvReassemblyList; /* server out of order packets */ + word32 cliReassemblyMemory; /* client packet memory used */ + word32 srvReassemblyMemory; /* server packet memory used */ + struct SnifferSession* next; /* for hash table list */ + byte* ticketID; /* mac ID of session ticket */ +#ifdef HAVE_SNI + const char* sni; /* server name indication */ +#endif +#ifdef HAVE_EXTENDED_MASTER + HsHashes* hash; +#endif +} SnifferSession; + + +/* Sniffer Server List and mutex */ +static WOLFSSL_GLOBAL SnifferServer* ServerList = 0; +static WOLFSSL_GLOBAL wolfSSL_Mutex ServerListMutex; + + +/* Session Hash Table, mutex, and count */ +static WOLFSSL_GLOBAL SnifferSession* SessionTable[HASH_SIZE]; +static WOLFSSL_GLOBAL wolfSSL_Mutex SessionMutex; +static WOLFSSL_GLOBAL int SessionCount = 0; + +/* Recovery of missed data switches and stats */ +static WOLFSSL_GLOBAL wolfSSL_Mutex RecoveryMutex; /* for stats */ +static WOLFSSL_GLOBAL int RecoveryEnabled = 0; /* global switch */ +static WOLFSSL_GLOBAL int MaxRecoveryMemory = -1; + /* per session max recovery memory */ +static WOLFSSL_GLOBAL word32 MissedDataSessions = 0; + /* # of sessions with missed data */ + +/* Connection Info Callback */ +static WOLFSSL_GLOBAL SSLConnCb ConnectionCb; +static WOLFSSL_GLOBAL void* ConnectionCbCtx = NULL; + +#ifdef WOLFSSL_SNIFFER_STATS +/* Sessions Statistics */ +static WOLFSSL_GLOBAL SSLStats SnifferStats; +static WOLFSSL_GLOBAL wolfSSL_Mutex StatsMutex; +#endif + +#ifdef WOLFSSL_SNIFFER_WATCH +/* Watch Key Callback */ +static WOLFSSL_GLOBAL SSLWatchCb WatchCb; +static WOLFSSL_GLOBAL void* WatchCbCtx = NULL; +#endif + +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB +/* Store Data Callback */ +static WOLFSSL_GLOBAL SSLStoreDataCb StoreDataCb; +#endif + + +static void UpdateMissedDataSessions(void) +{ + wc_LockMutex(&RecoveryMutex); + MissedDataSessions += 1; + wc_UnLockMutex(&RecoveryMutex); +} + + +#ifdef WOLFSSL_SNIFFER_STATS +#define LOCK_STAT() do { wc_LockMutex(&StatsMutex); } while (0) +#define UNLOCK_STAT() do { wc_UnLockMutex(&StatsMutex); } while (0) +#define NOLOCK_ADD_TO_STAT(x,y) do { TraceStat(#x, y); x += y; } while (0) +#define NOLOCK_INC_STAT(x) NOLOCK_ADD_TO_STAT(x,1) +#define ADD_TO_STAT(x,y) do { LOCK_STAT(); \ + NOLOCK_ADD_TO_STAT(x,y); UNLOCK_STAT(); } while (0) +#define INC_STAT(x) do { LOCK_STAT(); \ + NOLOCK_INC_STAT(x); UNLOCK_STAT(); } while (0) +#endif + + +#ifdef WOLF_CRYPTO_CB + static WOLFSSL_GLOBAL int CryptoDeviceId = INVALID_DEVID; +#endif + + +/* Initialize overall Sniffer */ +void ssl_InitSniffer(void) +{ + wolfSSL_Init(); + wc_InitMutex(&ServerListMutex); + wc_InitMutex(&SessionMutex); + wc_InitMutex(&RecoveryMutex); +#ifdef WOLFSSL_SNIFFER_STATS + XMEMSET(&SnifferStats, 0, sizeof(SSLStats)); + wc_InitMutex(&StatsMutex); +#endif +#ifdef WOLF_CRYPTO_CB + #ifdef HAVE_INTEL_QA_SYNC + CryptoDeviceId = wc_CryptoCb_InitIntelQa(); + if (INVALID_DEVID == CryptoDeviceId) { + printf("Couldn't init the Intel QA\n"); + } + #endif + #ifdef HAVE_CAVIUM_OCTEON_SYNC + CryptoDeviceId = wc_CryptoCb_InitOcteon(); + if (INVALID_DEVID == CryptoDeviceId) { + printf("Couldn't init the Intel QA\n"); + } + #endif +#endif +} + + +#ifdef HAVE_SNI + +/* Free Named Key and the zero out the private key it holds */ +static void FreeNamedKey(NamedKey* in) +{ + if (in) { + if (in->key) { + ForceZero(in->key, in->keySz); + XFREE(in->key, NULL, DYNAMIC_TYPE_X509); + } + XFREE(in, NULL, DYNAMIC_TYPE_SNIFFER_NAMED_KEY); + } +} + + +static void FreeNamedKeyList(NamedKey* in) +{ + NamedKey* next; + + while (in) { + next = in->next; + FreeNamedKey(in); + in = next; + } +} + +#endif + + +/* Free Sniffer Server's resources/self */ +static void FreeSnifferServer(SnifferServer* srv) +{ + if (srv) { +#ifdef HAVE_SNI + wc_LockMutex(&srv->namedKeysMutex); + FreeNamedKeyList(srv->namedKeys); + wc_UnLockMutex(&srv->namedKeysMutex); + wc_FreeMutex(&srv->namedKeysMutex); +#endif + SSL_CTX_free(srv->ctx); + } + XFREE(srv, NULL, DYNAMIC_TYPE_SNIFFER_SERVER); +} + + +/* free PacketBuffer's resources/self */ +static void FreePacketBuffer(PacketBuffer* del) +{ + if (del) { + XFREE(del->data, NULL, DYNAMIC_TYPE_SNIFFER_PB_BUFFER); + XFREE(del, NULL, DYNAMIC_TYPE_SNIFFER_PB); + } +} + + +/* remove PacketBuffer List */ +static void FreePacketList(PacketBuffer* in) +{ + if (in) { + PacketBuffer* del; + PacketBuffer* packet = in; + + while (packet) { + del = packet; + packet = packet->next; + FreePacketBuffer(del); + } + } +} + + +/* Free Sniffer Session's resources/self */ +static void FreeSnifferSession(SnifferSession* session) +{ + if (session) { + SSL_free(session->sslClient); + SSL_free(session->sslServer); + + FreePacketList(session->cliReassemblyList); + FreePacketList(session->srvReassemblyList); + + XFREE(session->ticketID, NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID); +#ifdef HAVE_EXTENDED_MASTER + XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); +#endif + } + XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); +} + + +/* Free overall Sniffer */ +void ssl_FreeSniffer(void) +{ + SnifferServer* srv; + SnifferServer* removeServer; + SnifferSession* session; + SnifferSession* removeSession; + int i; + + wc_LockMutex(&ServerListMutex); + wc_LockMutex(&SessionMutex); + + srv = ServerList; + while (srv) { + removeServer = srv; + srv = srv->next; + FreeSnifferServer(removeServer); + } + + for (i = 0; i < HASH_SIZE; i++) { + session = SessionTable[i]; + while (session) { + removeSession = session; + session = session->next; + FreeSnifferSession(removeSession); + } + } + + wc_UnLockMutex(&SessionMutex); + wc_UnLockMutex(&ServerListMutex); + + wc_FreeMutex(&RecoveryMutex); + wc_FreeMutex(&SessionMutex); + wc_FreeMutex(&ServerListMutex); + +#ifdef WOLF_CRYPTO_CB +#ifdef HAVE_INTEL_QA_SYNC + wc_CryptoCb_CleanupIntelQa(&CryptoDeviceId); +#endif +#ifdef HAVE_CAVIUM_OCTEON_SYNC + wc_CryptoCb_CleanupOcteon(&CryptoDeviceId); +#endif +#endif + + if (TraceFile) { + TraceOn = 0; + fclose(TraceFile); + TraceFile = NULL; + } + + wolfSSL_Cleanup(); +} + + +#ifdef HAVE_EXTENDED_MASTER + +static int HashInit(HsHashes* hash) +{ + int ret = 0; + + XMEMSET(hash, 0, sizeof(HsHashes)); + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + if (ret == 0) + ret = wc_InitSha(&hash->hashSha); +#endif +#ifndef NO_MD5 + if (ret == 0) { + ret = wc_InitMd5(&hash->hashMd5); + } +#endif +#endif +#ifndef NO_SHA256 + if (ret == 0) + ret = wc_InitSha256(&hash->hashSha256); +#endif +#ifdef WOLFSSL_SHA384 + if (ret == 0) + ret = wc_InitSha384(&hash->hashSha384); +#endif + + return ret; +} + + +static int HashUpdate(HsHashes* hash, const byte* input, int sz) +{ + int ret = 0; + + input -= HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + if (ret == 0) + ret = wc_ShaUpdate(&hash->hashSha, input, sz); +#endif +#ifndef NO_MD5 + if (ret == 0) { + ret = wc_Md5Update(&hash->hashMd5, input, sz); + } +#endif +#endif +#ifndef NO_SHA256 + if (ret == 0) + ret = wc_Sha256Update(&hash->hashSha256, input, sz); +#endif +#ifdef WOLFSSL_SHA384 + if (ret == 0) + ret = wc_Sha384Update(&hash->hashSha384, input, sz); +#endif + + return ret; +} + + +static int HashCopy(HS_Hashes* d, HsHashes* s) +{ +#ifndef NO_OLD_TLS +#ifndef NO_SHA + XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha)); +#endif +#ifndef NO_MD5 + XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5)); +#endif +#endif + +#ifndef NO_SHA256 + XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256)); +#endif +#ifdef WOLFSSL_SHA384 + XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384)); +#endif + + return 0; +} + +#endif + + +/* Initialize a SnifferServer */ +static void InitSnifferServer(SnifferServer* sniffer) +{ + XMEMSET(sniffer, 0, sizeof(SnifferServer)); +} + + +/* Initialize session flags */ +static void InitFlags(Flags* flags) +{ + XMEMSET(flags, 0, sizeof(Flags)); +} + + +/* Initialize FIN Capture */ +static void InitFinCapture(FinCaputre* cap) +{ + XMEMSET(cap, 0, sizeof(FinCaputre)); +} + + +/* Initialize a Sniffer Session */ +static void InitSession(SnifferSession* session) +{ + XMEMSET(session, 0, sizeof(SnifferSession)); + InitFlags(&session->flags); + InitFinCapture(&session->finCaputre); +} + + +/* IP Info from IP Header */ +typedef struct IpInfo { + int length; /* length of this header */ + int total; /* total length of fragment */ + IpAddrInfo src; /* network order source address */ + IpAddrInfo dst; /* network order destination address */ +} IpInfo; + + +/* TCP Info from TCP Header */ +typedef struct TcpInfo { + int srcPort; /* source port */ + int dstPort; /* source port */ + int length; /* length of this header */ + word32 sequence; /* sequence number */ + word32 ackNumber; /* ack number */ + byte fin; /* FIN set */ + byte rst; /* RST set */ + byte syn; /* SYN set */ + byte ack; /* ACK set */ +} TcpInfo; + + +/* Tcp Pseudo Header for Checksum calculation */ +typedef struct TcpPseudoHdr { + word32 src; /* source address */ + word32 dst; /* destination address */ + byte rsv; /* reserved, always 0 */ + byte protocol; /* IP protocol */ + word16 length; /* tcp header length + data length (doesn't include */ + /* pseudo header length) network order */ +} TcpPseudoHdr; + + +/* Password Setting Callback */ +static int SetPassword(char* passwd, int sz, int rw, void* userdata) +{ + (void)rw; + XSTRNCPY(passwd, (const char*)userdata, sz); + return (int)XSTRLEN((const char*)userdata); +} + + +/* Ethernet Header */ +typedef struct EthernetHdr { + byte dst[ETHER_IF_ADDR_LEN]; /* destination host address */ + byte src[ETHER_IF_ADDR_LEN]; /* source host address */ + word16 type; /* IP, ARP, etc */ +} EthernetHdr; + + +/* IPv4 Header */ +typedef struct IpHdr { + byte ver_hl; /* version/header length */ + byte tos; /* type of service */ + word16 length; /* total length */ + word16 id; /* identification */ + word16 offset; /* fragment offset field */ + byte ttl; /* time to live */ + byte protocol; /* protocol */ + word16 sum; /* checksum */ + word32 src; /* source address */ + word32 dst; /* destination address */ +} IpHdr; + + +/* IPv6 Header */ +typedef struct Ip6Hdr { + byte ver_hl; /* version/traffic class high */ + byte tc_fl; /* traffic class low/flow label high */ + word16 fl; /* flow label low */ + word16 length; /* payload length */ + byte next_header; /* next header (6 for TCP, any other skip) */ + byte hl; /* hop limit */ + byte src[16]; /* source address */ + byte dst[16]; /* destination address */ +} Ip6Hdr; + + +/* IPv6 extension header */ +typedef struct Ip6ExtHdr { + byte next_header; /* next header (6 for TCP, any other skip) */ + byte length; /* length in 8-octet units - 1 */ + byte reserved[6]; +} Ip6ExtHdr; + + +#define IP_HL(ip) ( (((ip)->ver_hl) & 0x0f) * 4) +#define IP_V(ip) ( ((ip)->ver_hl) >> 4) + +/* TCP Header */ +typedef struct TcpHdr { + word16 srcPort; /* source port */ + word16 dstPort; /* destination port */ + word32 sequence; /* sequence number */ + word32 ack; /* acknowledgment number */ + byte offset; /* data offset, reserved */ + byte flags; /* option flags */ + word16 window; /* window */ + word16 sum; /* checksum */ + word16 urgent; /* urgent pointer */ +} TcpHdr; + +#define TCP_LEN(tcp) ( (((tcp)->offset & 0xf0) >> 4) * 4) +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_ACK 0x10 + + + + + +/* Use platform specific GetError to write to trace file if tracing */ +static void Trace(int idx) +{ + if (TraceOn) { + char myBuffer[MAX_ERROR_LEN]; + GetError(idx, myBuffer); + fprintf(TraceFile, "\t%s\n", myBuffer); +#ifdef DEBUG_SNIFFER + fprintf(stderr, "\t%s\n", myBuffer); +#endif + } +} + + +/* Show TimeStamp for beginning of packet Trace */ +static void TraceHeader(void) +{ + if (TraceOn) { + time_t ticks = time(NULL); + fprintf(TraceFile, "\n%s", ctime(&ticks)); + } +} + + +/* Show Set Server info for Trace */ +static void TraceSetServer(const char* srv, int port, const char* keyFile) +{ + if (TraceOn) { + fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n"); + fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port, + keyFile); + } +} + + +#ifdef HAVE_SNI + +/* Show Set Named Server info for Trace */ +static void TraceSetNamedServer(const char* name, + const char* srv, int port, const char* keyFile) +{ + if (TraceOn) { + fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n"); + fprintf(TraceFile, "\tname: %s, server: %s, port: %d, keyFile: %s\n", + name, srv, port, keyFile); + } +} + +#endif + + +/* Trace got packet number */ +static void TracePacket(void) +{ + if (TraceOn) { + static word32 packetNumber = 0; + fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n", + ++packetNumber); + } +} + + +/* Convert network byte order address into human readable */ +static const char* IpToS(int version, void* src, char* dst) +{ + return inet_ntop(version, src, dst, TRACE_MSG_SZ); +} + + +/* Show destination and source address from Ip Hdr for packet Trace */ +static void TraceIP(IpHdr* iphdr) +{ + if (TraceOn) { + char src[TRACE_MSG_SZ]; + char dst[TRACE_MSG_SZ]; + fprintf(TraceFile, "\tdst:%s src:%s\n", + IpToS(AF_INET, &iphdr->dst, dst), + IpToS(AF_INET, &iphdr->src, src)); + } +} + + +/* Show destination and source address from Ip6Hdr for packet Trace */ +static void TraceIP6(Ip6Hdr* iphdr) +{ + if (TraceOn) { + char src[TRACE_MSG_SZ]; + char dst[TRACE_MSG_SZ]; + fprintf(TraceFile, "\tdst: %s src: %s\n", + IpToS(AF_INET6, iphdr->dst, dst), + IpToS(AF_INET6, iphdr->src, src)); + } +} + + +/* Show destination and source port from Tcp Hdr for packet Trace */ +static void TraceTcp(TcpHdr* tcphdr) +{ + if (TraceOn) { + fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort), + ntohs(tcphdr->srcPort)); + } +} + + +/* Show sequence and payload length for Trace */ +static void TraceSequence(word32 seq, int len) +{ + if (TraceOn) { + fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len); + } +} + + +/* Show sequence and payload length for Trace */ +static void TraceAck(word32 ack, word32 expected) +{ + if (TraceOn) { + fprintf(TraceFile, "\tAck:%u Expected:%u\n", ack, expected); + } +} + + +/* Show relative expected and relative received sequences */ +static void TraceRelativeSequence(word32 expected, word32 got) +{ + if (TraceOn) { + fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n", + expected, got); + } +} + + +/* Show server sequence startup from SYN */ +static void TraceServerSyn(word32 seq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq); + } +} + + +/* Show client sequence startup from SYN */ +static void TraceClientSyn(word32 seq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq); + } +} + + +/* Show client FIN capture */ +static void TraceClientFin(word32 finSeq, word32 relSeq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n", + finSeq, relSeq); + } +} + + +/* Show server FIN capture */ +static void TraceServerFin(word32 finSeq, word32 relSeq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n", + finSeq, relSeq); + } +} + + +/* Show number of SSL data bytes decoded, could be 0 (ok) */ +static void TraceGotData(int bytes) +{ + if (TraceOn) { + fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes); + } +} + + +/* Show bytes added to old SSL App data */ +static void TraceAddedData(int newBytes, int existingBytes) +{ + if (TraceOn) { + fprintf(TraceFile, + "\t%d bytes added to %d existing bytes in User Buffer\n", + newBytes, existingBytes); + } +} + + +/* Show Stale Session */ +static void TraceStaleSession(void) +{ + if (TraceOn) { + fprintf(TraceFile, "\tFound a stale session\n"); + } +} + + +/* Show Finding Stale Sessions */ +static void TraceFindingStale(void) +{ + if (TraceOn) { + fprintf(TraceFile, "\tTrying to find Stale Sessions\n"); + } +} + + +/* Show Removed Session */ +static void TraceRemovedSession(void) +{ + if (TraceOn) { + fprintf(TraceFile, "\tRemoved it\n"); + } +} + + +/* Show SSLInfo if provided and is valid. */ +static void TraceSessionInfo(SSLInfo* sslInfo) +{ + if (TraceOn) { + if (sslInfo != NULL && sslInfo->isValid) { + fprintf(TraceFile, + "\tver:(%u %u) suiteId:(%02x %02x) suiteName:(%s) " + #ifdef HAVE_SNI + "sni:(%s) " + #endif + "keySize:(%u)\n", + sslInfo->protocolVersionMajor, + sslInfo->protocolVersionMinor, + sslInfo->serverCipherSuite0, + sslInfo->serverCipherSuite, + sslInfo->serverCipherSuiteName, + #ifdef HAVE_SNI + sslInfo->serverNameIndication, + #endif + sslInfo->keySize); + } + } +} + + +#ifdef WOLFSSL_SNIFFER_STATS + +/* Show value added to a named statistic. */ +static void TraceStat(const char* name, int add) +{ + if (TraceOn) { + fprintf(TraceFile, "\tAdding %d to %s\n", add, name); + } +} + +#endif + + +/* Set user error string */ +static void SetError(int idx, char* error, SnifferSession* session, int fatal) +{ + GetError(idx, error); + Trace(idx); + if (session && fatal == FATAL_ERROR_STATE) + session->flags.fatalError = 1; +} + + +/* Compare IpAddrInfo structs */ +static WC_INLINE int MatchAddr(IpAddrInfo l, IpAddrInfo r) +{ + if (l.version == r.version) { + if (l.version == IPV4) + return (l.ip4 == r.ip4); + else if (l.version == IPV6) + return (0 == XMEMCMP(l.ip6, r.ip6, sizeof(l.ip6))); + } + return 0; +} + + +#ifndef WOLFSSL_SNIFFER_WATCH + +/* See if this IPV4 network order address has been registered */ +/* return 1 is true, 0 is false */ +static int IsServerRegistered(word32 addr) +{ + int ret = 0; /* false */ + SnifferServer* sniffer; + + wc_LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (sniffer->server.ip4 == addr) { + ret = 1; + break; + } + sniffer = sniffer->next; + } + + wc_UnLockMutex(&ServerListMutex); + + return ret; +} + + +/* See if this port has been registered to watch */ +/* See if this IPV4 network order address has been registered */ +/* return 1 is true, 0 is false */ +static int IsServerRegistered6(byte* addr) +{ + int ret = 0; /* false */ + SnifferServer* sniffer; + + wc_LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (sniffer->server.version == IPV6 && + 0 == XMEMCMP(sniffer->server.ip6, addr, sizeof(sniffer->server.ip6))) { + ret = 1; + break; + } + sniffer = sniffer->next; + } + + wc_UnLockMutex(&ServerListMutex); + + return ret; +} + + +/* See if this port has been registered to watch */ +/* return 1 is true, 0 is false */ +static int IsPortRegistered(word32 port) +{ + int ret = 0; /* false */ + SnifferServer* sniffer; + + wc_LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (sniffer->port == (int)port) { + ret = 1; + break; + } + sniffer = sniffer->next; + } + + wc_UnLockMutex(&ServerListMutex); + + return ret; +} + +#endif + + +/* Get SnifferServer from IP and Port */ +static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo) +{ + SnifferServer* sniffer; + + wc_LockMutex(&ServerListMutex); + + sniffer = ServerList; + +#ifndef WOLFSSL_SNIFFER_WATCH + while (sniffer) { + if (sniffer->port == tcpInfo->srcPort && + MatchAddr(sniffer->server, ipInfo->src)) + break; + if (sniffer->port == tcpInfo->dstPort && + MatchAddr(sniffer->server, ipInfo->dst)) + break; + + sniffer = sniffer->next; + } +#else + (void)ipInfo; + (void)tcpInfo; +#endif + + wc_UnLockMutex(&ServerListMutex); + + return sniffer; +} + + +/* Hash the Session Info, return hash row */ +static word32 SessionHash(IpInfo* ipInfo, TcpInfo* tcpInfo) +{ + word32 hash = 1; + + if (ipInfo->src.version == IPV4) { + hash *= ipInfo->src.ip4 * ipInfo->dst.ip4; + } + else if (ipInfo->src.version == IPV6) { + word32* x; + word32 y; + x = (word32*)ipInfo->src.ip6; + y = x[0] ^ x[1] ^ x[2] ^ x[3]; + hash *= y; + x = (word32*)ipInfo->dst.ip6; + y = x[0] ^ x[1] ^ x[2] ^ x[3]; + hash *= y; + } + hash *= tcpInfo->srcPort * tcpInfo->dstPort; + + return hash % HASH_SIZE; +} + + +/* Get Existing SnifferSession from IP and Port */ +static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo) +{ + SnifferSession* session; + time_t currTime = time(NULL); + word32 row = SessionHash(ipInfo, tcpInfo); + + assert(row <= HASH_SIZE); + + wc_LockMutex(&SessionMutex); + + session = SessionTable[row]; + while (session) { + if (MatchAddr(session->server, ipInfo->src) && + MatchAddr(session->client, ipInfo->dst) && + session->srvPort == tcpInfo->srcPort && + session->cliPort == tcpInfo->dstPort) + break; + + if (MatchAddr(session->client, ipInfo->src) && + MatchAddr(session->server, ipInfo->dst) && + session->cliPort == tcpInfo->srcPort && + session->srvPort == tcpInfo->dstPort) + break; + + session = session->next; + } + + if (session) + session->lastUsed= currTime; /* keep session alive, remove stale will */ + /* leave alone */ + wc_UnLockMutex(&SessionMutex); + + /* determine side */ + if (session) { + if (MatchAddr(ipInfo->dst, session->server) && + tcpInfo->dstPort == session->srvPort) { + + session->flags.side = WOLFSSL_SERVER_END; + } + else { + session->flags.side = WOLFSSL_CLIENT_END; + } + } + + return session; +} + + +#if defined(HAVE_SNI) || defined(WOLFSSL_SNIFFER_WATCH) + +static int LoadKeyFile(byte** keyBuf, word32* keyBufSz, + const char* keyFile, int typeKey, + const char* password) +{ + byte* loadBuf; + long fileSz = 0; + XFILE file; + int ret; + + if (keyBuf == NULL || keyBufSz == NULL || keyFile == NULL) { + return -1; + } + + file = XFOPEN(keyFile, "rb"); + if (file == XBADFILE) return -1; + if(XFSEEK(file, 0, XSEEK_END) != 0) { + XFCLOSE(file); + return -1; + } + fileSz = XFTELL(file); + if (fileSz > MAX_WOLFSSL_FILE_SIZE || fileSz < 0) { + XFCLOSE(file); + return -1; + } + XREWIND(file); + + loadBuf = (byte*)XMALLOC(fileSz, NULL, DYNAMIC_TYPE_FILE); + if (loadBuf == NULL) { + XFCLOSE(file); + return -1; + } + + ret = (int)XFREAD(loadBuf, 1, fileSz, file); + XFCLOSE(file); + + if (ret != fileSz) { + XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE); + return -1; + } + + if (typeKey == WOLFSSL_FILETYPE_PEM) { + byte* saveBuf = (byte*)XMALLOC(fileSz, NULL, DYNAMIC_TYPE_X509); + int saveBufSz = 0; + + ret = -1; + if (saveBuf != NULL) { + saveBufSz = wc_KeyPemToDer(loadBuf, (int)fileSz, + saveBuf, (int)fileSz, password); + if (saveBufSz < 0) { + saveBufSz = 0; + XFREE(saveBuf, NULL, DYNAMIC_TYPE_X509); + saveBuf = NULL; + } + else + ret = 0; + } + + ForceZero(loadBuf, (word32)fileSz); + XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE); + + if (saveBuf) { + *keyBuf = saveBuf; + *keyBufSz = (word32)saveBufSz; + } + } + else { + *keyBuf = loadBuf; + *keyBufSz = (word32)fileSz; + } + + if (ret < 0) { + return -1; + } + + return ret; +} + +#endif + + +#ifdef WOLFSSL_SNIFFER_WATCH + +static int CreateWatchSnifferServer(char* error) +{ + SnifferServer* sniffer; + + sniffer = (SnifferServer*)XMALLOC(sizeof(SnifferServer), NULL, + DYNAMIC_TYPE_SNIFFER_SERVER); + if (sniffer == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + return -1; + } + InitSnifferServer(sniffer); + sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); + if (!sniffer->ctx) { + SetError(MEMORY_STR, error, NULL, 0); + FreeSnifferServer(sniffer); + return -1; + } +#ifdef WOLF_CRYPTO_CB + if (CryptoDeviceId != INVALID_DEVID) + wolfSSL_CTX_SetDevId(sniffer->ctx, CryptoDeviceId); +#endif + ServerList = sniffer; + + return 0; +} + +#endif + + +static int SetNamedPrivateKey(const char* name, const char* address, int port, + const char* keyFile, int typeKey, const char* password, char* error) +{ + SnifferServer* sniffer; + int ret; + int type = (typeKey == FILETYPE_PEM) ? WOLFSSL_FILETYPE_PEM : + WOLFSSL_FILETYPE_ASN1; + int isNew = 0; + IpAddrInfo serverIp; + +#ifdef HAVE_SNI + NamedKey* namedKey = NULL; +#endif + + (void)name; +#ifdef HAVE_SNI + if (name != NULL) { + namedKey = (NamedKey*)XMALLOC(sizeof(NamedKey), + NULL, DYNAMIC_TYPE_SNIFFER_NAMED_KEY); + if (namedKey == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + return -1; + } + XMEMSET(namedKey, 0, sizeof(NamedKey)); + + namedKey->nameSz = (word32)XSTRLEN(name); + if (namedKey->nameSz > sizeof(namedKey->name)-1) + namedKey->nameSz = sizeof(namedKey->name)-1; + XSTRNCPY(namedKey->name, name, namedKey->nameSz); + namedKey->name[MAX_SERVER_NAME-1] = '\0'; + + ret = LoadKeyFile(&namedKey->key, &namedKey->keySz, + keyFile, type, password); + if (ret < 0) { + SetError(KEY_FILE_STR, error, NULL, 0); + FreeNamedKey(namedKey); + return -1; + } + } +#endif + + serverIp.version = IPV4; + serverIp.ip4 = inet_addr(address); + if (serverIp.ip4 == INADDR_NONE) { + if (inet_pton(AF_INET6, address, serverIp.ip6) == 1) { + serverIp.version = IPV6; + } + } + sniffer = ServerList; + while (sniffer != NULL && + (!MatchAddr(sniffer->server, serverIp) || sniffer->port != port)) { + sniffer = sniffer->next; + } + + if (sniffer == NULL) { + isNew = 1; + sniffer = (SnifferServer*)XMALLOC(sizeof(SnifferServer), + NULL, DYNAMIC_TYPE_SNIFFER_SERVER); + if (sniffer == NULL) { + SetError(MEMORY_STR, error, NULL, 0); +#ifdef HAVE_SNI + FreeNamedKey(namedKey); +#endif + return -1; + } + InitSnifferServer(sniffer); + + XSTRNCPY(sniffer->address, address, MAX_SERVER_ADDRESS-1); + sniffer->address[MAX_SERVER_ADDRESS-1] = '\0'; + sniffer->server = serverIp; + sniffer->port = port; + + sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); + if (!sniffer->ctx) { + SetError(MEMORY_STR, error, NULL, 0); +#ifdef HAVE_SNI + FreeNamedKey(namedKey); +#endif + FreeSnifferServer(sniffer); + return -1; + } + } + + if (name == NULL) { + if (password) { + #ifdef WOLFSSL_ENCRYPTED_KEYS + SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword); + SSL_CTX_set_default_passwd_cb_userdata( + sniffer->ctx, (void*)password); + #endif + } + ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); + if (ret != WOLFSSL_SUCCESS) { + SetError(KEY_FILE_STR, error, NULL, 0); + if (isNew) + FreeSnifferServer(sniffer); + return -1; + } + #ifdef WOLF_CRYPTO_CB + wolfSSL_CTX_SetDevId(sniffer->ctx, CryptoDeviceId); + #endif + } +#ifdef HAVE_SNI + else { + wc_LockMutex(&sniffer->namedKeysMutex); + namedKey->next = sniffer->namedKeys; + sniffer->namedKeys = namedKey; + wc_UnLockMutex(&sniffer->namedKeysMutex); + } +#endif + + if (isNew) { + sniffer->next = ServerList; + ServerList = sniffer; + } + + return 0; +} + + +#ifdef HAVE_SNI + +/* Sets the private key for a specific name, server and port */ +/* returns 0 on success, -1 on error */ +int ssl_SetNamedPrivateKey(const char* name, + const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error) +{ + int ret; + + TraceHeader(); + TraceSetNamedServer(name, address, port, keyFile); + + wc_LockMutex(&ServerListMutex); + ret = SetNamedPrivateKey(name, address, port, keyFile, + typeKey, password, error); + wc_UnLockMutex(&ServerListMutex); + + if (ret == 0) + Trace(NEW_SERVER_STR); + + return ret; +} + +#endif + + +/* Sets the private key for a specific server and port */ +/* returns 0 on success, -1 on error */ +int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, + int typeKey, const char* password, char* error) +{ + int ret; + + TraceHeader(); + TraceSetServer(address, port, keyFile); + + wc_LockMutex(&ServerListMutex); + ret = SetNamedPrivateKey(NULL, address, port, keyFile, + typeKey, password, error); + wc_UnLockMutex(&ServerListMutex); + + if (ret == 0) + Trace(NEW_SERVER_STR); + + return ret; +} + + +/* Check IP Header for IPV6, TCP, and a registered server address */ +/* returns 0 on success, -1 on error */ +static int CheckIp6Hdr(Ip6Hdr* iphdr, IpInfo* info, int length, char* error) +{ + int version = IP_V(iphdr); + int exthdrsz = IP6_HDR_SZ; + + TraceIP6(iphdr); + Trace(IP_CHECK_STR); + + if (version != IPV6) { + SetError(BAD_IPVER_STR, error, NULL, 0); + return -1; + } + + /* Here, we need to move onto next header if not TCP. */ + if (iphdr->next_header != TCP_PROTOCOL) { + Ip6ExtHdr* exthdr = (Ip6ExtHdr*)((byte*)iphdr + IP6_HDR_SZ); + do { + int hdrsz = (exthdr->length + 1) * 8; + if (hdrsz > length - exthdrsz) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + exthdrsz += hdrsz; + exthdr = (Ip6ExtHdr*)((byte*)exthdr + hdrsz); + } + while (exthdr->next_header != TCP_PROTOCOL && + exthdr->next_header != NO_NEXT_HEADER); + } + +#ifndef WOLFSSL_SNIFFER_WATCH + if (!IsServerRegistered6(iphdr->src) && !IsServerRegistered6(iphdr->dst)) { + SetError(SERVER_NOT_REG_STR, error, NULL, 0); + return -1; + } +#endif + + info->length = exthdrsz; + info->total = ntohs(iphdr->length) + info->length; + /* IPv6 doesn't include its own header size in the length like v4. */ + info->src.version = IPV6; + XMEMCPY(info->src.ip6, iphdr->src, sizeof(info->src.ip6)); + info->dst.version = IPV6; + XMEMCPY(info->dst.ip6, iphdr->dst, sizeof(info->dst.ip6)); + + return 0; +} + + +/* Check IP Header for IPV4, TCP, and a registered server address */ +/* If header IPv6, pass to CheckIp6Hdr(). */ +/* returns 0 on success, -1 on error */ +static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error) +{ + int version = IP_V(iphdr); + + if (version == IPV6) + return CheckIp6Hdr((Ip6Hdr*)iphdr, info, length, error); + + TraceIP(iphdr); + Trace(IP_CHECK_STR); + + if (version != IPV4) { + SetError(BAD_IPVER_STR, error, NULL, 0); + return -1; + } + + if (iphdr->protocol != TCP_PROTOCOL) { + SetError(BAD_PROTO_STR, error, NULL, 0); + return -1; + } + +#ifndef WOLFSSL_SNIFFER_WATCH + if (!IsServerRegistered(iphdr->src) && !IsServerRegistered(iphdr->dst)) { + SetError(SERVER_NOT_REG_STR, error, NULL, 0); + return -1; + } +#endif + + info->length = IP_HL(iphdr); + info->total = ntohs(iphdr->length); + info->src.version = IPV4; + info->src.ip4 = iphdr->src; + info->dst.version = IPV4; + info->dst.ip4 = iphdr->dst; + + if (info->total == 0) + info->total = length; /* reassembled may be off */ + + return 0; +} + + +/* Check TCP Header for a registered port */ +/* returns 0 on success, -1 on error */ +static int CheckTcpHdr(TcpHdr* tcphdr, TcpInfo* info, char* error) +{ + TraceTcp(tcphdr); + Trace(TCP_CHECK_STR); + info->srcPort = ntohs(tcphdr->srcPort); + info->dstPort = ntohs(tcphdr->dstPort); + info->length = TCP_LEN(tcphdr); + info->sequence = ntohl(tcphdr->sequence); + info->fin = tcphdr->flags & TCP_FIN; + info->rst = tcphdr->flags & TCP_RST; + info->syn = tcphdr->flags & TCP_SYN; + info->ack = tcphdr->flags & TCP_ACK; + if (info->ack) + info->ackNumber = ntohl(tcphdr->ack); + +#ifndef WOLFSSL_SNIFFER_WATCH + if (!IsPortRegistered(info->srcPort) && !IsPortRegistered(info->dstPort)) { + SetError(SERVER_PORT_NOT_REG_STR, error, NULL, 0); + return -1; + } +#else + (void)error; +#endif + + return 0; +} + + +/* Decode Record Layer Header */ +static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size) +{ + XMEMCPY(rh, input, RECORD_HEADER_SZ); + *size = (rh->length[0] << 8) | rh->length[1]; + + if (*size > (MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA)) + return LENGTH_ERROR; + + return 0; +} + + +/* Copies the session's information to the provided sslInfo. Skip copy if + * SSLInfo is not provided. */ +static void CopySessionInfo(SnifferSession* session, SSLInfo* sslInfo) +{ + if (NULL != sslInfo) { + XMEMSET(sslInfo, 0, sizeof(SSLInfo)); + + /* Pass back Session Info after we have processed the Server Hello. */ + if (0 != session->sslServer->options.cipherSuite) { + const char* pCipher; + + sslInfo->isValid = 1; + sslInfo->protocolVersionMajor = session->sslServer->version.major; + sslInfo->protocolVersionMinor = session->sslServer->version.minor; + sslInfo->serverCipherSuite0 = + session->sslServer->options.cipherSuite0; + sslInfo->serverCipherSuite = + session->sslServer->options.cipherSuite; + + pCipher = wolfSSL_get_cipher(session->sslServer); + if (NULL != pCipher) { + XSTRNCPY((char*)sslInfo->serverCipherSuiteName, pCipher, + sizeof(sslInfo->serverCipherSuiteName)); + sslInfo->serverCipherSuiteName + [sizeof(sslInfo->serverCipherSuiteName) - 1] = '\0'; + } + sslInfo->keySize = session->keySz; + #ifdef HAVE_SNI + if (NULL != session->sni) { + XSTRNCPY((char*)sslInfo->serverNameIndication, + session->sni, sizeof(sslInfo->serverNameIndication)); + sslInfo->serverNameIndication + [sizeof(sslInfo->serverNameIndication) - 1] = '\0'; + } + #endif + TraceSessionInfo(sslInfo); + } + } +} + + +/* Call the session connection start callback. */ +static void CallConnectionCb(SnifferSession* session) +{ + if (ConnectionCb != NULL) { + SSLInfo info; + CopySessionInfo(session, &info); + ConnectionCb((const void*)session, &info, ConnectionCbCtx); + } +} + + +/* Process Client Key Exchange, RSA or static ECDH */ +static int ProcessClientKeyExchange(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + word32 idx = 0; + int tryEcc = 0; + int ret; + + if (session->sslServer->buffers.key == NULL || + session->sslServer->buffers.key->buffer == NULL || + session->sslServer->buffers.key->length == 0) { + + SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + { + RsaKey key; + int length; + + ret = wc_InitRsaKey(&key, 0); + if (ret == 0) { + ret = wc_RsaPrivateKeyDecode( + session->sslServer->buffers.key->buffer, + &idx, &key, session->sslServer->buffers.key->length); + if (ret != 0) { + tryEcc = 1; + #ifndef HAVE_ECC + SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); + #else + /* If we can do ECC, this isn't fatal. Not loading an ECC + * key will be fatal, though. */ + SetError(RSA_DECODE_STR, error, session, 0); + #endif + } + } + + if (ret == 0) { + length = wc_RsaEncryptSize(&key); + if (IsTLS(session->sslServer)) { + input += 2; /* tls pre length */ + } + + if (length > *sslBytes) { + SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE); + ret = -1; + } + } + + #ifdef WC_RSA_BLINDING + if (ret == 0) { + ret = wc_RsaSetRNG(&key, session->sslServer->rng); + if (ret != 0) { + SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); + } + } + #endif + + if (ret == 0) { + session->keySz = length * WOLFSSL_BIT_SIZE; + /* length is the key size in bytes */ + session->sslServer->arrays->preMasterSz = SECRET_LEN; + + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &key.asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) { + ret = wc_RsaPrivateDecrypt(input, length, + session->sslServer->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSz, &key); + } + } while (ret == WC_PENDING_E); + + if (ret != SECRET_LEN) { + SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); + } + } + + wc_FreeRsaKey(&key); + } + + if (tryEcc) { +#ifdef HAVE_ECC + ecc_key key; + ecc_key pubKey; + int length, keyInit = 0, pubKeyInit = 0; + + idx = 0; + ret = wc_ecc_init(&key); + if (ret == 0) { + keyInit = 1; + ret = wc_ecc_init(&pubKey); + } + if (ret == 0) { + pubKeyInit = 1; + ret = wc_EccPrivateKeyDecode( + session->sslServer->buffers.key->buffer, + &idx, &key, session->sslServer->buffers.key->length); + if (ret != 0) { + SetError(ECC_DECODE_STR, error, session, FATAL_ERROR_STATE); + } + } + + if (ret == 0) { + length = wc_ecc_size(&key) * 2 + 1; + /* The length should be 2 times the key size (x and y), plus 1 + * for the type byte. */ + if (IsTLS(session->sslServer)) { + input += 1; /* Don't include the TLS length for the key. */ + } + + if (length + 1 > *sslBytes) { + SetError(PARTIAL_INPUT_STR, + error, session, FATAL_ERROR_STATE); + ret = -1; + } + } + + if (ret == 0) { + ret = wc_ecc_import_x963_ex(input, length, &pubKey, ECC_CURVE_DEF); + if (ret != 0) { + SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE); + } + } + + if (ret == 0) { + session->keySz = ((length - 1) / 2) * WOLFSSL_BIT_SIZE; + /* Length is in bytes. Subtract 1 for the ECC key type. Divide + * by two as the key is in (x,y) coordinates, where x and y are + * the same size, the key size. Convert from bytes to bits. */ + session->sslServer->arrays->preMasterSz = ENCRYPT_LEN; + + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &key.asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) { + ret = wc_ecc_shared_secret(&key, &pubKey, + session->sslServer->arrays->preMasterSecret, + &session->sslServer->arrays->preMasterSz); + } + } while (ret == WC_PENDING_E); + } + +#ifdef WOLFSSL_SNIFFER_STATS + if (ret != 0) + INC_STAT(SnifferStats.sslKeyFails); +#endif + + if (keyInit) + wc_ecc_free(&key); + if (pubKeyInit) + wc_ecc_free(&pubKey); +#endif + } + + /* store for client side as well */ + XMEMCPY(session->sslClient->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSz); + session->sslClient->arrays->preMasterSz = + session->sslServer->arrays->preMasterSz; + + #ifdef SHOW_SECRETS + { + word32 i; + printf("pre master secret: "); + for (i = 0; i < session->sslServer->arrays->preMasterSz; i++) + printf("%02x", session->sslServer->arrays->preMasterSecret[i]); + printf("\n"); + } + #endif + + if (SetCipherSpecs(session->sslServer) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (SetCipherSpecs(session->sslClient) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + ret = MakeMasterSecret(session->sslServer); + ret += MakeMasterSecret(session->sslClient); + ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); + ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); + + if (ret != 0) { + SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + +#ifdef SHOW_SECRETS + { + int i; + printf("server master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslServer->arrays->masterSecret[i]); + printf("\n"); + + printf("client master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslClient->arrays->masterSecret[i]); + printf("\n"); + + printf("server suite = %d\n", session->sslServer->options.cipherSuite); + printf("client suite = %d\n", session->sslClient->options.cipherSuite); + } +#endif + + CallConnectionCb(session); + + return ret; +} + + +/* Process Session Ticket */ +static int ProcessSessionTicket(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + word16 len; + + /* make sure can read through hint and len */ + if (TICKET_HINT_LEN + LENGTH_SZ > *sslBytes) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + input += TICKET_HINT_LEN; /* skip over hint */ + *sslBytes -= TICKET_HINT_LEN; + + len = (word16)((input[0] << 8) | input[1]); + input += LENGTH_SZ; + *sslBytes -= LENGTH_SZ; + + /* make sure can read through ticket */ + if (len > *sslBytes || len < ID_LEN) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* store session with macID as sessionID */ + session->sslServer->options.haveSessionId = 1; + XMEMCPY(session->sslServer->arrays->sessionID, input + len - ID_LEN,ID_LEN); + + return 0; +} + + +/* Process Server Hello */ +static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + ProtocolVersion pv; + byte b, b0; + int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; + int doResume = 0; + int initialBytes = *sslBytes; + + (void)msgSz; + (void)initialBytes; + + /* make sure we didn't miss ClientHello */ + if (session->flags.clientHello == 0) { + SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* make sure can read through session len */ + if (toRead > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + XMEMCPY(&pv, input, VERSION_SZ); + input += VERSION_SZ; + *sslBytes -= VERSION_SZ; + + session->sslServer->version = pv; + session->sslClient->version = pv; + + XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN); + XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN); + input += RAN_LEN; + *sslBytes -= RAN_LEN; + + b = *input++; + *sslBytes -= 1; + + /* make sure can read through compression */ + if ( (b + SUITE_LEN + ENUM_LEN) > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + if (b) { + XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN); + session->sslServer->options.haveSessionId = 1; + } + input += b; + *sslBytes -= b; + + /* cipher suite */ + b0 = *input++; /* first byte, ECC or not */ + session->sslServer->options.cipherSuite0 = b0; + session->sslClient->options.cipherSuite0 = b0; + b = *input++; + session->sslServer->options.cipherSuite = b; + session->sslClient->options.cipherSuite = b; + *sslBytes -= SUITE_LEN; + +#ifdef WOLFSSL_SNIFFER_STATS + { + const CipherSuiteInfo* suites = GetCipherNames(); + int suitesSz = GetCipherNamesSize(); + int match = 0; + + while (suitesSz) { + if (b0 == suites->cipherSuite0 && b == suites->cipherSuite) { + match = 1; + break; + } + suites++; + suitesSz--; + } + if (!match) + INC_STAT(SnifferStats.sslCiphersUnsupported); + } +#endif /* WOLFSSL_SNIFFER_STATS */ + + /* compression */ + b = *input++; + *sslBytes -= ENUM_LEN; + + if (b) { + SetError(BAD_COMPRESSION_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + +#ifdef HAVE_EXTENDED_MASTER + /* extensions */ + if ((initialBytes - *sslBytes) < msgSz) { + word16 len; + + /* skip extensions until extended master secret */ + /* make sure can read len */ + if (SUITE_LEN > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + len = (word16)((input[0] << 8) | input[1]); + input += SUITE_LEN; + *sslBytes -= SUITE_LEN; + /* make sure can read through all extensions */ + if (len > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + while (len >= EXT_TYPE_SZ + LENGTH_SZ) { + byte extType[EXT_TYPE_SZ]; + word16 extLen; + + extType[0] = input[0]; + extType[1] = input[1]; + input += EXT_TYPE_SZ; + *sslBytes -= EXT_TYPE_SZ; + + extLen = (word16)((input[0] << 8) | input[1]); + input += LENGTH_SZ; + *sslBytes -= LENGTH_SZ; + + /* make sure can read through individual extension */ + if (extLen > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + + if (extType[0] == 0x00 && extType[1] == EXT_MASTER_SECRET) { + session->flags.expectEms = 1; + } + + input += extLen; + *sslBytes -= extLen; + len -= extLen + EXT_TYPE_SZ + LENGTH_SZ; + } + } + + if (!session->flags.expectEms) { + XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); + session->hash = NULL; + } +#endif + + if (session->sslServer->options.haveSessionId) { + if (XMEMCMP(session->sslServer->arrays->sessionID, + session->sslClient->arrays->sessionID, ID_LEN) == 0) + doResume = 1; + } + else if (session->sslClient->options.haveSessionId == 0 && + session->sslServer->options.haveSessionId == 0 && + session->ticketID) + doResume = 1; + + if (session->ticketID && doResume) { + /* use ticketID to retrieve from session, prefer over sessionID */ + XMEMCPY(session->sslServer->arrays->sessionID,session->ticketID,ID_LEN); + session->sslServer->options.haveSessionId = 1; /* may not have + actual sessionID */ + } + + if (doResume ) { + int ret = 0; + SSL_SESSION* resume = GetSession(session->sslServer, + session->sslServer->arrays->masterSecret, 0); + if (resume == NULL) { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslResumeMisses); +#endif + SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + /* make sure client has master secret too */ + XMEMCPY(session->sslClient->arrays->masterSecret, + session->sslServer->arrays->masterSecret, SECRET_LEN); + session->flags.resuming = 1; + + Trace(SERVER_DID_RESUMPTION_STR); +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslResumedConns); + INC_STAT(SnifferStats.sslResumptionValid); +#endif + if (SetCipherSpecs(session->sslServer) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (SetCipherSpecs(session->sslClient) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (session->sslServer->options.tls) { + ret = DeriveTlsKeys(session->sslServer); + ret += DeriveTlsKeys(session->sslClient); + } + else { + ret = DeriveKeys(session->sslServer); + ret += DeriveKeys(session->sslClient); + } + ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); + ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); + + if (ret != 0) { + SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + } + else { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslStandardConns); +#endif + } +#ifdef SHOW_SECRETS + { + int i; + printf("cipher suite = 0x%02x\n", + session->sslServer->options.cipherSuite); + printf("server random: "); + for (i = 0; i < RAN_LEN; i++) + printf("%02x", session->sslServer->arrays->serverRandom[i]); + printf("\n"); + } +#endif + return 0; +} + + +/* Process normal Client Hello */ +static int ProcessClientHello(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + byte bLen; + word16 len; + int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; + +#ifdef HAVE_SNI + { + byte name[MAX_SERVER_NAME]; + word32 nameSz = sizeof(name); + int ret; + + ret = wolfSSL_SNI_GetFromBuffer( + input - HANDSHAKE_HEADER_SZ - RECORD_HEADER_SZ, + *sslBytes + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ, + WOLFSSL_SNI_HOST_NAME, name, &nameSz); + + if (ret == WOLFSSL_SUCCESS) { + NamedKey* namedKey; + + if (nameSz > sizeof(name) - 1) + nameSz = sizeof(name) - 1; + name[nameSz] = 0; + wc_LockMutex(&session->context->namedKeysMutex); + namedKey = session->context->namedKeys; + while (namedKey != NULL) { + if (nameSz == namedKey->nameSz && + XSTRNCMP((char*)name, namedKey->name, nameSz) == 0) { + if (wolfSSL_use_PrivateKey_buffer(session->sslServer, + namedKey->key, namedKey->keySz, + WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { + wc_UnLockMutex(&session->context->namedKeysMutex); + SetError(CLIENT_HELLO_LATE_KEY_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + session->sni = namedKey->name; + break; + } + else + namedKey = namedKey->next; + } + wc_UnLockMutex(&session->context->namedKeysMutex); + } + } +#endif + + session->flags.clientHello = 1; /* don't process again */ + + /* make sure can read up to session len */ + if (toRead > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* skip, get negotiated one from server hello */ + input += VERSION_SZ; + *sslBytes -= VERSION_SZ; + + XMEMCPY(session->sslServer->arrays->clientRandom, input, RAN_LEN); + XMEMCPY(session->sslClient->arrays->clientRandom, input, RAN_LEN); + + input += RAN_LEN; + *sslBytes -= RAN_LEN; + + /* store session in case trying to resume */ + bLen = *input++; + *sslBytes -= ENUM_LEN; + if (bLen) { + if (ID_LEN > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + Trace(CLIENT_RESUME_TRY_STR); + XMEMCPY(session->sslClient->arrays->sessionID, input, ID_LEN); + session->sslClient->options.haveSessionId = 1; + } +#ifdef SHOW_SECRETS + { + int i; + printf("client random: "); + for (i = 0; i < RAN_LEN; i++) + printf("%02x", session->sslServer->arrays->clientRandom[i]); + printf("\n"); + } +#endif + + input += bLen; + *sslBytes -= bLen; + + /* skip cipher suites */ + /* make sure can read len */ + if (SUITE_LEN > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + len = (word16)((input[0] << 8) | input[1]); + input += SUITE_LEN; + *sslBytes -= SUITE_LEN; + /* make sure can read suites + comp len */ + if (len + ENUM_LEN > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + input += len; + *sslBytes -= len; + + /* skip compression */ + bLen = *input++; + *sslBytes -= ENUM_LEN; + /* make sure can read len */ + if (bLen > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + input += bLen; + *sslBytes -= bLen; + + if (*sslBytes == 0) { + /* no extensions */ + return 0; + } + + /* skip extensions until session ticket */ + /* make sure can read len */ + if (SUITE_LEN > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + len = (word16)((input[0] << 8) | input[1]); + input += SUITE_LEN; + *sslBytes -= SUITE_LEN; + /* make sure can read through all extensions */ + if (len > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + while (len >= EXT_TYPE_SZ + LENGTH_SZ) { + byte extType[EXT_TYPE_SZ]; + word16 extLen; + + extType[0] = input[0]; + extType[1] = input[1]; + input += EXT_TYPE_SZ; + *sslBytes -= EXT_TYPE_SZ; + + extLen = (word16)((input[0] << 8) | input[1]); + input += LENGTH_SZ; + *sslBytes -= LENGTH_SZ; + + /* make sure can read through individual extension */ + if (extLen > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) { + + /* make sure can read through ticket if there is a non blank one */ + if (extLen && extLen < ID_LEN) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + + if (extLen) { + if (session->ticketID == 0) { + session->ticketID = (byte*)XMALLOC(ID_LEN, + NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID); + if (session->ticketID == 0) { + SetError(MEMORY_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + } + XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN); + } + } + + input += extLen; + *sslBytes -= extLen; + len -= extLen + EXT_TYPE_SZ + LENGTH_SZ; + } + + return 0; +} + + +#ifdef WOLFSSL_SNIFFER_WATCH + +/* Process Certificate */ +static int ProcessCertificate(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + Sha256 sha; + const byte* certChain; + word32 certChainSz; + word32 certSz; + int ret; + byte digest[SHA256_DIGEST_SIZE]; + + /* If the receiver is the server, this is the client certificate message, + * and it should be ignored at this point. */ + if (session->flags.side == WOLFSSL_SERVER_END) + return 0; + + if (WatchCb == NULL) { + SetError(WATCH_CB_MISSING_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (*sslBytes < CERT_HEADER_SZ) { + SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + ato24(input, &certChainSz); + *sslBytes -= CERT_HEADER_SZ; + input += CERT_HEADER_SZ; + + if (*sslBytes < (int)certChainSz) { + SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + certChain = input; + + ato24(input, &certSz); + input += OPAQUE24_LEN; + if (*sslBytes < (int)certSz) { + SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + *sslBytes -= certChainSz; + + ret = wc_InitSha256(&sha); + if (ret == 0) + ret = wc_Sha256Update(&sha, input, certSz); + if (ret == 0) + ret = wc_Sha256Final(&sha, digest); + if (ret != 0) { + SetError(WATCH_HASH_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + ret = WatchCb((void*)session, digest, sizeof(digest), + certChain, certChainSz, WatchCbCtx, error); + if (ret != 0) { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslKeysUnmatched); +#endif + SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + else { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslKeyMatches); +#endif + } + + return 0; +} + +#endif + + +/* Process Finished */ +static int ProcessFinished(const byte* input, int size, int* sslBytes, + SnifferSession* session, char* error) +{ + SSL* ssl; + word32 inOutIdx = 0; + int ret; + + if (session->flags.side == WOLFSSL_SERVER_END) + ssl = session->sslServer; + else + ssl = session->sslClient; + + ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes, + SNIFF); + *sslBytes -= (int)inOutIdx; + + if (ret < 0) { + SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE); + return ret; + } + + if (ret == 0 && session->flags.cached == 0) { + if (session->sslServer->options.haveSessionId) { + WOLFSSL_SESSION* sess = GetSession(session->sslServer, NULL, 0); + if (sess == NULL) { + AddSession(session->sslServer); /* don't re add */ +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslResumptionInserts); +#endif + } + session->flags.cached = 1; + } + } + + /* If receiving a finished message from one side, free the resources + * from the other side's tracker. */ + if (session->flags.side == WOLFSSL_SERVER_END) + FreeHandshakeResources(session->sslClient); + else + FreeHandshakeResources(session->sslServer); + + return ret; +} + + +/* Process HandShake input */ +static int DoHandShake(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + byte type; + int size; + int ret = 0; + int startBytes; + + if (*sslBytes < HANDSHAKE_HEADER_SZ) { + SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + type = input[0]; + size = (input[1] << 16) | (input[2] << 8) | input[3]; + + input += HANDSHAKE_HEADER_SZ; + *sslBytes -= HANDSHAKE_HEADER_SZ; + startBytes = *sslBytes; + + if (*sslBytes < size) { + Trace(SPLIT_HANDSHAKE_MSG_STR); + *sslBytes = 0; + return ret; + } + + /* A session's arrays are released when the handshake is completed. */ + if (session->sslServer->arrays == NULL && + session->sslClient->arrays == NULL) { + + SetError(NO_SECURE_RENEGOTIATION, error, session, FATAL_ERROR_STATE); + return -1; + } + +#ifdef HAVE_EXTENDED_MASTER + if (session->hash) { + if (HashUpdate(session->hash, input, size) != 0) { + SetError(EXTENDED_MASTER_HASH_STR, error, + session, FATAL_ERROR_STATE); + return -1; + } + } +#endif + + switch (type) { + case hello_verify_request: + Trace(GOT_HELLO_VERIFY_STR); + break; + case hello_request: + Trace(GOT_HELLO_REQUEST_STR); + break; + case session_ticket: + Trace(GOT_SESSION_TICKET_STR); + ret = ProcessSessionTicket(input, sslBytes, session, error); + break; + case server_hello: + Trace(GOT_SERVER_HELLO_STR); + ret = ProcessServerHello(size, input, sslBytes, session, error); + break; + case certificate_request: + Trace(GOT_CERT_REQ_STR); + break; + case server_key_exchange: +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslEphemeralMisses); +#endif + Trace(GOT_SERVER_KEY_EX_STR); + /* can't know temp key passively */ + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + ret = -1; + break; + case certificate: + Trace(GOT_CERT_STR); + if (session->flags.side == WOLFSSL_SERVER_END) { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslClientAuthConns); +#endif + } +#ifdef WOLFSSL_SNIFFER_WATCH + ret = ProcessCertificate(input, sslBytes, session, error); +#endif + break; + case server_hello_done: + Trace(GOT_SERVER_HELLO_DONE_STR); + break; + case finished: + Trace(GOT_FINISHED_STR); + ret = ProcessFinished(input, size, sslBytes, session, error); + break; + case client_hello: + Trace(GOT_CLIENT_HELLO_STR); + ret = ProcessClientHello(input, sslBytes, session, error); + break; + case client_key_exchange: + Trace(GOT_CLIENT_KEY_EX_STR); +#ifdef HAVE_EXTENDED_MASTER + if (session->flags.expectEms && session->hash != NULL) { + if (HashCopy(session->sslServer->hsHashes, + session->hash) == 0 && + HashCopy(session->sslClient->hsHashes, + session->hash) == 0) { + + session->sslServer->options.haveEMS = 1; + session->sslClient->options.haveEMS = 1; + } + else { + SetError(EXTENDED_MASTER_HASH_STR, error, + session, FATAL_ERROR_STATE); + ret = -1; + } + XMEMSET(session->hash, 0, sizeof(HsHashes)); + XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); + session->hash = NULL; + } + else { + session->sslServer->options.haveEMS = 0; + session->sslClient->options.haveEMS = 0; + } +#endif + if (ret == 0) + ret = ProcessClientKeyExchange(input, sslBytes, session, error); + break; + case certificate_verify: + Trace(GOT_CERT_VER_STR); + break; + case certificate_status: + Trace(GOT_CERT_STATUS_STR); + break; + default: + SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0); + return -1; + } + + *sslBytes = startBytes - size; /* actual bytes of full process */ + + return ret; +} + + +/* Decrypt input into plain output, 0 on success */ +static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) +{ + int ret = 0; + + (void)output; + (void)input; + (void)sz; + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case wolfssl_rc4: + wc_Arc4Process(ssl->decrypt.arc4, output, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case wolfssl_triple_des: + ret = wc_Des3_CbcDecrypt(ssl->decrypt.des3, output, input, sz); + break; + #endif + + #ifdef BUILD_AES + case wolfssl_aes: + ret = wc_AesCbcDecrypt(ssl->decrypt.aes, output, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case wolfssl_hc128: + wc_Hc128_Process(ssl->decrypt.hc128, output, input, sz); + break; + #endif + + #ifdef BUILD_RABBIT + case wolfssl_rabbit: + wc_RabbitProcess(ssl->decrypt.rabbit, output, input, sz); + break; + #endif + + #ifdef HAVE_CAMELLIA + case wolfssl_camellia: + wc_CamelliaCbcDecrypt(ssl->decrypt.cam, output, input, sz); + break; + #endif + + #ifdef HAVE_IDEA + case wolfssl_idea: + wc_IdeaCbcDecrypt(ssl->decrypt.idea, output, input, sz); + break; + #endif + + #ifdef HAVE_AESGCM + case wolfssl_aes_gcm: + if (sz >= (word32)(AESGCM_EXP_IV_SZ + ssl->specs.aead_mac_size)) + { + /* scratch buffer, sniffer ignores auth tag*/ + byte authTag[WOLFSSL_MIN_AUTH_TAG_SZ]; + + byte nonce[AESGCM_NONCE_SZ]; + XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AESGCM_IMP_IV_SZ); + XMEMCPY(nonce + AESGCM_IMP_IV_SZ, input, AESGCM_EXP_IV_SZ); + + if (wc_AesGcmEncrypt(ssl->decrypt.aes, + output, + input + AESGCM_EXP_IV_SZ, + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, + nonce, AESGCM_NONCE_SZ, + authTag, sizeof(authTag), + NULL, 0) < 0) { + Trace(BAD_DECRYPT); + ret = -1; + } + ForceZero(nonce, AESGCM_NONCE_SZ); + } + else { + Trace(BAD_DECRYPT_SIZE); + ret = -1; + } + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + XMEMCPY(output, input, sz); + break; + #endif + + default: + Trace(BAD_DECRYPT_TYPE); + ret = -1; + break; + } + + return ret; +} + + +/* Decrypt input message into output, adjust output steam if needed */ +static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz, + byte* output, int* error, int* advance) +{ + int ivExtra = 0; + + int ret = Decrypt(ssl, output, input, sz); + if (ret != 0) { + *error = ret; + return NULL; + } + ssl->keys.encryptSz = sz; + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) { + output += ssl->specs.block_size; /* go past TLSv1.1 IV */ + ivExtra = ssl->specs.block_size; + *advance = ssl->specs.block_size; + } + + if (ssl->specs.cipher_type == aead) { + *advance = ssl->specs.aead_mac_size; + ssl->keys.padSz = ssl->specs.aead_mac_size; + } + else + ssl->keys.padSz = ssl->specs.hash_size; + + if (ssl->specs.cipher_type == block) + ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1; + + return output; +} + + +/* remove session from table, use rowHint if no info (means we have a lock) */ +static void RemoveSession(SnifferSession* session, IpInfo* ipInfo, + TcpInfo* tcpInfo, word32 rowHint) +{ + SnifferSession* previous = 0; + SnifferSession* current; + word32 row = rowHint; + int haveLock = 0; + + if (ipInfo && tcpInfo) + row = SessionHash(ipInfo, tcpInfo); + else + haveLock = 1; + + assert(row <= HASH_SIZE); + Trace(REMOVE_SESSION_STR); + + if (!haveLock) + wc_LockMutex(&SessionMutex); + + current = SessionTable[row]; + + while (current) { + if (current == session) { + if (previous) + previous->next = current->next; + else + SessionTable[row] = current->next; + FreeSnifferSession(session); + TraceRemovedSession(); + break; + } + previous = current; + current = current->next; + } + + if (!haveLock) + wc_UnLockMutex(&SessionMutex); +} + + +/* Remove stale sessions from the Session Table, have a lock */ +static void RemoveStaleSessions(void) +{ + word32 i; + SnifferSession* session; + + for (i = 0; i < HASH_SIZE; i++) { + session = SessionTable[i]; + while (session) { + SnifferSession* next = session->next; + if (time(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) { + TraceStaleSession(); + RemoveSession(session, NULL, NULL, i); + } + session = next; + } + } +} + + +/* Create a new Sniffer Session */ +static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, + char* error) +{ + SnifferSession* session = 0; + int row; + + Trace(NEW_SESSION_STR); + /* create a new one */ + session = (SnifferSession*)XMALLOC(sizeof(SnifferSession), + NULL, DYNAMIC_TYPE_SNIFFER_SESSION); + if (session == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + return 0; + } + InitSession(session); +#ifdef HAVE_EXTENDED_MASTER + { + HsHashes* newHash = (HsHashes*)XMALLOC(sizeof(HsHashes), + NULL, DYNAMIC_TYPE_HASHES); + if (newHash == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); + return 0; + } + if (HashInit(newHash) != 0) { + SetError(EXTENDED_MASTER_HASH_STR, error, NULL, 0); + XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); + return 0; + } + session->hash = newHash; + } +#endif + session->server = ipInfo->dst; + session->client = ipInfo->src; + session->srvPort = (word16)tcpInfo->dstPort; + session->cliPort = (word16)tcpInfo->srcPort; + session->cliSeqStart = tcpInfo->sequence; + session->cliExpected = 1; /* relative */ + session->lastUsed= time(NULL); + session->keySz = 0; +#ifdef HAVE_SNI + session->sni = NULL; +#endif + + session->context = GetSnifferServer(ipInfo, tcpInfo); + if (session->context == NULL) { + SetError(SERVER_NOT_REG_STR, error, NULL, 0); + XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); + return 0; + } + + session->sslServer = SSL_new(session->context->ctx); + if (session->sslServer == NULL) { + SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); + XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); + return 0; + } + session->sslClient = SSL_new(session->context->ctx); + if (session->sslClient == NULL) { + SSL_free(session->sslServer); + session->sslServer = 0; + + SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); + XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); + return 0; + } + /* put server back into server mode */ + session->sslServer->options.side = WOLFSSL_SERVER_END; + + row = SessionHash(ipInfo, tcpInfo); + + /* add it to the session table */ + wc_LockMutex(&SessionMutex); + + session->next = SessionTable[row]; + SessionTable[row] = session; + + SessionCount++; + + if ( (SessionCount % HASH_SIZE) == 0) { + TraceFindingStale(); + RemoveStaleSessions(); + } + + wc_UnLockMutex(&SessionMutex); + + /* CreateSession is called in response to a SYN packet, we know this + * is headed to the server. Also we know the server is one we care + * about as we've passed the GetSnifferServer() successfully. */ + session->flags.side = WOLFSSL_SERVER_END; + + return session; +} + + +#ifdef OLD_HELLO_ALLOWED + +/* Process Old Client Hello Input */ +static int DoOldHello(SnifferSession* session, const byte* sslFrame, + int* rhSize, int* sslBytes, char* error) +{ + const byte* input = sslFrame; + byte b0, b1; + word32 idx = 0; + int ret; + + Trace(GOT_OLD_CLIENT_HELLO_STR); + session->flags.clientHello = 1; /* don't process again */ + b0 = *input++; + b1 = *input++; + *sslBytes -= 2; + *rhSize = ((b0 & 0x7f) << 8) | b1; + + if (*rhSize > *sslBytes) { + SetError(OLD_CLIENT_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + ret = ProcessOldClientHello(session->sslServer, input, &idx, *sslBytes, + (word16)*rhSize); + if (ret < 0 && ret != MATCH_SUITE_ERROR) { + SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + Trace(OLD_CLIENT_OK_STR); + XMEMCPY(session->sslClient->arrays->clientRandom, + session->sslServer->arrays->clientRandom, RAN_LEN); + + *sslBytes -= *rhSize; + return 0; +} + +#endif /* OLD_HELLO_ALLOWED */ + + +#if 0 +/* Calculate the TCP checksum, see RFC 1071 */ +/* return 0 for success, -1 on error */ +/* can be called from decode() with + TcpChecksum(&ipInfo, &tcpInfo, sslBytes, packet + ipInfo.length); + could also add a 64bit version if type available and using this +*/ +int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen, + const byte* packet) +{ + TcpPseudoHdr pseudo; + int count = PSEUDO_HDR_SZ; + const word16* data = (word16*)&pseudo; + word32 sum = 0; + word16 checksum; + + pseudo.src = ipInfo->src; + pseudo.dst = ipInfo->dst; + pseudo.rsv = 0; + pseudo.protocol = TCP_PROTO; + pseudo.length = htons(tcpInfo->length + dataLen); + + /* pseudo header sum */ + while (count >= 2) { + sum += *data++; + count -= 2; + } + + count = tcpInfo->length + dataLen; + data = (word16*)packet; + + /* main sum */ + while (count > 1) { + sum += *data++; + count -=2; + } + + /* get left-over, if any */ + packet = (byte*)data; + if (count > 0) { + sum += *packet; + } + + /* fold 32bit sum into 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + checksum = (word16)~sum; + /* checksum should now equal 0, since included already calcd checksum */ + /* field, but tcp checksum offloading could negate calculation */ + if (checksum == 0) + return 0; + return -1; +} +#endif + + +/* Check IP and TCP headers, set payload */ +/* returns 0 on success, -1 on error */ +static int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet, + int length, const byte** sslFrame, int* sslBytes, char* error) +{ + TraceHeader(); + TracePacket(); + + /* ip header */ + if (length < IP_HDR_SZ) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0) + return -1; + + /* tcp header */ + if (length < (ipInfo->length + TCP_HDR_SZ)) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + if (CheckTcpHdr((TcpHdr*)(packet + ipInfo->length), tcpInfo, error) != 0) + return -1; + + /* setup */ + *sslFrame = packet + ipInfo->length + tcpInfo->length; + if (*sslFrame > packet + length) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + /* We only care about the data in the TCP/IP record. There may be extra + * data after the IP record for the FCS for Ethernet. */ + *sslBytes = (int)(packet + ipInfo->total - *sslFrame); + + return 0; +} + + +/* Create or Find existing session */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int CheckSession(IpInfo* ipInfo, TcpInfo* tcpInfo, int sslBytes, + SnifferSession** session, char* error) +{ + /* create a new SnifferSession on client SYN */ + if (tcpInfo->syn && !tcpInfo->ack) { + TraceClientSyn(tcpInfo->sequence); +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslEncryptedConns); +#endif + *session = CreateSession(ipInfo, tcpInfo, error); + if (*session == NULL) { + *session = GetSnifferSession(ipInfo, tcpInfo); + /* already had existing, so OK */ + if (*session) + return 1; + + SetError(MEMORY_STR, error, NULL, 0); + return -1; + } + return 1; + } + /* get existing sniffer session */ + else { + *session = GetSnifferSession(ipInfo, tcpInfo); + if (*session == NULL) { + /* don't worry about extraneous RST or duplicate FINs */ + if (tcpInfo->fin || tcpInfo->rst) + return 1; + /* don't worry about duplicate ACKs either */ + if (sslBytes == 0 && tcpInfo->ack) + return 1; + +#ifdef WOLFSSL_SNIFFER_STATS + LOCK_STAT(); + NOLOCK_INC_STAT(SnifferStats.sslDecryptedPackets); + NOLOCK_ADD_TO_STAT(SnifferStats.sslDecryptedBytes, sslBytes); + UNLOCK_STAT(); +#endif + + SetError(BAD_SESSION_STR, error, NULL, 0); + return -1; + } + } + return 0; +} + + +/* Create a Packet Buffer from *begin - end, adjust new *begin and bytesLeft */ +static PacketBuffer* CreateBuffer(word32* begin, word32 end, const byte* data, + int* bytesLeft) +{ + PacketBuffer* pb; + + int added = end - *begin + 1; + assert(*begin <= end); + + pb = (PacketBuffer*)XMALLOC(sizeof(PacketBuffer), + NULL, DYNAMIC_TYPE_SNIFFER_PB); + if (pb == NULL) return NULL; + + pb->next = 0; + pb->begin = *begin; + pb->end = end; + pb->data = (byte*)XMALLOC(added, NULL, DYNAMIC_TYPE_SNIFFER_PB_BUFFER); + + if (pb->data == NULL) { + XFREE(pb, NULL, DYNAMIC_TYPE_SNIFFER_PB); + return NULL; + } + XMEMCPY(pb->data, data, added); + + *bytesLeft -= added; + *begin = pb->end + 1; + + return pb; +} + + +/* Add sslFrame to Reassembly List */ +/* returns 1 (end) on success, -1, on error */ +static int AddToReassembly(byte from, word32 seq, const byte* sslFrame, + int sslBytes, SnifferSession* session, char* error) +{ + PacketBuffer* add; + PacketBuffer** front = (from == WOLFSSL_SERVER_END) ? + &session->cliReassemblyList: &session->srvReassemblyList; + PacketBuffer* curr = *front; + PacketBuffer* prev = curr; + + word32* reassemblyMemory = (from == WOLFSSL_SERVER_END) ? + &session->cliReassemblyMemory : &session->srvReassemblyMemory; + word32 startSeq = seq; + word32 added; + int bytesLeft = sslBytes; /* could be overlapping fragment */ + + /* if list is empty add full frame to front */ + if (!curr) { + if (MaxRecoveryMemory != -1 && + (int)(*reassemblyMemory + sslBytes) > MaxRecoveryMemory) { + SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft); + if (add == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + *front = add; + *reassemblyMemory += sslBytes; + return 1; + } + + /* add to front if before current front, up to next->begin */ + if (seq < curr->begin) { + word32 end = seq + sslBytes - 1; + + if (end >= curr->begin) + end = curr->begin - 1; + + if (MaxRecoveryMemory -1 && + (int)(*reassemblyMemory + sslBytes) > MaxRecoveryMemory) { + SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add = CreateBuffer(&seq, end, sslFrame, &bytesLeft); + if (add == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add->next = curr; + *front = add; + *reassemblyMemory += sslBytes; + } + + /* while we have bytes left, try to find a gap to fill */ + while (bytesLeft > 0) { + /* get previous packet in list */ + while (curr && (seq >= curr->begin)) { + prev = curr; + curr = curr->next; + } + + /* don't add duplicate data */ + if (prev->end >= seq) { + if ( (seq + bytesLeft - 1) <= prev->end) + return 1; + seq = prev->end + 1; + bytesLeft = startSeq + sslBytes - seq; + } + + if (!curr) + /* we're at the end */ + added = bytesLeft; + else + /* we're in between two frames */ + added = min((word32)bytesLeft, curr->begin - seq); + + /* data already there */ + if (added == 0) + continue; + + if (MaxRecoveryMemory != -1 && + (int)(*reassemblyMemory + added) > MaxRecoveryMemory) { + SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq], + &bytesLeft); + if (add == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add->next = prev->next; + prev->next = add; + *reassemblyMemory += added; + } + return 1; +} + + +/* Add out of order FIN capture */ +/* returns 1 for success (end) */ +static int AddFinCapture(SnifferSession* session, word32 sequence) +{ + if (session->flags.side == WOLFSSL_SERVER_END) { + if (session->finCaputre.cliCounted == 0) + session->finCaputre.cliFinSeq = sequence; + } + else { + if (session->finCaputre.srvCounted == 0) + session->finCaputre.srvFinSeq = sequence; + } + return 1; +} + + +/* Adjust incoming sequence based on side */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session, + int* sslBytes, const byte** sslFrame, char* error) +{ + word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? + session->cliSeqStart :session->srvSeqStart; + word32 real = tcpInfo->sequence - seqStart; + word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliExpected : &session->srvExpected; + PacketBuffer* reassemblyList = (session->flags.side == WOLFSSL_SERVER_END) ? + session->cliReassemblyList : session->srvReassemblyList; + byte skipPartial = (session->flags.side == WOLFSSL_SERVER_END) ? + session->flags.srvSkipPartial : + session->flags.cliSkipPartial; + + /* handle rollover of sequence */ + if (tcpInfo->sequence < seqStart) + real = 0xffffffffU - seqStart + tcpInfo->sequence; + + TraceRelativeSequence(*expected, real); + + if (real < *expected) { + Trace(DUPLICATE_STR); + if (real + *sslBytes > *expected) { + int overlap = *expected - real; + Trace(OVERLAP_DUPLICATE_STR); + + /* adjust to expected, remove duplicate */ + *sslFrame += overlap; + *sslBytes -= overlap; + + /* The following conditional block is duplicated below. It is the + * same action but for a different setup case. If changing this + * block be sure to also update the block below. */ + if (reassemblyList) { + word32 newEnd = *expected + *sslBytes; + + if (newEnd > reassemblyList->begin) { + Trace(OVERLAP_REASSEMBLY_BEGIN_STR); + + /* remove bytes already on reassembly list */ + *sslBytes -= newEnd - reassemblyList->begin; + } + if (newEnd > reassemblyList->end) { + Trace(OVERLAP_REASSEMBLY_END_STR); + + /* may be past reassembly list end (could have more on list) + so try to add what's past the front->end */ + AddToReassembly(session->flags.side, reassemblyList->end +1, + *sslFrame + reassemblyList->end - *expected + 1, + newEnd - reassemblyList->end, session, error); + } + } + } + else + return 1; + } + else if (real > *expected) { + Trace(OUT_OF_ORDER_STR); + if (*sslBytes > 0) { + int addResult = AddToReassembly(session->flags.side, real, + *sslFrame, *sslBytes, session, error); + if (skipPartial) { + *sslBytes = 0; + return 0; + } + else + return addResult; + } + else if (tcpInfo->fin) + return AddFinCapture(session, real); + } + else if (*sslBytes > 0) { + if (skipPartial) { + AddToReassembly(session->flags.side, real, + *sslFrame, *sslBytes, session, error); + *expected += *sslBytes; + *sslBytes = 0; + if (tcpInfo->fin) + *expected += 1; + return 0; + } + /* The following conditional block is duplicated above. It is the + * same action but for a different setup case. If changing this + * block be sure to also update the block above. */ + else if (reassemblyList) { + word32 newEnd = *expected + *sslBytes; + + if (newEnd > reassemblyList->begin) { + Trace(OVERLAP_REASSEMBLY_BEGIN_STR); + + /* remove bytes already on reassembly list */ + *sslBytes -= newEnd - reassemblyList->begin; + } + if (newEnd > reassemblyList->end) { + Trace(OVERLAP_REASSEMBLY_END_STR); + + /* may be past reassembly list end (could have more on list) + so try to add what's past the front->end */ + AddToReassembly(session->flags.side, reassemblyList->end +1, + *sslFrame + reassemblyList->end - *expected + 1, + newEnd - reassemblyList->end, session, error); + } + } + } + /* got expected sequence */ + *expected += *sslBytes; + if (tcpInfo->fin) + *expected += 1; + + return 0; +} + + +static int FindNextRecordInAssembly(SnifferSession* session, + const byte** sslFrame, int* sslBytes, + const byte** end, char* error) +{ + PacketBuffer** front = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliReassemblyList : + &session->srvReassemblyList; + PacketBuffer* curr = *front; + PacketBuffer* prev = NULL; + byte* skipPartial = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->flags.srvSkipPartial : + &session->flags.cliSkipPartial; + word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliReassemblyMemory : + &session->srvReassemblyMemory; + SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? + session->sslServer : + session->sslClient; + ProtocolVersion pv = ssl->version; + word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliExpected : + &session->srvExpected; + + while (curr != NULL) { + *expected = curr->end + 1; + + if (curr->data[0] == application_data && + curr->data[1] == pv.major && + curr->data[2] == pv.minor) { + + if (ssl->buffers.inputBuffer.length > 0) + Trace(DROPPING_PARTIAL_RECORD); + + *sslBytes = curr->end - curr->begin + 1; + if ( (word32)*sslBytes > ssl->buffers.inputBuffer.bufferSize) { + if (GrowInputBuffer(ssl, *sslBytes, 0) < 0) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + } + + XMEMCPY(ssl->buffers.inputBuffer.buffer, curr->data, *sslBytes); + + *front = curr->next; + *reassemblyMemory -= *sslBytes; + FreePacketBuffer(curr); + + ssl->buffers.inputBuffer.length = *sslBytes; + *sslFrame = ssl->buffers.inputBuffer.buffer; + *end = *sslFrame + *sslBytes; + *skipPartial = 0; + + return 0; + } + else if (ssl->specs.cipher_type == block) { + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes) { +#ifdef BUILD_AES + wc_AesSetIV(ssl->decrypt.aes, + curr->data + curr->end - curr->begin + - ssl->specs.block_size + 1); +#endif + } + else if (ssl->specs.bulk_cipher_algorithm == wolfssl_triple_des) { +#ifdef BUILD_DES3 + wc_Des3_SetIV(ssl->decrypt.des3, + curr->data + curr->end - curr->begin + - ssl->specs.block_size + 1); +#endif + } + } + + Trace(DROPPING_LOST_FRAG_STR); +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslDecodeFails); +#endif + prev = curr; + curr = curr->next; + *reassemblyMemory -= (prev->end - prev->begin + 1); + FreePacketBuffer(prev); + } + + *front = curr; + + return 0; +} + + +static int FixSequence(TcpInfo* tcpInfo, SnifferSession* session) +{ + word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->srvExpected : &session->cliExpected; + PacketBuffer* list = (session->flags.side == WOLFSSL_SERVER_END) ? + session->srvReassemblyList : + session->cliReassemblyList; + byte* skipPartial = (session->flags.side != WOLFSSL_SERVER_END) ? + &session->flags.srvSkipPartial : + &session->flags.cliSkipPartial; + + *skipPartial = 1; + if (list != NULL) + *expected = list->begin; + else { + word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? + session->srvSeqStart : session->cliSeqStart; + word32 real = tcpInfo->ackNumber - seqStart; + + *expected = real; + } + + return 1; +} + + +/* Check latest ack number for missing packets + return 0 ok, <0 on error */ +static int CheckAck(TcpInfo* tcpInfo, SnifferSession* session) +{ + if (tcpInfo->ack) { + word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? + session->srvSeqStart :session->cliSeqStart; + word32 real = tcpInfo->ackNumber - seqStart; + word32 expected = (session->flags.side == WOLFSSL_SERVER_END) ? + session->srvExpected : session->cliExpected; + + /* handle rollover of sequence */ + if (tcpInfo->ackNumber < seqStart) + real = 0xffffffffU - seqStart + tcpInfo->ackNumber; + + TraceAck(real, expected); + + if (real > expected) + return -1; /* we missed a packet, ACKing data we never saw */ + } + return 0; +} + + +/* Check TCP Sequence status */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo, + SnifferSession* session, int* sslBytes, + const byte** sslFrame, char* error) +{ + int actualLen; + byte* ackFault = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->flags.cliAckFault : + &session->flags.srvAckFault; + + /* init SEQ from server to client */ + if (tcpInfo->syn && tcpInfo->ack) { + session->srvSeqStart = tcpInfo->sequence; + session->srvExpected = 1; + TraceServerSyn(tcpInfo->sequence); + return 1; + } + + /* adjust potential ethernet trailer */ + actualLen = ipInfo->total - ipInfo->length - tcpInfo->length; + if (*sslBytes > actualLen) { + *sslBytes = actualLen; + } + + TraceSequence(tcpInfo->sequence, *sslBytes); + if (CheckAck(tcpInfo, session) < 0) { + if (!RecoveryEnabled) { + UpdateMissedDataSessions(); + SetError(ACK_MISSED_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + else { + SetError(ACK_MISSED_STR, error, session, 0); + if (*ackFault == 0) { + *ackFault = 1; + UpdateMissedDataSessions(); + } + return FixSequence(tcpInfo, session); + } + } + + if (*ackFault) { + Trace(CLEAR_ACK_FAULT); + *ackFault = 0; + } + + return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error); +} + + +/* Check Status before record processing */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, + const byte** sslFrame, SnifferSession** session, + int* sslBytes, const byte** end, + void* vChain, word32 chainSz, char* error) +{ + word32 length; + SSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ? + (*session)->sslServer : (*session)->sslClient; + byte skipPartial = ((*session)->flags.side == WOLFSSL_SERVER_END) ? + (*session)->flags.srvSkipPartial : + (*session)->flags.cliSkipPartial; + /* remove SnifferSession on 2nd FIN or RST */ + if (tcpInfo->fin || tcpInfo->rst) { + /* flag FIN and RST */ + if (tcpInfo->fin) + (*session)->flags.finCount += 1; + else if (tcpInfo->rst) + (*session)->flags.finCount += 2; + + if ((*session)->flags.finCount >= 2) { + RemoveSession(*session, ipInfo, tcpInfo, 0); + *session = NULL; + return 1; + } + } + + if ((*session)->flags.fatalError == FATAL_ERROR_STATE) { + SetError(FATAL_ERROR_STR, error, NULL, 0); + return -1; + } + + if (skipPartial) { + if (FindNextRecordInAssembly(*session, + sslFrame, sslBytes, end, error) < 0) { + return -1; + } + } + + if (*sslBytes == 0) { + Trace(NO_DATA_STR); + return 1; + } + + /* if current partial data, add to end of partial */ + /* if skipping, the data is already at the end of partial */ + if ( !skipPartial && (length = ssl->buffers.inputBuffer.length) ) { + Trace(PARTIAL_ADD_STR); + + if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) { + if (GrowInputBuffer(ssl, *sslBytes, length) < 0) { + SetError(MEMORY_STR, error, *session, FATAL_ERROR_STATE); + return -1; + } + } + if (vChain == NULL) { + XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], + *sslFrame, *sslBytes); + *sslBytes += length; + ssl->buffers.inputBuffer.length = *sslBytes; + *sslFrame = ssl->buffers.inputBuffer.buffer; + *end = *sslFrame + *sslBytes; + } + } + + if (vChain != NULL) { +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + struct iovec* chain = (struct iovec*)vChain; + word32 i, offset, headerSz, qty, remainder; + + Trace(CHAIN_INPUT_STR); + headerSz = (word32)*sslFrame - (word32)chain[0].iov_base; + remainder = *sslBytes; + + if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) { + if (GrowInputBuffer(ssl, *sslBytes, length) < 0) { + SetError(MEMORY_STR, error, *session, FATAL_ERROR_STATE); + return -1; + } + } + + qty = min(*sslBytes, (word32)chain[0].iov_len - headerSz); + XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], + (byte*)chain[0].iov_base + headerSz, qty); + offset = length; + for (i = 1; i < chainSz; i++) { + offset += qty; + remainder -= qty; + + if (chain[i].iov_len > remainder) + qty = remainder; + else + qty = (word32)chain[i].iov_len; + XMEMCPY(ssl->buffers.inputBuffer.buffer + offset, + chain[i].iov_base, qty); + } + + *sslBytes += length; + ssl->buffers.inputBuffer.length = *sslBytes; + *sslFrame = ssl->buffers.inputBuffer.buffer; + *end = *sslFrame + *sslBytes; +#endif + (void)chainSz; + } + + if ((*session)->flags.clientHello == 0 && **sslFrame != handshake) { + /* Sanity check the packet for an old style client hello. */ + int rhSize = (((*sslFrame)[0] & 0x7f) << 8) | ((*sslFrame)[1]); + + if ((rhSize <= (*sslBytes - 2)) && + (*sslFrame)[2] == OLD_HELLO_ID && (*sslFrame)[3] == SSLv3_MAJOR) { +#ifdef OLD_HELLO_ALLOWED + int ret = DoOldHello(*session, *sslFrame, &rhSize, sslBytes, error); + if (ret < 0) + return -1; /* error already set */ + if (*sslBytes <= 0) + return 1; +#endif + } + else { +#ifdef STARTTLS_ALLOWED + if (ssl->buffers.inputBuffer.dynamicFlag) { + ssl->buffers.inputBuffer.length = 0; + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + } + return 1; +#endif + } + } + + return 0; +} + + +/* See if input on the reassembly list is ready for consuming */ +/* returns 1 for TRUE, 0 for FALSE */ +static int HaveMoreInput(SnifferSession* session, const byte** sslFrame, + int* sslBytes, const byte** end, char* error) +{ + /* sequence and reassembly based on from, not to */ + int moreInput = 0; + PacketBuffer** front = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliReassemblyList : &session->srvReassemblyList; + word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliExpected : &session->srvExpected; + /* buffer is on receiving end */ + word32* length = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->sslServer->buffers.inputBuffer.length : + &session->sslClient->buffers.inputBuffer.length; + byte** myBuffer = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->sslServer->buffers.inputBuffer.buffer : + &session->sslClient->buffers.inputBuffer.buffer; + word32* bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->sslServer->buffers.inputBuffer.bufferSize : + &session->sslClient->buffers.inputBuffer.bufferSize; + SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? + session->sslServer : session->sslClient; + word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ? + &session->cliReassemblyMemory : &session->srvReassemblyMemory; + + while (*front && ((*front)->begin == *expected) ) { + word32 room = *bufferSize - *length; + word32 packetLen = (*front)->end - (*front)->begin + 1; + + if (packetLen > room && *bufferSize < MAX_INPUT_SZ) { + if (GrowInputBuffer(ssl, packetLen, *length) < 0) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return 0; + } + room = *bufferSize - *length; /* bufferSize is now bigger */ + } + + if (packetLen <= room) { + PacketBuffer* del = *front; + byte* buf = *myBuffer; + + XMEMCPY(&buf[*length], (*front)->data, packetLen); + *length += packetLen; + *expected += packetLen; + + /* remove used packet */ + *front = (*front)->next; + + *reassemblyMemory -= packetLen; + FreePacketBuffer(del); + + moreInput = 1; + } + else + break; + } + if (moreInput) { + *sslFrame = *myBuffer; + *sslBytes = *length; + *end = *myBuffer + *length; + } + return moreInput; +} + + + +/* Process Message(s) from sslFrame */ +/* return Number of bytes on success, 0 for no data yet, and -1 on error */ +static int ProcessMessage(const byte* sslFrame, SnifferSession* session, + int sslBytes, byte** data, const byte* end, + void* ctx, char* error) +{ + const byte* sslBegin = sslFrame; + const byte* recordEnd; /* end of record indicator */ + const byte* inRecordEnd; /* indicator from input stream not decrypt */ + RecordLayerHeader rh; + int rhSize = 0; + int ret; + int errCode = 0; + int decoded = 0; /* bytes stored for user in data */ + int notEnough; /* notEnough bytes yet flag */ + int decrypted = 0; /* was current msg decrypted */ + SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? + session->sslServer : session->sslClient; +doMessage: + notEnough = 0; + if (sslBytes < 0) { + SetError(PACKET_HDR_SHORT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + if (sslBytes >= RECORD_HEADER_SZ) { + if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) { + SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + } + else + notEnough = 1; + + if (notEnough || rhSize > (sslBytes - RECORD_HEADER_SZ)) { + /* don't have enough input yet to process full SSL record */ + Trace(PARTIAL_INPUT_STR); + + /* store partial if not there already or we advanced */ + if (ssl->buffers.inputBuffer.length == 0 || sslBegin != sslFrame) { + if (sslBytes > (int)ssl->buffers.inputBuffer.bufferSize) { + if (GrowInputBuffer(ssl, sslBytes, 0) < 0) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + } + XMEMMOVE(ssl->buffers.inputBuffer.buffer, sslFrame, sslBytes); + ssl->buffers.inputBuffer.length = sslBytes; + } + if (HaveMoreInput(session, &sslFrame, &sslBytes, &end, error)) + goto doMessage; + return decoded; + } + sslFrame += RECORD_HEADER_SZ; + sslBytes -= RECORD_HEADER_SZ; + recordEnd = sslFrame + rhSize; /* may have more than one record */ + inRecordEnd = recordEnd; + + /* decrypt if needed */ + if ((session->flags.side == WOLFSSL_SERVER_END && + session->flags.serverCipherOn) + || (session->flags.side == WOLFSSL_CLIENT_END && + session->flags.clientCipherOn)) { + int ivAdvance = 0; /* TLSv1.1 advance amount */ + if (ssl->decrypt.setup != 1) { + SetError(DECRYPT_KEYS_NOT_SETUP, error, session, FATAL_ERROR_STATE); + return -1; + } + if (CheckAvailableSize(ssl, rhSize) < 0) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + sslFrame = DecryptMessage(ssl, sslFrame, rhSize, + ssl->buffers.outputBuffer.buffer, &errCode, + &ivAdvance); + recordEnd = sslFrame - ivAdvance + rhSize; /* sslFrame moved so + should recordEnd */ + decrypted = 1; + +#ifdef WOLFSSL_SNIFFER_STATS + if (errCode != 0) { + INC_STAT(SnifferStats.sslKeyFails); + } + else { + LOCK_STAT(); + NOLOCK_INC_STAT(SnifferStats.sslDecryptedPackets); + NOLOCK_ADD_TO_STAT(SnifferStats.sslDecryptedBytes, sslBytes); + UNLOCK_STAT(); + } +#endif + if (errCode != 0) { + SetError(BAD_DECRYPT, error, session, FATAL_ERROR_STATE); + return -1; + } + } + +doPart: + + switch ((enum ContentType)rh.type) { + case handshake: + { + int startIdx = sslBytes; + int used; + + Trace(GOT_HANDSHAKE_STR); + ret = DoHandShake(sslFrame, &sslBytes, session, error); + if (ret != 0) { + if (session->flags.fatalError == 0) + SetError(BAD_HANDSHAKE_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + + /* DoHandShake now fully decrements sslBytes to remaining */ + used = startIdx - sslBytes; + sslFrame += used; + if (decrypted) + sslFrame += ssl->keys.padSz; + } + break; + case change_cipher_spec: + if (session->flags.side == WOLFSSL_SERVER_END) + session->flags.serverCipherOn = 1; + else + session->flags.clientCipherOn = 1; + Trace(GOT_CHANGE_CIPHER_STR); + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + + sslFrame += 1; + sslBytes -= 1; + + break; + case application_data: + Trace(GOT_APP_DATA_STR); + { + word32 inOutIdx = 0; + + ret = DoApplicationData(ssl, (byte*)sslFrame, &inOutIdx); + if (ret == 0) { + ret = ssl->buffers.clearOutputBuffer.length; + TraceGotData(ret); + if (ret) { /* may be blank message */ + if (data != NULL) { + byte* tmpData; /* don't leak on realloc free */ + /* add an extra byte at end of allocation in case + * user wants to null terminate plaintext */ + tmpData = (byte*)XREALLOC(*data, decoded + ret + 1, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmpData == NULL) { + ForceZero(*data, decoded); + XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *data = NULL; + SetError(MEMORY_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + *data = tmpData; + XMEMCPY(*data + decoded, + ssl->buffers.clearOutputBuffer.buffer, ret); + } + else { +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + if (StoreDataCb) { + const byte* buf; + word32 offset = 0; + word32 bufSz; + int stored; + + buf = ssl->buffers.clearOutputBuffer.buffer; + bufSz = ssl->buffers.clearOutputBuffer.length; + do { + stored = StoreDataCb(buf, bufSz, offset, + ctx); + if (stored <= 0) { + return -1; + } + offset += stored; + } while (offset < bufSz); + } + else { + SetError(STORE_DATA_CB_MISSING_STR, error, + session, FATAL_ERROR_STATE); + return -1; + } +#else + (void)ctx; + SetError(NO_DATA_DEST_STR, error, session, + FATAL_ERROR_STATE); + return -1; +#endif + } + TraceAddedData(ret, decoded); + decoded += ret; + ssl->buffers.clearOutputBuffer.length = 0; + } + } + else { + SetError(BAD_APP_DATA_STR, error,session,FATAL_ERROR_STATE); + return -1; + } + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); + + sslFrame += inOutIdx; + sslBytes -= inOutIdx; + } + break; + case alert: + Trace(GOT_ALERT_STR); +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslAlerts); +#endif + sslFrame += rhSize; + sslBytes -= rhSize; + break; + case no_type: + default: + SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* do we have another msg in record ? */ + if (sslFrame < recordEnd) { + Trace(ANOTHER_MSG_STR); + goto doPart; + } + + /* back to input stream instead of potential decrypt buffer */ + recordEnd = inRecordEnd; + + /* do we have more records ? */ + if (recordEnd < end) { + Trace(ANOTHER_MSG_STR); + sslFrame = recordEnd; + sslBytes = (int)(end - recordEnd); + goto doMessage; + } + + /* clear used input */ + ssl->buffers.inputBuffer.length = 0; + + /* could have more input ready now */ + if (HaveMoreInput(session, &sslFrame, &sslBytes, &end, error)) + goto doMessage; + + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + + return decoded; +} + + +/* See if we need to process any pending FIN captures */ +/* Return 0=normal, else = session removed */ +static int CheckFinCapture(IpInfo* ipInfo, TcpInfo* tcpInfo, + SnifferSession* session) +{ + int ret = 0; + if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <= + session->cliExpected) { + if (session->finCaputre.cliCounted == 0) { + session->flags.finCount += 1; + session->finCaputre.cliCounted = 1; + TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected); + } + } + + if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <= + session->srvExpected) { + if (session->finCaputre.srvCounted == 0) { + session->flags.finCount += 1; + session->finCaputre.srvCounted = 1; + TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected); + } + } + + if (session->flags.finCount >= 2) { + RemoveSession(session, ipInfo, tcpInfo, 0); + ret = 1; + } + return ret; +} + + +/* If session is in fatal error state free resources now + return true if removed, 0 otherwise */ +static int RemoveFatalSession(IpInfo* ipInfo, TcpInfo* tcpInfo, + SnifferSession* session, char* error) +{ + if (session && session->flags.fatalError == FATAL_ERROR_STATE) { + RemoveSession(session, ipInfo, tcpInfo, 0); + SetError(FATAL_ERROR_STR, error, NULL, 0); + return 1; + } + return 0; +} + + +/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */ +/* returns Number of bytes on success, 0 for no data yet, and -1 on error */ +static int ssl_DecodePacketInternal(const byte* packet, int length, + void* vChain, word32 chainSz, + byte** data, SSLInfo* sslInfo, + void* ctx, char* error) +{ + TcpInfo tcpInfo; + IpInfo ipInfo; + const byte* sslFrame; + const byte* end; + int sslBytes; /* ssl bytes unconsumed */ + int ret; + SnifferSession* session = 0; + +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + if (packet == NULL && vChain != NULL) { + struct iovec* chain = (struct iovec*)vChain; + word32 i; + + length = 0; + for (i = 0; i < chainSz; i++) + length += chain[i].iov_len; + packet = (const byte*)chain[0].iov_base; + } +#endif + + if (CheckHeaders(&ipInfo, &tcpInfo, packet, length, &sslFrame, &sslBytes, + error) != 0) + return -1; + + end = sslFrame + sslBytes; + + ret = CheckSession(&ipInfo, &tcpInfo, sslBytes, &session, error); + if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; + else if (ret == -1) return -1; + else if (ret == 1) { +#ifdef WOLFSSL_SNIFFER_STATS + if (sslBytes > 0) { + LOCK_STAT(); + NOLOCK_INC_STAT(SnifferStats.sslEncryptedPackets); + NOLOCK_ADD_TO_STAT(SnifferStats.sslEncryptedBytes, sslBytes); + UNLOCK_STAT(); + } + else + INC_STAT(SnifferStats.sslDecryptedPackets); +#endif + return 0; /* done for now */ + } + + ret = CheckSequence(&ipInfo, &tcpInfo, session, &sslBytes, &sslFrame,error); + if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; + else if (ret == -1) return -1; + else if (ret == 1) { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslDecryptedPackets); +#endif + return 0; /* done for now */ + } + + ret = CheckPreRecord(&ipInfo, &tcpInfo, &sslFrame, &session, &sslBytes, + &end, vChain, chainSz, error); + if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; + else if (ret == -1) return -1; + else if (ret == 1) { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslDecryptedPackets); +#endif + return 0; /* done for now */ + } + +#ifdef WOLFSSL_SNIFFER_STATS + if (sslBytes > 0) { + LOCK_STAT(); + NOLOCK_INC_STAT(SnifferStats.sslEncryptedPackets); + NOLOCK_ADD_TO_STAT(SnifferStats.sslEncryptedBytes, sslBytes); + UNLOCK_STAT(); + } + else + INC_STAT(SnifferStats.sslDecryptedPackets); +#endif + + ret = ProcessMessage(sslFrame, session, sslBytes, data, end, ctx, error); + if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; + if (CheckFinCapture(&ipInfo, &tcpInfo, session) == 0) { + CopySessionInfo(session, sslInfo); + } + + return ret; +} + + +/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */ +/* returns Number of bytes on success, 0 for no data yet, and -1 on error */ +/* Also returns Session Info if available */ +int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length, + unsigned char** data, SSLInfo* sslInfo, char* error) +{ + return ssl_DecodePacketInternal(packet, length, NULL, 0, data, sslInfo, + NULL, error); +} + + +/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */ +/* returns Number of bytes on success, 0 for no data yet, and -1 on error */ +int ssl_DecodePacket(const byte* packet, int length, byte** data, char* error) +{ + return ssl_DecodePacketInternal(packet, length, NULL, 0, data, NULL, NULL, + error); +} + + +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + +int ssl_DecodePacketWithSessionInfoStoreData(const unsigned char* packet, + int length, void* ctx, SSLInfo* sslInfo, char* error) +{ + return ssl_DecodePacketInternal(packet, length, NULL, 0, NULL, sslInfo, + ctx, error); +} + +#endif + + +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + +int ssl_DecodePacketWithChain(void* vChain, word32 chainSz, byte** data, + char* error) +{ + return ssl_DecodePacketInternal(NULL, 0, vChain, chainSz, data, NULL, NULL, + error); +} + +#endif + + +#if defined(WOLFSSL_SNIFFER_CHAIN_INPUT) && \ + defined(WOLFSSL_SNIFFER_STORE_DATA_CB) + +int ssl_DecodePacketWithChainSessionInfoStoreData(void* vChain, word32 chainSz, + void* ctx, SSLInfo* sslInfo, char* error) +{ + return ssl_DecodePacketInternal(NULL, 0, vChain, chainSz, NULL, sslInfo, + ctx, error); +} + +#endif + + +/* Deallocator for the decoded data buffer. */ +/* returns 0 on success, -1 on error */ +int ssl_FreeDecodeBuffer(byte** data, char* error) +{ + return ssl_FreeZeroDecodeBuffer(data, 0, error); +} + + +/* Deallocator for the decoded data buffer, zeros out buffer. */ +/* returns 0 on success, -1 on error */ +int ssl_FreeZeroDecodeBuffer(byte** data, int sz, char* error) +{ + (void)error; + + if (sz < 0) { + return -1; + } + + if (data != NULL) { + ForceZero(*data, (word32)sz); + XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *data = NULL; + } + + return 0; +} + + +/* Enables (if traceFile)/ Disables debug tracing */ +/* returns 0 on success, -1 on error */ +int ssl_Trace(const char* traceFile, char* error) +{ + if (traceFile) { + /* Don't try to reopen the file */ + if (TraceFile == NULL) { + TraceFile = fopen(traceFile, "a"); + if (!TraceFile) { + SetError(BAD_TRACE_FILE_STR, error, NULL, 0); + return -1; + } + TraceOn = 1; + } + } + else + TraceOn = 0; + + return 0; +} + + +/* Enables/Disables Recovery of missed data if later packets allow + * maxMemory is number of bytes to use for reassembly buffering per session, + * -1 means unlimited + * returns 0 on success, -1 on error */ +int ssl_EnableRecovery(int onOff, int maxMemory, char* error) +{ + (void)error; + + RecoveryEnabled = onOff; + if (onOff) + MaxRecoveryMemory = maxMemory; + + return 0; +} + + + +#ifdef WOLFSSL_SESSION_STATS + +int ssl_GetSessionStats(unsigned int* active, unsigned int* total, + unsigned int* peak, unsigned int* maxSessions, + unsigned int* missedData, unsigned int* reassemblyMem, + char* error) +{ + int ret; + + if (missedData) { + wc_LockMutex(&RecoveryMutex); + *missedData = MissedDataSessions; + wc_UnLockMutex(&RecoveryMutex); + } + + if (reassemblyMem) { + SnifferSession* session; + int i; + + *reassemblyMem = 0; + wc_LockMutex(&SessionMutex); + for (i = 0; i < HASH_SIZE; i++) { + session = SessionTable[i]; + while (session) { + *reassemblyMem += session->cliReassemblyMemory; + *reassemblyMem += session->srvReassemblyMemory; + session = session->next; + } + } + wc_UnLockMutex(&SessionMutex); + } + + ret = wolfSSL_get_session_stats(active, total, peak, maxSessions); + + if (ret == WOLFSSL_SUCCESS) + return 0; + else { + SetError(BAD_SESSION_STATS, error, NULL, 0); + return -1; + } +} + +#endif + + + +int ssl_SetConnectionCb(SSLConnCb cb) +{ + ConnectionCb = cb; + return 0; +} + + + +int ssl_SetConnectionCtx(void* ctx) +{ + ConnectionCbCtx = ctx; + return 0; +} + + +#ifdef WOLFSSL_SNIFFER_STATS + +/* Resets the statistics tracking global structure. + * returns 0 on success, -1 on error */ +int ssl_ResetStatistics(void) +{ + wc_LockMutex(&StatsMutex); + XMEMSET(&SnifferStats, 0, sizeof(SSLStats)); + wc_UnLockMutex(&StatsMutex); + return 0; +} + + +/* Copies the SSL statistics into the provided stats record. + * returns 0 on success, -1 on error */ +int ssl_ReadStatistics(SSLStats* stats) +{ + if (stats == NULL) + return -1; + + LOCK_STAT(); + XMEMCPY(stats, &SnifferStats, sizeof(SSLStats)); + UNLOCK_STAT(); + return 0; +} + +/* Copies the SSL statistics into the provided stats record then + * resets the statistics tracking global structure. + * returns 0 on success, -1 on error */ +int ssl_ReadResetStatistics(SSLStats* stats) +{ + if (stats == NULL) + return -1; + + LOCK_STAT(); + XMEMCPY(stats, &SnifferStats, sizeof(SSLStats)); + XMEMSET(&SnifferStats, 0, sizeof(SSLStats)); + UNLOCK_STAT(); + return 0; +} + +#endif /* WOLFSSL_SNIFFER_STATS */ + + +#ifdef WOLFSSL_SNIFFER_WATCH + +int ssl_SetWatchKeyCallback_ex(SSLWatchCb cb, int devId, char* error) +{ + (void)devId; + WatchCb = cb; + return CreateWatchSnifferServer(error); +} + + +int ssl_SetWatchKeyCallback(SSLWatchCb cb, char* error) +{ + WatchCb = cb; + return CreateWatchSnifferServer(error); +} + + +int ssl_SetWatchKeyCtx(void* ctx, char* error) +{ + (void)error; + WatchCbCtx = ctx; + return 0; +} + + +int ssl_SetWatchKey_buffer(void* vSniffer, const byte* key, word32 keySz, + int keyType, char* error) +{ + SnifferSession* sniffer; + int ret; + + if (vSniffer == NULL) { + return -1; + } + if (key == NULL || keySz == 0) { + return -1; + } + + sniffer = (SnifferSession*)vSniffer; + /* Remap the keyType from what the user can use to + * what wolfSSL_use_PrivateKey_buffer expects. */ + keyType = (keyType == FILETYPE_PEM) ? WOLFSSL_FILETYPE_PEM : + WOLFSSL_FILETYPE_ASN1; + + ret = wolfSSL_use_PrivateKey_buffer(sniffer->sslServer, + key, keySz, keyType); + if (ret != WOLFSSL_SUCCESS) { + SetError(KEY_FILE_STR, error, sniffer, FATAL_ERROR_STATE); + return -1; + } + + return 0; +} + + +int ssl_SetWatchKey_file(void* vSniffer, const char* keyFile, int keyType, + const char* password, char* error) +{ + byte* keyBuf = NULL; + word32 keyBufSz = 0; + int ret; + + if (vSniffer == NULL) { + return -1; + } + if (keyFile == NULL) { + return -1; + } + + /* Remap the keyType from what the user can use to + * what LoadKeyFile expects. */ + keyType = (keyType == FILETYPE_PEM) ? WOLFSSL_FILETYPE_PEM : + WOLFSSL_FILETYPE_ASN1; + + ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, keyType, password); + if (ret < 0) { + SetError(KEY_FILE_STR, error, NULL, 0); + XFREE(keyBuf, NULL, DYNAMIC_TYPE_X509); + return -1; + } + + ret = ssl_SetWatchKey_buffer(vSniffer, keyBuf, keyBufSz, FILETYPE_DER, + error); + XFREE(keyBuf, NULL, DYNAMIC_TYPE_X509); + + return ret; +} + +#endif /* WOLFSSL_SNIFFER_WATCH */ + + +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + +int ssl_SetStoreDataCallback(SSLStoreDataCb cb) +{ + StoreDataCb = cb; + return 0; +} + +#endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */ + +#endif /* WOLFSSL_SNIFFER */ +#endif /* WOLFCRYPT_ONLY */ diff --git a/client/wolfssl/src/ssl.c b/client/wolfssl/src/ssl.c new file mode 100644 index 0000000..58569f3 --- /dev/null +++ b/client/wolfssl/src/ssl.c @@ -0,0 +1,47707 @@ +/* ssl.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include +#if defined(OPENSSL_EXTRA) && !defined(_WIN32) + /* turn on GNU extensions for XVASPRINTF with wolfSSL_BIO_printf */ + #undef _GNU_SOURCE + #define _GNU_SOURCE +#endif + +#if !defined(WOLFCRYPT_ONLY) || defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) + +#ifdef HAVE_ERRNO_H + #include +#endif + +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + + +#if !defined(WOLFSSL_ALLOW_NO_SUITES) && !defined(WOLFCRYPT_ONLY) + #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(WOLFSSL_STATIC_RSA) \ + && !defined(WOLFSSL_STATIC_DH) && !defined(WOLFSSL_STATIC_PSK) \ + && !defined(HAVE_ED25519) && !defined(HAVE_ED448) + #error "No cipher suites defined because DH disabled, ECC disabled, and no static suites defined. Please see top of README" + #endif + #ifdef WOLFSSL_CERT_GEN + /* need access to Cert struct for creating certificate */ + #include + #endif +#endif + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(HAVE_WEBSERVER) || defined(WOLFSSL_KEY_GEN) + #include + /* openssl headers end, wolfssl internal headers next */ +#endif + +#include + +#ifndef NO_RSA + #include +#endif + +#ifdef OPENSSL_EXTRA + /* openssl headers begin */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + /* openssl headers end, wolfssl internal headers next */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) + #include + #endif /* WITH_STUNNEL */ + #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) + #include + #endif + #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ + && !defined(WC_NO_RNG) + #include + #endif + #if defined(HAVE_FIPS) || defined(HAVE_SELFTEST) + #include + #endif + #if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) + #include + #endif /* OPENSSL_ALL && HAVE_PKCS7 */ +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + int SetIndividualInternal(WOLFSSL_BIGNUM* bn, mp_int* mpi); + int SetIndividualExternal(WOLFSSL_BIGNUM** bn, mp_int* mpi); + int oid2nid(word32 oid, int grp); +#endif + +#if defined(WOLFSSL_QT) + #include +#endif + +#ifdef NO_ASN + #include +#endif +#endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ + +#define WOLFSSL_EVP_INCLUDED +#include "wolfcrypt/src/evp.c" + +#ifdef OPENSSL_EXTRA +/* Global pointer to constant BN on */ +static WOLFSSL_BIGNUM* bn_one = NULL; +#endif + +#ifndef WOLFCRYPT_ONLY + +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +const WOLF_EC_NIST_NAME kNistCurves[] = { + {XSTR_SIZEOF("P-192"), "P-192", NID_X9_62_prime192v1}, + {XSTR_SIZEOF("P-256"), "P-256", NID_X9_62_prime256v1}, + {XSTR_SIZEOF("P-112"), "P-112", NID_secp112r1}, + {XSTR_SIZEOF("P-112-2"), "P-112-2", NID_secp112r2}, + {XSTR_SIZEOF("P-128"), "P-128", NID_secp128r1}, + {XSTR_SIZEOF("P-128-2"), "P-128-2", NID_secp128r2}, + {XSTR_SIZEOF("P-160"), "P-160", NID_secp160r1}, + {XSTR_SIZEOF("P-160-2"), "P-160-2", NID_secp160r2}, + {XSTR_SIZEOF("P-224"), "P-224", NID_secp224r1}, + {XSTR_SIZEOF("P-384"), "P-384", NID_secp384r1}, + {XSTR_SIZEOF("P-521"), "P-521", NID_secp521r1}, + {XSTR_SIZEOF("K-160"), "K-160", NID_secp160k1}, + {XSTR_SIZEOF("K-192"), "K-192", NID_secp192k1}, + {XSTR_SIZEOF("K-224"), "K-224", NID_secp224k1}, + {XSTR_SIZEOF("K-256"), "K-256", NID_secp256k1}, + {XSTR_SIZEOF("B-160"), "B-160", NID_brainpoolP160r1}, + {XSTR_SIZEOF("B-192"), "B-192", NID_brainpoolP192r1}, + {XSTR_SIZEOF("B-224"), "B-224", NID_brainpoolP224r1}, + {XSTR_SIZEOF("B-256"), "B-256", NID_brainpoolP256r1}, + {XSTR_SIZEOF("B-320"), "B-320", NID_brainpoolP320r1}, + {XSTR_SIZEOF("B-384"), "B-384", NID_brainpoolP384r1}, + {XSTR_SIZEOF("B-512"), "B-512", NID_brainpoolP512r1}, + {0, NULL, 0}, +}; +#endif + +#if defined(WOLFSSL_RENESAS_TSIP_TLS) + /* for root ca verification */ +int tsip_tls_RootCertVerify(const byte *cert, word32 cert_len, + word32 key_n_start, word32 key_n_len, + word32 key_e_start, word32 key_e_len, + word32 cm_row); +byte tsip_rootCAverified( ); +#endif + +#ifdef WOLFSSL_SESSION_EXPORT +#ifdef WOLFSSL_DTLS +int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, unsigned int sz) +{ + WOLFSSL_ENTER("wolfSSL_session_import"); + + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + + /* sanity checks on buffer and protocol are done in internal function */ + return wolfSSL_dtls_import_internal(ssl, buf, sz); +} + + +/* Sets the function to call for serializing the session. This function is + * called right after the handshake is completed. */ +int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) +{ + + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_export"); + + /* purposefully allow func to be NULL */ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + ctx->dtls_export = func; + + return WOLFSSL_SUCCESS; +} + + +/* Sets the function in WOLFSSL struct to call for serializing the session. This + * function is called right after the handshake is completed. */ +int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) +{ + + WOLFSSL_ENTER("wolfSSL_dtls_set_export"); + + /* purposefully allow func to be NULL */ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ssl->dtls_export = func; + + return WOLFSSL_SUCCESS; +} + + +/* This function allows for directly serializing a session rather than using + * callbacks. It has less overhead by removing a temporary buffer and gives + * control over when the session gets serialized. When using callbacks the + * session is always serialized immediately after the handshake is finished. + * + * buf is the argument to contain the serialized session + * sz is the size of the buffer passed in + * ssl is the WOLFSSL struct to serialize + * returns the size of serialized session on success, 0 on no action, and + * negative value on error */ +int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) +{ + WOLFSSL_ENTER("wolfSSL_dtls_export"); + + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + + if (buf == NULL) { + *sz = MAX_EXPORT_BUFFER; + return 0; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + WOLFSSL_MSG("Currently only DTLS export is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + return wolfSSL_dtls_export_internal(ssl, buf, *sz); +} + + +/* This function is similar to wolfSSL_dtls_export but only exports the portion + * of the WOLFSSL structure related to the state of the connection, i.e. peer + * sequence number, epoch, AEAD state etc. + * + * buf is the argument to contain the serialized state, if null then set "sz" to + * buffer size required + * sz is the size of the buffer passed in + * ssl is the WOLFSSL struct to serialize + * returns the size of serialized session on success, 0 on no action, and + * negative value on error */ +int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf, + unsigned int* sz) +{ + WOLFSSL_ENTER("wolfSSL_dtls_export_state_only"); + + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + + if (buf == NULL) { + *sz = MAX_EXPORT_STATE_BUFFER; + return 0; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + WOLFSSL_MSG("Currently only DTLS export state is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + return wolfSSL_dtls_export_state_internal(ssl, buf, *sz); +} + + +/* returns 0 on success */ +int wolfSSL_send_session(WOLFSSL* ssl) +{ + int ret; + byte* buf; + word16 bufSz = MAX_EXPORT_BUFFER; + + WOLFSSL_ENTER("wolfSSL_send_session"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + buf = (byte*)XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + return MEMORY_E; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_MSG("Currently only DTLS export is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + ret = wolfSSL_dtls_export_internal(ssl, buf, bufSz); + if (ret < 0) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + /* if no error ret has size of buffer */ + ret = ssl->dtls_export(ssl, buf, ret, NULL); + if (ret != WOLFSSL_SUCCESS) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return 0; +} +#endif /* WOLFSSL_DTLS */ +#endif /* WOLFSSL_SESSION_EXPORT */ + +/* prevent multiple mutex initializations */ +static volatile WOLFSSL_GLOBAL int initRefCount = 0; +static WOLFSSL_GLOBAL wolfSSL_Mutex count_mutex; /* init ref count mutex */ + +/* Create a new WOLFSSL_CTX struct and return the pointer to created struct. + WOLFSSL_METHOD pointer passed in is given to ctx to manage. + This function frees the passed in WOLFSSL_METHOD struct on failure and on + success is freed when ctx is freed. + */ +WOLFSSL_CTX* wolfSSL_CTX_new_ex(WOLFSSL_METHOD* method, void* heap) +{ + WOLFSSL_CTX* ctx = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_new_ex"); + + if (initRefCount == 0) { + /* user no longer forced to call Init themselves */ + int ret = wolfSSL_Init(); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_Init failed"); + WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0); + if (method != NULL) { + XFREE(method, heap, DYNAMIC_TYPE_METHOD); + } + return NULL; + } + } + + if (method == NULL) + return ctx; + + ctx = (WOLFSSL_CTX*) XMALLOC(sizeof(WOLFSSL_CTX), heap, DYNAMIC_TYPE_CTX); + if (ctx) { + int ret; + + ret = InitSSL_Ctx(ctx, method, heap); + #ifdef WOLFSSL_STATIC_MEMORY + if (heap != NULL) { + ctx->onHeap = 1; /* free the memory back to heap when done */ + } + #endif + if (ret < 0) { + WOLFSSL_MSG("Init CTX failed"); + wolfSSL_CTX_free(ctx); + ctx = NULL; + } +#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \ + && !defined(NO_SHA256) && !defined(WC_NO_RNG) + else { + ctx->srp = (Srp*) XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP); + if (ctx->srp == NULL){ + WOLFSSL_MSG("Init CTX failed"); + wolfSSL_CTX_free(ctx); + return NULL; + } + XMEMSET(ctx->srp, 0, sizeof(Srp)); + } +#endif + } + else { + WOLFSSL_MSG("Alloc CTX failed, method freed"); + XFREE(method, heap, DYNAMIC_TYPE_METHOD); + } + + + WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0); + return ctx; +} + + +WOLFSSL_ABI +WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD* method) +{ +#ifdef WOLFSSL_HEAP_TEST + /* if testing the heap hint then set top level CTX to have test value */ + return wolfSSL_CTX_new_ex(method, (void*)WOLFSSL_HEAP_TEST); +#else + return wolfSSL_CTX_new_ex(method, NULL); +#endif +} + +#ifdef OPENSSL_EXTRA +/* increases CTX reference count to track proper time to "free" */ +int wolfSSL_CTX_up_ref(WOLFSSL_CTX* ctx) +{ + int refCount = SSL_CTX_RefCount(ctx, 1); + return ((refCount > 1) ? 1 : 0); +} +#endif + +WOLFSSL_ABI +void wolfSSL_CTX_free(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("SSL_CTX_free"); + if (ctx) { +#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \ +&& !defined(NO_SHA256) && !defined(WC_NO_RNG) + if (ctx->srp != NULL){ + if (ctx->srp_password != NULL){ + XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP); + ctx->srp_password = NULL; + } + wc_SrpTerm(ctx->srp); + XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP); + ctx->srp = NULL; + } +#endif + FreeSSL_Ctx(ctx); + } + + WOLFSSL_LEAVE("SSL_CTX_free", 0); +} + + +#ifdef HAVE_ENCRYPT_THEN_MAC +/** + * Sets whether Encrypt-Then-MAC extension can be negotiated against context. + * The default value: enabled. + * + * ctx SSL/TLS context. + * set Whether to allow or not: 1 is allow and 0 is disallow. + * returns WOLFSSL_SUCCESS + */ +int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *ctx, int set) +{ + ctx->disallowEncThenMac = !set; + return WOLFSSL_SUCCESS; +} + +/** + * Sets whether Encrypt-Then-MAC extension can be negotiated against context. + * The default value comes from context. + * + * ctx SSL/TLS context. + * set Whether to allow or not: 1 is allow and 0 is disallow. + * returns WOLFSSL_SUCCESS + */ +int wolfSSL_AllowEncryptThenMac(WOLFSSL *ssl, int set) +{ + ssl->options.disallowEncThenMac = !set; + return WOLFSSL_SUCCESS; +} +#endif + +#ifdef SINGLE_THREADED +/* no locking in single threaded mode, allow a CTX level rng to be shared with + * WOLFSSL objects, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_new_rng(WOLFSSL_CTX* ctx) +{ + WC_RNG* rng; + int ret; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ctx->heap, DYNAMIC_TYPE_RNG); + if (rng == NULL) { + return MEMORY_E; + } + +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(rng, ctx->heap, ctx->devId); +#else + ret = wc_InitRng(rng); +#endif + if (ret != 0) { + XFREE(rng, ctx->heap, DYNAMIC_TYPE_RNG); + return ret; + } + + ctx->rng = rng; + return WOLFSSL_SUCCESS; +} +#endif + + +WOLFSSL_ABI +WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx) +{ + WOLFSSL* ssl = NULL; + int ret = 0; + + (void)ret; + WOLFSSL_ENTER("SSL_new"); + + if (ctx == NULL) + return ssl; + + ssl = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ctx->heap, DYNAMIC_TYPE_SSL); + if (ssl) + if ( (ret = InitSSL(ssl, ctx, 0)) < 0) { + FreeSSL(ssl, ctx->heap); + ssl = 0; + } + + WOLFSSL_LEAVE("SSL_new", ret); + return ssl; +} + + +WOLFSSL_ABI +void wolfSSL_free(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_free"); + if (ssl) + FreeSSL(ssl, ssl->ctx->heap); + WOLFSSL_LEAVE("SSL_free", 0); +} + + +int wolfSSL_is_server(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + return ssl->options.side == WOLFSSL_SERVER_END; +} + +#ifdef HAVE_WRITE_DUP + +/* + * Release resources around WriteDup object + * + * ssl WOLFSSL object + * + * no return, destruction so make best attempt +*/ +void FreeWriteDup(WOLFSSL* ssl) +{ + int doFree = 0; + + WOLFSSL_ENTER("FreeWriteDup"); + + if (ssl->dupWrite) { + if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) { + ssl->dupWrite->dupCount--; + if (ssl->dupWrite->dupCount == 0) { + doFree = 1; + } else { + WOLFSSL_MSG("WriteDup count not zero, no full free"); + } + wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + } + + if (doFree) { + WOLFSSL_MSG("Doing WriteDup full free, count to zero"); + wc_FreeMutex(&ssl->dupWrite->dupMutex); + XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); + } +} + + +/* + * duplicate existing ssl members into dup needed for writing + * + * dup write only WOLFSSL + * ssl existing WOLFSSL + * + * 0 on success +*/ +static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl) +{ + /* shared dupWrite setup */ + ssl->dupWrite = (WriteDup*)XMALLOC(sizeof(WriteDup), ssl->heap, + DYNAMIC_TYPE_WRITEDUP); + if (ssl->dupWrite == NULL) { + return MEMORY_E; + } + XMEMSET(ssl->dupWrite, 0, sizeof(WriteDup)); + + if (wc_InitMutex(&ssl->dupWrite->dupMutex) != 0) { + XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); + ssl->dupWrite = NULL; + return BAD_MUTEX_E; + } + ssl->dupWrite->dupCount = 2; /* both sides have a count to start */ + dup->dupWrite = ssl->dupWrite; /* each side uses */ + + /* copy write parts over to dup writer */ + XMEMCPY(&dup->specs, &ssl->specs, sizeof(CipherSpecs)); + XMEMCPY(&dup->options, &ssl->options, sizeof(Options)); + XMEMCPY(&dup->keys, &ssl->keys, sizeof(Keys)); + XMEMCPY(&dup->encrypt, &ssl->encrypt, sizeof(Ciphers)); + /* dup side now owns encrypt/write ciphers */ + XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers)); + + dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx; + dup->wfd = ssl->wfd; + dup->wflags = ssl->wflags; + dup->hmac = ssl->hmac; +#ifdef HAVE_TRUNCATED_HMAC + dup->truncated_hmac = ssl->truncated_hmac; +#endif + + /* unique side dup setup */ + dup->dupSide = WRITE_DUP_SIDE; + ssl->dupSide = READ_DUP_SIDE; + + return 0; +} + + +/* + * duplicate a WOLFSSL object post handshake for writing only + * turn existing object into read only. Allows concurrent access from two + * different threads. + * + * ssl existing WOLFSSL object + * + * return dup'd WOLFSSL object on success +*/ +WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) +{ + WOLFSSL* dup = NULL; + int ret = 0; + + (void)ret; + WOLFSSL_ENTER("wolfSSL_write_dup"); + + if (ssl == NULL) { + return ssl; + } + + if (ssl->options.handShakeDone == 0) { + WOLFSSL_MSG("wolfSSL_write_dup called before handshake complete"); + return NULL; + } + + if (ssl->dupWrite) { + WOLFSSL_MSG("wolfSSL_write_dup already called once"); + return NULL; + } + + dup = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ssl->ctx->heap, DYNAMIC_TYPE_SSL); + if (dup) { + if ( (ret = InitSSL(dup, ssl->ctx, 1)) < 0) { + FreeSSL(dup, ssl->ctx->heap); + dup = NULL; + } else if ( (ret = DupSSL(dup, ssl)) < 0) { + FreeSSL(dup, ssl->ctx->heap); + dup = NULL; + } + } + + WOLFSSL_LEAVE("wolfSSL_write_dup", ret); + + return dup; +} + + +/* + * Notify write dup side of fatal error or close notify + * + * ssl WOLFSSL object + * err Notify err + * + * 0 on success +*/ +int NotifyWriteSide(WOLFSSL* ssl, int err) +{ + int ret; + + WOLFSSL_ENTER("NotifyWriteSide"); + + ret = wc_LockMutex(&ssl->dupWrite->dupMutex); + if (ret == 0) { + ssl->dupWrite->dupErr = err; + ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + + return ret; +} + + +#endif /* HAVE_WRITE_DUP */ + + +#ifdef HAVE_POLY1305 +/* set if to use old poly 1 for yes 0 to use new poly */ +int wolfSSL_use_old_poly(WOLFSSL* ssl, int value) +{ + (void)ssl; + (void)value; + +#ifndef WOLFSSL_NO_TLS12 + WOLFSSL_ENTER("SSL_use_old_poly"); + WOLFSSL_MSG("Warning SSL connection auto detects old/new and this function" + "is depreciated"); + ssl->options.oldPoly = (word16)value; + WOLFSSL_LEAVE("SSL_use_old_poly", 0); +#endif + return 0; +} +#endif + + +WOLFSSL_ABI +int wolfSSL_set_fd(WOLFSSL* ssl, int fd) +{ + int ret; + + WOLFSSL_ENTER("SSL_set_fd"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ret = wolfSSL_set_read_fd(ssl, fd); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_set_write_fd(ssl, fd); + } + + return ret; +} + + +int wolfSSL_set_read_fd(WOLFSSL* ssl, int fd) +{ + WOLFSSL_ENTER("SSL_set_read_fd"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ssl->rfd = fd; /* not used directly to allow IO callbacks */ + ssl->IOCB_ReadCtx = &ssl->rfd; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx; + ssl->buffers.dtlsCtx.rfd = fd; + } + #endif + + WOLFSSL_LEAVE("SSL_set_read_fd", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_set_write_fd(WOLFSSL* ssl, int fd) +{ + WOLFSSL_ENTER("SSL_set_write_fd"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ssl->wfd = fd; /* not used directly to allow IO callbacks */ + ssl->IOCB_WriteCtx = &ssl->wfd; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx; + ssl->buffers.dtlsCtx.wfd = fd; + } + #endif + + WOLFSSL_LEAVE("SSL_set_write_fd", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} + + +/** + * Get the name of cipher at priority level passed in. + */ +char* wolfSSL_get_cipher_list(int priority) +{ + const CipherSuiteInfo* ciphers = GetCipherNames(); + + if (priority >= GetCipherNamesSize() || priority < 0) { + return 0; + } + + return (char*)ciphers[priority].name; +} + + +/** + * Get the name of cipher at priority level passed in. + */ +char* wolfSSL_get_cipher_list_ex(WOLFSSL* ssl, int priority) +{ + + if (ssl == NULL) { + return NULL; + } + else { + const char* cipher; + + if ((cipher = wolfSSL_get_cipher_name_internal(ssl)) != NULL) { + if (priority == 0) { + return (char*)cipher; + } + else { + return NULL; + } + } + else { + return wolfSSL_get_cipher_list(priority); + } + } +} + + +int wolfSSL_get_ciphers(char* buf, int len) +{ + const CipherSuiteInfo* ciphers = GetCipherNames(); + int ciphersSz = GetCipherNamesSize(); + int i; + int cipherNameSz; + + if (buf == NULL || len <= 0) + return BAD_FUNC_ARG; + + /* Add each member to the buffer delimited by a : */ + for (i = 0; i < ciphersSz; i++) { + cipherNameSz = (int)XSTRLEN(ciphers[i].name); + if (cipherNameSz + 1 < len) { + XSTRNCPY(buf, ciphers[i].name, len); + buf += cipherNameSz; + + if (i < ciphersSz - 1) + *buf++ = ':'; + *buf = 0; + + len -= cipherNameSz + 1; + } + else + return BUFFER_E; + } + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_ERROR_STRINGS +/* places a list of all supported cipher suites in TLS_* format into "buf" + * return WOLFSSL_SUCCESS on success */ +int wolfSSL_get_ciphers_iana(char* buf, int len) +{ + const CipherSuiteInfo* ciphers = GetCipherNames(); + int ciphersSz = GetCipherNamesSize(); + int i; + int cipherNameSz; + + if (buf == NULL || len <= 0) + return BAD_FUNC_ARG; + + /* Add each member to the buffer delimited by a : */ + for (i = 0; i < ciphersSz; i++) { + cipherNameSz = (int)XSTRLEN(ciphers[i].name_iana); + if (cipherNameSz + 1 < len) { + XSTRNCPY(buf, ciphers[i].name_iana, len); + buf += cipherNameSz; + + if (i < ciphersSz - 1) + *buf++ = ':'; + *buf = 0; + + len -= cipherNameSz + 1; + } + else + return BUFFER_E; + } + return WOLFSSL_SUCCESS; +} +#endif /* NO_ERROR_STRINGS */ + + +const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len) +{ + const char* cipher; + + if (ssl == NULL) + return NULL; + + cipher = wolfSSL_get_cipher_name_iana(ssl); + len = min(len, (int)(XSTRLEN(cipher) + 1)); + XMEMCPY(buf, cipher, len); + return buf; +} + +int wolfSSL_get_fd(const WOLFSSL* ssl) +{ + int fd = -1; + WOLFSSL_ENTER("SSL_get_fd"); + if (ssl) { + fd = ssl->rfd; + } + WOLFSSL_LEAVE("SSL_get_fd", fd); + return fd; +} + + +int wolfSSL_dtls(WOLFSSL* ssl) +{ + int dtlsOpt = 0; + if (ssl) + dtlsOpt = ssl->options.dtls; + return dtlsOpt; +} + +#if !defined(NO_CERTS) +/* Set whether mutual authentication is required for connections. + * Server side only. + * + * ctx The SSL/TLS CTX object. + * req 1 to indicate required and 0 when not. + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and + * 0 on success. + */ +int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + ctx->mutualAuth = (byte)req; + + return 0; +} + +/* Set whether mutual authentication is required for the connection. + * Server side only. + * + * ssl The SSL/TLS object. + * req 1 to indicate required and 0 when not. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SIDE_ERROR when not a client and 0 on success. + */ +int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.mutualAuth = (word16)req; + + return 0; +} +#endif /* NO_CERTS */ + +#ifndef WOLFSSL_LEANPSK +int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) +{ +#ifdef WOLFSSL_DTLS + void* sa; + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR); + if (sa != NULL) { + if (ssl->buffers.dtlsCtx.peer.sa != NULL) { + XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.peer.sa = NULL; + } + XMEMCPY(sa, peer, peerSz); + ssl->buffers.dtlsCtx.peer.sa = sa; + ssl->buffers.dtlsCtx.peer.sz = peerSz; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + +int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) +{ +#ifdef WOLFSSL_DTLS + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + + if (peer != NULL && peerSz != NULL + && *peerSz >= ssl->buffers.dtlsCtx.peer.sz + && ssl->buffers.dtlsCtx.peer.sa != NULL) { + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + + +#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) + +int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp()"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->dtlsSctp = 1; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_set_sctp()"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.dtlsSctp = 1; + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ + +#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ + defined(WOLFSSL_DTLS) + +int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) +{ + if (ctx == NULL || newMtu > MAX_RECORD_SIZE) + return BAD_FUNC_ARG; + + ctx->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (newMtu > MAX_RECORD_SIZE) { + ssl->error = BAD_FUNC_ARG; + return WOLFSSL_FAILURE; + } + + ssl->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ + + +#ifdef WOLFSSL_DTLS_DROP_STATS + +int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, + word32* macDropCount, word32* replayDropCount) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats()"); + + if (ssl == NULL) + ret = BAD_FUNC_ARG; + else { + ret = WOLFSSL_SUCCESS; + if (macDropCount != NULL) + *macDropCount = ssl->macDropCount; + if (replayDropCount != NULL) + *replayDropCount = ssl->replayDropCount; + } + + WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats()", ret); + return ret; +} + +#endif /* WOLFSSL_DTLS_DROP_STATS */ + + +#if defined(WOLFSSL_MULTICAST) + +int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id()"); + + if (ctx == NULL || id > 255) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + ctx->haveEMS = 0; + ctx->haveMcast = 1; + ctx->mcastID = (byte)id; +#ifndef WOLFSSL_USER_IO + ctx->CBIORecv = EmbedReceiveFromMcast; +#endif /* WOLFSSL_USER_IO */ + + ret = WOLFSSL_SUCCESS; + } + WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id()", ret); + return ret; +} + +int wolfSSL_mcast_get_max_peers(void) +{ + return WOLFSSL_MULTICAST_PEERS; +} + +#ifdef WOLFSSL_DTLS +static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 max) +{ + word32 newCur = 0; + + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < max) + newCur = max; + + return newCur; +} +#endif /* WOLFSSL_DTLS */ + + +int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, + const byte* preMasterSecret, word32 preMasterSz, + const byte* clientRandom, const byte* serverRandom, + const byte* suite) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_set_secret()"); + + if (ssl == NULL || preMasterSecret == NULL || + preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || + clientRandom == NULL || serverRandom == NULL || suite == NULL) { + + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); + ssl->arrays->preMasterSz = preMasterSz; + XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); + XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); + ssl->options.cipherSuite0 = suite[0]; + ssl->options.cipherSuite = suite[1]; + + ret = SetCipherSpecs(ssl); + } + + if (ret == 0) + ret = MakeTlsMasterSecret(ssl); + + if (ret == 0) { + ssl->keys.encryptionOn = 1; + ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + } + + if (ret == 0) { + if (ssl->options.dtls) { + #ifdef WOLFSSL_DTLS + WOLFSSL_DTLS_PEERSEQ* peerSeq; + int i; + + ssl->keys.dtls_epoch = epoch; + for (i = 0, peerSeq = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, peerSeq++) { + + peerSeq->nextEpoch = epoch; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + #else + (void)epoch; + #endif + } + FreeHandshakeResources(ssl); + ret = WOLFSSL_SUCCESS; + } + else { + if (ssl) + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_set_secret()", ret); + return ret; +} + + +#ifdef WOLFSSL_DTLS + +int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int remove) +{ + WOLFSSL_DTLS_PEERSEQ* p = NULL; + int ret = WOLFSSL_SUCCESS; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_add()"); + if (ssl == NULL || peerId > 255) + return BAD_FUNC_ARG; + + if (!remove) { + /* Make sure it isn't already present, while keeping the first + * open spot. */ + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) + p = &ssl->keys.peerSeq[i]; + if (ssl->keys.peerSeq[i].peerId == peerId) { + WOLFSSL_MSG("Peer ID already in multicast peer list."); + p = NULL; + } + } + + if (p != NULL) { + XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); + p->peerId = peerId; + p->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + else { + WOLFSSL_MSG("No room in peer list."); + ret = -1; + } + } + else { + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) + p = &ssl->keys.peerSeq[i]; + } + + if (p != NULL) { + p->peerId = INVALID_PEER_ID; + } + else { + WOLFSSL_MSG("Peer not found in list."); + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_add()", ret); + return ret; +} + + +/* If peerId is in the list of peers and its last sequence number is non-zero, + * return 1, otherwise return 0. */ +int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) +{ + int known = 0; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_known()"); + + if (ssl == NULL || peerId > 255) { + return BAD_FUNC_ARG; + } + + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) { + if (ssl->keys.peerSeq[i].nextSeq_hi || + ssl->keys.peerSeq[i].nextSeq_lo) { + + known = 1; + } + break; + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_known()", known); + return known; +} + + +int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, + word32 first, word32 second, + CallbackMcastHighwater cb) +{ + if (ctx == NULL || (second && first > second) || + first > maxSeq || second > maxSeq || cb == NULL) { + + return BAD_FUNC_ARG; + } + + ctx->mcastHwCb = cb; + ctx->mcastFirstSeq = first; + ctx->mcastSecondSeq = second; + ctx->mcastMaxSeq = maxSeq; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) +{ + if (ssl == NULL || ctx == NULL) + return BAD_FUNC_ARG; + + ssl->mcastHwCbCtx = ctx; + + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS */ + +#endif /* WOLFSSL_MULTICAST */ + + +#endif /* WOLFSSL_LEANPSK */ + + +/* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ +int wolfSSL_negotiate(WOLFSSL* ssl) +{ + int err = WOLFSSL_FATAL_ERROR; + + WOLFSSL_ENTER("wolfSSL_negotiate"); +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_accept_TLSv13(ssl); + else +#endif + err = wolfSSL_accept(ssl); + } +#endif + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_connect_TLSv13(ssl); + else +#endif + err = wolfSSL_connect(ssl); + } +#endif + + (void)ssl; + + WOLFSSL_LEAVE("wolfSSL_negotiate", err); + + return err; +} + + +WOLFSSL_ABI +WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) +{ + if (ssl) { + return ssl->rng; + } + + return NULL; +} + + +#ifndef WOLFSSL_LEANPSK +/* object size based on build */ +int wolfSSL_GetObjectSize(void) +{ +#ifdef SHOW_SIZES + printf("sizeof suites = %lu\n", (unsigned long)sizeof(Suites)); + printf("sizeof ciphers(2) = %lu\n", (unsigned long)sizeof(Ciphers)); +#ifndef NO_RC4 + printf("\tsizeof arc4 = %lu\n", (unsigned long)sizeof(Arc4)); +#endif + printf("\tsizeof aes = %lu\n", (unsigned long)sizeof(Aes)); +#ifndef NO_DES3 + printf("\tsizeof des3 = %lu\n", (unsigned long)sizeof(Des3)); +#endif +#ifndef NO_RABBIT + printf("\tsizeof rabbit = %lu\n", (unsigned long)sizeof(Rabbit)); +#endif +#ifdef HAVE_CHACHA + printf("\tsizeof chacha = %lu\n", (unsigned long)sizeof(ChaCha)); +#endif + printf("sizeof cipher specs = %lu\n", (unsigned long)sizeof(CipherSpecs)); + printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); + printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); +#ifndef NO_MD5 + printf("\tsizeof MD5 = %lu\n", (unsigned long)sizeof(wc_Md5)); +#endif +#ifndef NO_SHA + printf("\tsizeof SHA = %lu\n", (unsigned long)sizeof(wc_Sha)); +#endif +#ifdef WOLFSSL_SHA224 + printf("\tsizeof SHA224 = %lu\n", (unsigned long)sizeof(wc_Sha224)); +#endif +#ifndef NO_SHA256 + printf("\tsizeof SHA256 = %lu\n", (unsigned long)sizeof(wc_Sha256)); +#endif +#ifdef WOLFSSL_SHA384 + printf("\tsizeof SHA384 = %lu\n", (unsigned long)sizeof(wc_Sha384)); +#endif +#ifdef WOLFSSL_SHA384 + printf("\tsizeof SHA512 = %lu\n", (unsigned long)sizeof(wc_Sha512)); +#endif + printf("sizeof Buffers = %lu\n", (unsigned long)sizeof(Buffers)); + printf("sizeof Options = %lu\n", (unsigned long)sizeof(Options)); + printf("sizeof Arrays = %lu\n", (unsigned long)sizeof(Arrays)); +#ifndef NO_RSA + printf("sizeof RsaKey = %lu\n", (unsigned long)sizeof(RsaKey)); +#endif +#ifdef HAVE_ECC + printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); +#endif + printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long)sizeof(WOLFSSL_CIPHER)); + printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long)sizeof(WOLFSSL_SESSION)); + printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); + printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long)sizeof(WOLFSSL_CTX)); +#endif + + return sizeof(WOLFSSL); +} + +int wolfSSL_CTX_GetObjectSize(void) +{ + return sizeof(WOLFSSL_CTX); +} + +int wolfSSL_METHOD_GetObjectSize(void) +{ + return sizeof(WOLFSSL_METHOD); +} +#endif + + +#ifdef WOLFSSL_STATIC_MEMORY + +int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, wolfSSL_method_func method, + unsigned char* buf, unsigned int sz, + int flag, int max) +{ + WOLFSSL_HEAP* heap; + WOLFSSL_HEAP_HINT* hint; + word32 idx = 0; + + if (ctx == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + + if (*ctx == NULL && method == NULL) { + return BAD_FUNC_ARG; + } + + if (*ctx == NULL || (*ctx)->heap == NULL) { + if (sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT) > sz - idx) { + return BUFFER_E; /* not enough memory for structures */ + } + heap = (WOLFSSL_HEAP*)buf; + idx += sizeof(WOLFSSL_HEAP); + if (wolfSSL_init_memory_heap(heap) != 0) { + return WOLFSSL_FAILURE; + } + hint = (WOLFSSL_HEAP_HINT*)(buf + idx); + idx += sizeof(WOLFSSL_HEAP_HINT); + XMEMSET(hint, 0, sizeof(WOLFSSL_HEAP_HINT)); + hint->memory = heap; + + if (*ctx && (*ctx)->heap == NULL) { + (*ctx)->heap = (void*)hint; + } + } + else { +#ifdef WOLFSSL_HEAP_TEST + /* do not load in memory if test has been set */ + if ((*ctx)->heap == (void*)WOLFSSL_HEAP_TEST) { + return WOLFSSL_SUCCESS; + } +#endif + hint = (WOLFSSL_HEAP_HINT*)((*ctx)->heap); + heap = hint->memory; + } + + if (wolfSSL_load_static_memory(buf + idx, sz - idx, flag, heap) != 1) { + WOLFSSL_MSG("Error partitioning memory"); + return WOLFSSL_FAILURE; + } + + /* create ctx if needed */ + if (*ctx == NULL) { + *ctx = wolfSSL_CTX_new_ex(method(hint), hint); + if (*ctx == NULL) { + WOLFSSL_MSG("Error creating ctx"); + return WOLFSSL_FAILURE; + } + } + + /* determine what max applies too */ + if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) { + heap->maxIO = max; + } + else { /* general memory used in handshakes */ + heap->maxHa = max; + } + + heap->flag |= flag; + + (void)max; + (void)method; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + WOLFSSL_ENTER("wolfSSL_is_static_memory"); + + /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ + if (mem_stats != NULL && ssl->heap != NULL) { + WOLFSSL_HEAP_HINT* hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); + WOLFSSL_HEAP* heap = hint->memory; + if (heap->flag & WOLFMEM_TRACK_STATS && hint->stats != NULL) { + XMEMCPY(mem_stats, hint->stats, sizeof(WOLFSSL_MEM_CONN_STATS)); + } + } + + return (ssl->heap) ? 1 : 0; +} + + +int wolfSSL_CTX_is_static_memory(WOLFSSL_CTX* ctx, WOLFSSL_MEM_STATS* mem_stats) +{ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + WOLFSSL_ENTER("wolfSSL_CTX_is_static_memory"); + + /* fill out statistics if wanted */ + if (mem_stats != NULL && ctx->heap != NULL) { + WOLFSSL_HEAP* heap = ((WOLFSSL_HEAP_HINT*)(ctx->heap))->memory; + if (wolfSSL_GetMemStats(heap, mem_stats) != 1) { + return MEMORY_E; + } + } + + return (ctx->heap) ? 1 : 0; +} + +#endif /* WOLFSSL_STATIC_MEMORY */ + + +/* return max record layer size plaintext input size */ +int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + WOLFSSL_MSG("Handshake not complete yet"); + return BAD_FUNC_ARG; + } + + return wolfSSL_GetMaxRecordSize(ssl, OUTPUT_RECORD_SIZE); +} + + +/* return record layer size of plaintext input size */ +int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) +{ + int maxSize; + + WOLFSSL_ENTER("wolfSSL_GetOutputSize"); + + if (inSz < 0) + return BAD_FUNC_ARG; + + maxSize = wolfSSL_GetMaxOutputSize(ssl); + if (maxSize < 0) + return maxSize; /* error */ + if (inSz > maxSize) + return INPUT_SIZE_E; + + return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0); +} + + +#ifdef HAVE_ECC +int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); + return BAD_FUNC_ARG; + } + + ctx->minEccKeySz = keySz / 8; +#ifndef NO_CERTS + ctx->cm->minEccKeySz = keySz / 8; +#endif + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) +{ + if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); + return BAD_FUNC_ARG; + } + + ssl->options.minEccKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} + +#endif /* !NO_RSA */ + +#ifndef NO_RSA +int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); + return BAD_FUNC_ARG; + } + + ctx->minRsaKeySz = keySz / 8; + ctx->cm->minRsaKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) +{ + if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); + return BAD_FUNC_ARG; + } + + ssl->options.minRsaKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} +#endif /* !NO_RSA */ + +#ifndef NO_DH +/* server Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, + const unsigned char* g, int gSz) +{ + WOLFSSL_ENTER("wolfSSL_SetTmpDH"); + + if (ssl == NULL || p == NULL || g == NULL) + return BAD_FUNC_ARG; + + if ((word16)pSz < ssl->options.minDhKeySz) + return DH_KEY_SIZE_E; + if ((word16)pSz > ssl->options.maxDhKeySz) + return DH_KEY_SIZE_E; + + /* this function is for server only */ + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ssl->options.dhKeyTested = 0; + ssl->options.dhDoKeyTest = 1; + #endif + + if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ssl->buffers.serverDH_P.buffer = NULL; + } + if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ssl->buffers.serverDH_G.buffer = NULL; + } + + ssl->buffers.weOwnDH = 1; /* SSL owns now */ + ssl->buffers.serverDH_P.buffer = (byte*)XMALLOC(pSz, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (ssl->buffers.serverDH_P.buffer == NULL) + return MEMORY_E; + + ssl->buffers.serverDH_G.buffer = (byte*)XMALLOC(gSz, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (ssl->buffers.serverDH_G.buffer == NULL) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ssl->buffers.serverDH_P.buffer = NULL; + return MEMORY_E; + } + + ssl->buffers.serverDH_P.length = pSz; + ssl->buffers.serverDH_G.length = gSz; + + XMEMCPY(ssl->buffers.serverDH_P.buffer, p, pSz); + XMEMCPY(ssl->buffers.serverDH_G.buffer, g, gSz); + + ssl->options.haveDH = 1; + + if (ssl->options.side != WOLFSSL_NEITHER_END) { + word16 havePSK; + word16 haveRSA; + int keySz = 0; + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #else + havePSK = 0; + #endif + #ifdef NO_RSA + haveRSA = 0; + #else + haveRSA = 1; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + + WOLFSSL_LEAVE("wolfSSL_SetTmpDH", 0); + + return WOLFSSL_SUCCESS; +} + + +#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) +/* Enables or disables the session's DH key prime test. */ +int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) +{ + WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (!enable) + ssl->options.dhDoKeyTest = 0; + else + ssl->options.dhDoKeyTest = 1; + + WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} +#endif + + +/* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, + const unsigned char* g, int gSz) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH"); + if (ctx == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; + + if ((word16)pSz < ctx->minDhKeySz) + return DH_KEY_SIZE_E; + if ((word16)pSz > ctx->maxDhKeySz) + return DH_KEY_SIZE_E; + + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + { + DhKey checkKey; + WC_RNG rng; + int error, freeKey = 0; + + error = wc_InitRng(&rng); + if (!error) + error = wc_InitDhKey(&checkKey); + if (!error) { + freeKey = 1; + error = wc_DhSetCheckKey(&checkKey, + p, pSz, g, gSz, NULL, 0, 0, &rng); + } + if (freeKey) + wc_FreeDhKey(&checkKey); + wc_FreeRng(&rng); + if (error) + return error; + + ctx->dhKeyTested = 1; + } + #endif + + XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ctx->serverDH_P.buffer = NULL; + XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ctx->serverDH_G.buffer = NULL; + + ctx->serverDH_P.buffer = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ctx->serverDH_P.buffer == NULL) + return MEMORY_E; + + ctx->serverDH_G.buffer = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ctx->serverDH_G.buffer == NULL) { + XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + ctx->serverDH_P.buffer = NULL; + return MEMORY_E; + } + + ctx->serverDH_P.length = pSz; + ctx->serverDH_G.length = gSz; + + XMEMCPY(ctx->serverDH_P.buffer, p, pSz); + XMEMCPY(ctx->serverDH_G.buffer, g, gSz); + + ctx->haveDH = 1; + + WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0); + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz) +{ + if (ctx == NULL || keySz > 16000 || keySz % 8 != 0) + return BAD_FUNC_ARG; + + ctx->minDhKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz) +{ + if (ssl == NULL || keySz > 16000 || keySz % 8 != 0) + return BAD_FUNC_ARG; + + ssl->options.minDhKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz) +{ + if (ctx == NULL || keySz > 16000 || keySz % 8 != 0) + return BAD_FUNC_ARG; + + ctx->maxDhKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz) +{ + if (ssl == NULL || keySz > 16000 || keySz % 8 != 0) + return BAD_FUNC_ARG; + + ssl->options.maxDhKeySz = keySz / 8; + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return (ssl->options.dhKeySz * 8); +} + +#endif /* !NO_DH */ + + +WOLFSSL_ABI +int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) +{ + int ret; + + WOLFSSL_ENTER("SSL_write()"); + + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data && (ret = wolfSSL_negotiate(ssl)) < 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; + } + ssl->earlyData = no_early_data; +#endif + +#ifdef HAVE_WRITE_DUP + { /* local variable scope */ + int dupErr = 0; /* local copy */ + + ret = 0; + + if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { + WOLFSSL_MSG("Read dup side cannot write"); + return WRITE_DUP_WRITE_E; + } + if (ssl->dupWrite) { + if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) { + return BAD_MUTEX_E; + } + dupErr = ssl->dupWrite->dupErr; + ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + + if (ret != 0) { + ssl->error = ret; /* high priority fatal error */ + return WOLFSSL_FATAL_ERROR; + } + if (dupErr != 0) { + WOLFSSL_MSG("Write dup error from other side"); + ssl->error = dupErr; + return WOLFSSL_FATAL_ERROR; + } + } +#endif + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_WRITE, SSL_SUCCESS); + ssl->cbmode = SSL_CB_WRITE; + } + #endif + ret = SendData(ssl, data, sz); + + WOLFSSL_LEAVE("SSL_write()", ret); + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} + +static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_read_internal()"); + + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; + +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { + WOLFSSL_MSG("Write dup side cannot read"); + return WRITE_DUP_READ_E; + } +#endif + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + ssl->dtls_expected_rx = max(sz + 100, MAX_MTU); +#ifdef WOLFSSL_SCTP + if (ssl->options.dtlsSctp) +#endif +#if defined(WOLLSSL_SCTP) || defined(WOLFSSL_DTLS_MTU) + ssl->dtls_expected_rx = max(ssl->dtls_expected_rx, ssl->dtlsMtuSz); +#endif + } +#endif + + sz = wolfSSL_GetMaxRecordSize(ssl, sz); + + ret = ReceiveData(ssl, (byte*)data, sz, peek); + +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite) { + if (ssl->error != 0 && ssl->error != WANT_READ + #ifdef WOLFSSL_ASYNC_CRYPT + && ssl->error != WC_PENDING_E + #endif + ) { + int notifyErr; + + WOLFSSL_MSG("Notifying write side of fatal read error"); + notifyErr = NotifyWriteSide(ssl, ssl->error); + if (notifyErr < 0) { + ret = ssl->error = notifyErr; + } + } + } +#endif + + WOLFSSL_LEAVE("wolfSSL_read_internal()", ret); + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} + + +int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) +{ + WOLFSSL_ENTER("wolfSSL_peek()"); + + return wolfSSL_read_internal(ssl, data, sz, TRUE); +} + + +WOLFSSL_ABI +int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) +{ + WOLFSSL_ENTER("wolfSSL_read()"); + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_READ, SSL_SUCCESS); + ssl->cbmode = SSL_CB_READ; + } + #endif + return wolfSSL_read_internal(ssl, data, sz, FALSE); +} + + +#ifdef WOLFSSL_MULTICAST + +int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_mcast_read()"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ret = wolfSSL_read_internal(ssl, data, sz, FALSE); + if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) + *id = ssl->keys.curPeerId; + return ret; +} + +#endif /* WOLFSSL_MULTICAST */ + + +/* helpers to set the device id, WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->devId = devId; + + return WOLFSSL_SUCCESS; +} + +WOLFSSL_ABI +int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->devId = devId; + + return WOLFSSL_SUCCESS; +} + +/* helpers to get device id and heap */ +WOLFSSL_ABI +int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + int devId = INVALID_DEVID; + if (ctx != NULL) + devId = ctx->devId; + else if (ssl != NULL) + devId = ssl->devId; + return devId; +} +void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + void* heap = NULL; + if (ctx != NULL) + heap = ctx->heap; + else if (ssl != NULL) + heap = ssl->heap; + return heap; +} + + +#ifdef HAVE_SNI + +WOLFSSL_ABI +int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); +} + + +WOLFSSL_ABI +int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, + word16 size) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); +} + +#ifndef NO_WOLFSSL_SERVER + +void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) +{ + if (ssl && ssl->extensions) + TLSX_SNI_SetOptions(ssl->extensions, type, options); +} + + +void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) +{ + if (ctx && ctx->extensions) + TLSX_SNI_SetOptions(ctx->extensions, type, options); +} + + +byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) +{ + return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type); +} + + +word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) +{ + if (data) + *data = NULL; + + if (ssl && ssl->extensions) + return TLSX_SNI_GetRequest(ssl->extensions, type, data); + + return 0; +} + + +int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, + byte type, byte* sni, word32* inOutSz) +{ + if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0) + return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); + + return BAD_FUNC_ARG; +} + +#endif /* NO_WOLFSSL_SERVER */ + +#endif /* HAVE_SNI */ + + +#ifdef HAVE_TRUSTED_CA + +WOLFSSL_API int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, + const byte* certId, word32 certIdSz) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { + if (certId != NULL || certIdSz != 0) + return BAD_FUNC_ARG; + } + else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { + if (certId == NULL || certIdSz == 0) + return BAD_FUNC_ARG; + } + #ifndef NO_SHA + else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || + type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { + if (certId == NULL || certIdSz != WC_SHA_DIGEST_SIZE) + return BAD_FUNC_ARG; + } + #endif + else + return BAD_FUNC_ARG; + + return TLSX_UseTrustedCA(&ssl->extensions, + type, certId, certIdSz, ssl->heap); +} + +#endif /* HAVE_TRUSTED_CA */ + + +#ifdef HAVE_MAX_FRAGMENT +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST + /* The following is a non-standard way to reconfigure the max packet size + post-handshake for wolfSSL_write/woflSSL_read */ + if (ssl->options.handShakeState == HANDSHAKE_DONE) { + switch (mfl) { + case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; + case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; + case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; + case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; + case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; + case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; + default: ssl->max_fragment = MAX_RECORD_SIZE; break; + } + return WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ + + /* This call sets the max fragment TLS extension, which gets sent to server. + The server_hello response is what sets the `ssl->max_fragment` in + TLSX_MFL_Parse */ + return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); +} + + +int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_MAX_FRAGMENT */ + +#ifdef HAVE_TRUNCATED_HMAC +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); +} + + +int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_TRUNCATED_HMAC */ + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + +int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options) +{ + if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, + options, NULL, ssl->heap, ssl->devId); +} + + +int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type, + byte options) +{ + if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, + options, NULL, ctx->heap, ctx->devId); +} + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + +int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options) +{ + if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, + options, ssl->heap, ssl->devId); +} + + +int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type, + byte options) +{ + if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequestV2(&ctx->extensions, status_type, + options, ctx->heap, ctx->devId); +} + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +/* Elliptic Curves */ +#if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT) + +int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (name) { + case WOLFSSL_ECC_SECP160K1: + case WOLFSSL_ECC_SECP160R1: + case WOLFSSL_ECC_SECP160R2: + case WOLFSSL_ECC_SECP192K1: + case WOLFSSL_ECC_SECP192R1: + case WOLFSSL_ECC_SECP224K1: + case WOLFSSL_ECC_SECP224R1: + case WOLFSSL_ECC_SECP256K1: + case WOLFSSL_ECC_SECP256R1: + case WOLFSSL_ECC_SECP384R1: + case WOLFSSL_ECC_SECP521R1: + case WOLFSSL_ECC_BRAINPOOLP256R1: + case WOLFSSL_ECC_BRAINPOOLP384R1: + case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_X25519: + case WOLFSSL_ECC_X448: + + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: + break; + + default: + return BAD_FUNC_ARG; + } + + ssl->options.userCurves = 1; + + return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); +} + + +int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + switch (name) { + case WOLFSSL_ECC_SECP160K1: + case WOLFSSL_ECC_SECP160R1: + case WOLFSSL_ECC_SECP160R2: + case WOLFSSL_ECC_SECP192K1: + case WOLFSSL_ECC_SECP192R1: + case WOLFSSL_ECC_SECP224K1: + case WOLFSSL_ECC_SECP224R1: + case WOLFSSL_ECC_SECP256K1: + case WOLFSSL_ECC_SECP256R1: + case WOLFSSL_ECC_SECP384R1: + case WOLFSSL_ECC_SECP521R1: + case WOLFSSL_ECC_BRAINPOOLP256R1: + case WOLFSSL_ECC_BRAINPOOLP384R1: + case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_X25519: + case WOLFSSL_ECC_X448: + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: + break; + + default: + return BAD_FUNC_ARG; + } + + ctx->userCurves = 1; + + return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); +} + +#endif /* HAVE_SUPPORTED_CURVES && !NO_WOLFSSL_CLIENT */ + +/* QSH quantum safe handshake */ +#ifdef HAVE_QSH +/* returns 1 if QSH has been used 0 otherwise */ +int wolfSSL_isQSH(WOLFSSL* ssl) +{ + /* if no ssl struct than QSH was not used */ + if (ssl == NULL) + return 0; + + return ssl->isQSH; +} + + +int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, word16 name) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + break; + #endif + default: + return BAD_FUNC_ARG; + } + + ssl->user_set_QSHSchemes = 1; + + return TLSX_UseQSHScheme(&ssl->extensions, name, NULL, 0, ssl->heap); +} + +#ifndef NO_WOLFSSL_CLIENT + /* user control over sending client public key in hello + when flag = 1 will send keys if flag is 0 or function is not called + then will not send keys in the hello extension + return 0 on success + */ + int wolfSSL_UseClientQSHKeys(WOLFSSL* ssl, unsigned char flag) + { + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->sendQSHKeys = flag; + + return 0; + } +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_QSH */ + +/* Application-Layer Protocol Negotiation */ +#ifdef HAVE_ALPN + +WOLFSSL_ABI +int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, + word32 protocol_name_listSz, byte options) +{ + char *list, *ptr, *token[WOLFSSL_MAX_ALPN_NUMBER]={NULL}; + word16 len; + int idx = 0; + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_UseALPN"); + + if (ssl == NULL || protocol_name_list == NULL) + return BAD_FUNC_ARG; + + if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * + WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + + WOLFSSL_MAX_ALPN_NUMBER)) { + WOLFSSL_MSG("Invalid arguments, protocol name list too long"); + return BAD_FUNC_ARG; + } + + if (!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) && + !(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH)) { + WOLFSSL_MSG("Invalid arguments, options not supported"); + return BAD_FUNC_ARG; + } + + + list = (char *)XMALLOC(protocol_name_listSz+1, ssl->heap, + DYNAMIC_TYPE_ALPN); + if (list == NULL) { + WOLFSSL_MSG("Memory failure"); + return MEMORY_ERROR; + } + + XSTRNCPY(list, protocol_name_list, protocol_name_listSz); + list[protocol_name_listSz] = '\0'; + + /* read all protocol name from the list */ + token[idx] = XSTRTOK(list, ",", &ptr); + while (idx < WOLFSSL_MAX_ALPN_NUMBER && token[idx] != NULL) + token[++idx] = XSTRTOK(NULL, ",", &ptr); + + /* add protocol name list in the TLS extension in reverse order */ + while ((idx--) > 0) { + len = (word16)XSTRLEN(token[idx]); + + ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("TLSX_UseALPN failure"); + break; + } + } + + XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); + + return ret; +} + +int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) +{ + return TLSX_ALPN_GetRequest(ssl ? ssl->extensions : NULL, + (void **)protocol_name, size); +} + +int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) +{ + if (list == NULL || listSz == NULL) + return BAD_FUNC_ARG; + + if (ssl->alpn_client_list == NULL) + return BUFFER_ERROR; + + *listSz = (word16)XSTRLEN(ssl->alpn_client_list); + if (*listSz == 0) + return BUFFER_ERROR; + + *list = (char *)XMALLOC((*listSz)+1, ssl->heap, DYNAMIC_TYPE_TLSX); + if (*list == NULL) + return MEMORY_ERROR; + + XSTRNCPY(*list, ssl->alpn_client_list, (*listSz)+1); + (*list)[*listSz] = 0; + + return WOLFSSL_SUCCESS; +} + + +/* used to free memory allocated by wolfSSL_ALPN_GetPeerProtocol */ +int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; + + return WOLFSSL_SUCCESS; +} + +#endif /* HAVE_ALPN */ + +/* Secure Renegotiation */ +#ifdef HAVE_SECURE_RENEGOTIATION + +/* user is forcing ability to use secure renegotiation, we discourage it */ +int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) +{ + int ret = BAD_FUNC_ARG; + + if (ssl) + ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); + + if (ret == WOLFSSL_SUCCESS) { + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + + if (extension) + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; + } + + return ret; +} + +int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->useSecureReneg = 1; + return WOLFSSL_SUCCESS; +} + + +/* do a secure renegotiation handshake, user forced, we discourage */ +static int _Rehandshake(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (ssl->secure_renegotiation == NULL) { + WOLFSSL_MSG("Secure Renegotiation not forced on by user"); + return SECURE_RENEGOTIATION_E; + } + + if (ssl->secure_renegotiation->enabled == 0) { + WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); + return SECURE_RENEGOTIATION_E; + } + + /* If the client started the renegotiation, the server will already + * have processed the client's hello. */ + if (ssl->options.side != WOLFSSL_SERVER_END || + ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) { + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + WOLFSSL_MSG("Can't renegotiate until previous handshake complete"); + return SECURE_RENEGOTIATION_E; + } + +#ifndef NO_FORCE_SCR_SAME_SUITE + /* force same suite */ + if (ssl->suites) { + ssl->suites->suiteSz = SUITE_LEN; + ssl->suites->suites[0] = ssl->options.cipherSuite0; + ssl->suites->suites[1] = ssl->options.cipherSuite; + } +#endif + + /* reset handshake states */ + ssl->options.sendVerify = 0; + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN_RENEG; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = 0; /* TODO, move states in internal.h */ + + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + + ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; + +#if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SERVER_RENEGOTIATION_INFO) + if (ssl->options.side == WOLFSSL_SERVER_END) { + ret = SendHelloRequest(ssl); + if (ret != 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* NO_WOLFSSL_SERVER && HAVE_SERVER_RENEGOTIATION_INFO */ + + ret = InitHandshakeHashes(ssl); + if (ret != 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; + } + } + ret = wolfSSL_negotiate(ssl); + ssl->secure_rene_count++; + return ret; +} + + +/* do a secure renegotiation handshake, user forced, we discourage */ +int wolfSSL_Rehandshake(WOLFSSL* ssl) +{ + int ret = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_Rehandshake"); + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Reset option to send certificate verify. */ + ssl->options.sendVerify = 0; + } + else { + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; + #ifdef HAVE_SESSION_TICKET + /* Clearing the ticket. */ + ret = wolfSSL_UseSessionTicket(ssl); + #endif + } + + if (ret == WOLFSSL_SUCCESS) + ret = _Rehandshake(ssl); + + return ret; +} + + +#ifndef NO_WOLFSSL_CLIENT + +/* do a secure resumption handshake, user forced, we discourage */ +int wolfSSL_SecureResume(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_SecureResume"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->error = SIDE_ERROR; + return SSL_FATAL_ERROR; + } + + return _Rehandshake(ssl); +} + +#endif /* NO_WOLFSSL_CLIENT */ + +long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); + + if (!ssl || !ssl->secure_renegotiation) + return WOLFSSL_FAILURE; + return ssl->secure_renegotiation->enabled; +} + +#endif /* HAVE_SECURE_RENEGOTIATION */ + +/* Session Ticket */ +#if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SESSION_TICKET) +/* WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->ticketEncCb = cb; + + return WOLFSSL_SUCCESS; +} + +/* set hint interval, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->ticketHint = hint; + + return WOLFSSL_SUCCESS; +} + +/* set user context, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->ticketEncCtx = userCtx; + + return WOLFSSL_SUCCESS; +} + +#endif /* !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET) */ + +/* Session Ticket */ +#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET) +int wolfSSL_UseSessionTicket(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); +} + +int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); +} + +WOLFSSL_API int wolfSSL_get_SessionTicket(WOLFSSL* ssl, + byte* buf, word32* bufSz) +{ + if (ssl == NULL || buf == NULL || bufSz == NULL || *bufSz == 0) + return BAD_FUNC_ARG; + + if (ssl->session.ticketLen <= *bufSz) { + XMEMCPY(buf, ssl->session.ticket, ssl->session.ticketLen); + *bufSz = ssl->session.ticketLen; + } + else + *bufSz = 0; + + return WOLFSSL_SUCCESS; +} + +WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, + word32 bufSz) +{ + if (ssl == NULL || (buf == NULL && bufSz > 0)) + return BAD_FUNC_ARG; + + if (bufSz > 0) { + /* Ticket will fit into static ticket */ + if(bufSz <= SESSION_TICKET_LEN) { + if (ssl->session.isDynamic) { + XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + ssl->session.isDynamic = 0; + ssl->session.ticket = ssl->session.staticTicket; + } + } else { /* Ticket requires dynamic ticket storage */ + if (ssl->session.ticketLen < bufSz) { /* is dyn buffer big enough */ + if(ssl->session.isDynamic) + XFREE(ssl->session.ticket, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + ssl->session.ticket = (byte*)XMALLOC(bufSz, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + if(!ssl->session.ticket) { + ssl->session.ticket = ssl->session.staticTicket; + ssl->session.isDynamic = 0; + return MEMORY_ERROR; + } + ssl->session.isDynamic = 1; + } + } + XMEMCPY(ssl->session.ticket, buf, bufSz); + } + ssl->session.ticketLen = (word16)bufSz; + + return WOLFSSL_SUCCESS; +} + + +WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, + CallbackSessionTicket cb, void* ctx) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->session_ticket_cb = cb; + ssl->session_ticket_ctx = ctx; + + return WOLFSSL_SUCCESS; +} +#endif + + +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->haveEMS = 0; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.haveEMS = 0; + + return WOLFSSL_SUCCESS; +} + +#endif +#endif + + +#ifndef WOLFSSL_LEANPSK + +int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) +{ + int ret; + int oldFlags; + + WOLFSSL_ENTER("wolfSSL_send()"); + + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; + + oldFlags = ssl->wflags; + + ssl->wflags = flags; + ret = wolfSSL_write(ssl, data, sz); + ssl->wflags = oldFlags; + + WOLFSSL_LEAVE("wolfSSL_send()", ret); + + return ret; +} + + +int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) +{ + int ret; + int oldFlags; + + WOLFSSL_ENTER("wolfSSL_recv()"); + + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; + + oldFlags = ssl->rflags; + + ssl->rflags = flags; + ret = wolfSSL_read(ssl, data, sz); + ssl->rflags = oldFlags; + + WOLFSSL_LEAVE("wolfSSL_recv()", ret); + + return ret; +} +#endif + + +/* WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_shutdown(WOLFSSL* ssl) +{ + int ret = WOLFSSL_FATAL_ERROR; + WOLFSSL_ENTER("SSL_shutdown()"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (ssl->options.quietShutdown) { + WOLFSSL_MSG("quiet shutdown, no close notify sent"); + ret = WOLFSSL_SUCCESS; + } + else { + /* try to send close notify, not an error if can't */ + if (!ssl->options.isClosed && !ssl->options.connReset && + !ssl->options.sentNotify) { + ssl->error = SendAlert(ssl, alert_warning, close_notify); + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentNotify = 1; /* don't send close_notify twice */ + if (ssl->options.closeNotify) + ret = WOLFSSL_SUCCESS; + else { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + WOLFSSL_LEAVE("SSL_shutdown()", ret); + return ret; + } + } + +#ifdef WOLFSSL_SHUTDOWNONCE + if (ssl->options.isClosed || ssl->options.connReset) { + /* Shutdown has already occurred. + * Caller is free to ignore this error. */ + return SSL_SHUTDOWN_ALREADY_DONE_E; + } +#endif + + /* call wolfSSL_shutdown again for bidirectional shutdown */ + if (ssl->options.sentNotify && !ssl->options.closeNotify) { + ret = ProcessReply(ssl); + if (ret == ZERO_RETURN) { + /* simulate OpenSSL behavior */ + ssl->error = WOLFSSL_ERROR_SYSCALL; + ret = WOLFSSL_SUCCESS; + } else if (ssl->error == WOLFSSL_ERROR_NONE) { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + } else { + WOLFSSL_ERROR(ssl->error); + ret = WOLFSSL_FATAL_ERROR; + } + } + } + +#ifdef OPENSSL_EXTRA + /* reset WOLFSSL structure state for possible re-use */ + if (ret == WOLFSSL_SUCCESS) { + if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("could not clear WOLFSSL"); + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif + + WOLFSSL_LEAVE("SSL_shutdown()", ret); + + return ret; +} + + +/* get current error state value */ +int wolfSSL_state(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + return ssl->error; +} + + +WOLFSSL_ABI +int wolfSSL_get_error(WOLFSSL* ssl, int ret) +{ + WOLFSSL_ENTER("SSL_get_error"); + + if (ret > 0) + return WOLFSSL_ERROR_NONE; + if (ssl == NULL) + return BAD_FUNC_ARG; + + WOLFSSL_LEAVE("SSL_get_error", ssl->error); + + /* make sure converted types are handled in SetErrorString() too */ + if (ssl->error == WANT_READ) + return WOLFSSL_ERROR_WANT_READ; /* convert to OpenSSL type */ + else if (ssl->error == WANT_WRITE) + return WOLFSSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ + else if (ssl->error == ZERO_RETURN) + return WOLFSSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ + return ssl->error; +} + + +/* retrieve alert history, WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) +{ + if (ssl && h) { + *h = ssl->alert_history; + } + return WOLFSSL_SUCCESS; +} + +#ifdef OPENSSL_EXTRA +/* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ +int wolfSSL_want(WOLFSSL* ssl) +{ + int rw_state = SSL_NOTHING; + if (ssl) { + if (ssl->error == WANT_READ) + rw_state = SSL_READING; + else if (ssl->error == WANT_WRITE) + rw_state = SSL_WRITING; + } + return rw_state; +} +#endif + +/* return TRUE if current error is want read */ +int wolfSSL_want_read(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_want_read"); + if (ssl->error == WANT_READ) + return 1; + + return 0; +} + + +/* return TRUE if current error is want write */ +int wolfSSL_want_write(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_want_write"); + if (ssl->error == WANT_WRITE) + return 1; + + return 0; +} + + +char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) +{ + static wcchar msg = "Please supply a buffer for error string"; + + WOLFSSL_ENTER("ERR_error_string"); + if (data) { + SetErrorString((int)errNumber, data); + return data; + } + + return (char*)msg; +} + + +void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) +{ + WOLFSSL_ENTER("wolfSSL_ERR_error_string_n"); + if (len >= WOLFSSL_MAX_ERROR_SZ) + wolfSSL_ERR_error_string(e, buf); + else { + char tmp[WOLFSSL_MAX_ERROR_SZ]; + + WOLFSSL_MSG("Error buffer too short, truncating"); + if (len) { + wolfSSL_ERR_error_string(e, tmp); + XMEMCPY(buf, tmp, len-1); + buf[len-1] = '\0'; + } + } +} + + +/* don't free temporary arrays at end of handshake */ +void wolfSSL_KeepArrays(WOLFSSL* ssl) +{ + if (ssl) + ssl->options.saveArrays = 1; +} + + +/* user doesn't need temporary arrays anymore, Free */ +void wolfSSL_FreeArrays(WOLFSSL* ssl) +{ + if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { + ssl->options.saveArrays = 0; + FreeArrays(ssl, 1); + } +} + +/* Set option to indicate that the resources are not to be freed after + * handshake. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.keepResources = 1; + + return 0; +} + +/* Free the handshake resources after handshake. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_FreeHandshakeResources(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + FreeHandshakeResources(ssl); + + return 0; +} + +/* Use the client's order of preference when matching cipher suites. + * + * ssl The SSL/TLS context object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_CTX_UseClientSuites(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->useClientOrder = 1; + + return 0; +} + +/* Use the client's order of preference when matching cipher suites. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_UseClientSuites(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.useClientOrder = 1; + + return 0; +} + +const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) +{ +#ifndef WOLFSSL_AEAD_ONLY + if (ssl == NULL) + return NULL; + + if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || + (ssl->options.side == WOLFSSL_SERVER_END && verify) ) + return ssl->keys.client_write_MAC_secret; + else + return ssl->keys.server_write_MAC_secret; +#else + (void)ssl; + (void)verify; + + return NULL; +#endif +} + + +#ifdef ATOMIC_USER + +void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) +{ + if (ctx) + ctx->MacEncryptCb = cb; +} + + +void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->MacEncryptCtx = ctx; +} + + +void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->MacEncryptCtx; + + return NULL; +} + + +void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) +{ + if (ctx) + ctx->DecryptVerifyCb = cb; +} + + +void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->DecryptVerifyCtx = ctx; +} + + +void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->DecryptVerifyCtx; + + return NULL; +} + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +/** + * Set the callback, against the context, that encrypts then MACs. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) +{ + if (ctx) + ctx->EncryptMacCb = cb; +} + +/** + * Set the context to use with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EncryptMacCtx = ctx; +} + +/** + * Get the context being used with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EncryptMacCtx; + + return NULL; +} + + +/** + * Set the callback, against the context, that MAC verifies then decrypts. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) +{ + if (ctx) + ctx->VerifyDecryptCb = cb; +} + +/** + * Set the context to use with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->VerifyDecryptCtx = ctx; +} + +/** + * Get the context being used with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->VerifyDecryptCtx; + + return NULL; +} +#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ + + + +const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.client_write_key; + + return NULL; +} + + +const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.client_write_IV; + + return NULL; +} + + +const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.server_write_key; + + return NULL; +} + + +const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.server_write_IV; + + return NULL; +} + +int wolfSSL_GetKeySize(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.key_size; + + return BAD_FUNC_ARG; +} + + +int wolfSSL_GetIVSize(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.iv_size; + + return BAD_FUNC_ARG; +} + + +int wolfSSL_GetBulkCipher(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.bulk_cipher_algorithm; + + return BAD_FUNC_ARG; +} + + +int wolfSSL_GetCipherType(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + +#ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) + return WOLFSSL_BLOCK_TYPE; + if (ssl->specs.cipher_type == stream) + return WOLFSSL_STREAM_TYPE; +#endif + if (ssl->specs.cipher_type == aead) + return WOLFSSL_AEAD_TYPE; + + return -1; +} + + +int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return ssl->specs.block_size; +} + + +int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return ssl->specs.aead_mac_size; +} + + +int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (ssl->options.tls1_1) + return 1; + + return 0; +} + + +int wolfSSL_GetSide(WOLFSSL* ssl) +{ + if (ssl) + return ssl->options.side; + + return BAD_FUNC_ARG; +} + + +int wolfSSL_GetHmacSize(WOLFSSL* ssl) +{ + /* AEAD ciphers don't have HMAC keys */ + if (ssl) + return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0; + + return BAD_FUNC_ARG; +} + +#endif /* ATOMIC_USER */ + +#ifndef NO_CERTS + +WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) +{ + WOLFSSL_CERT_MANAGER* cm = NULL; + if (ctx) + cm = ctx->cm; + return cm; +} + +WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew_ex(void* heap) +{ + WOLFSSL_CERT_MANAGER* cm; + + WOLFSSL_ENTER("wolfSSL_CertManagerNew"); + + cm = (WOLFSSL_CERT_MANAGER*) XMALLOC(sizeof(WOLFSSL_CERT_MANAGER), heap, + DYNAMIC_TYPE_CERT_MANAGER); + if (cm) { + XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER)); + + if (wc_InitMutex(&cm->caLock) != 0) { + WOLFSSL_MSG("Bad mutex init"); + wolfSSL_CertManagerFree(cm); + return NULL; + } + + #ifdef WOLFSSL_TRUST_PEER_CERT + if (wc_InitMutex(&cm->tpLock) != 0) { + WOLFSSL_MSG("Bad mutex init"); + wolfSSL_CertManagerFree(cm); + return NULL; + } + #endif + + /* set default minimum key size allowed */ + #ifndef NO_RSA + cm->minRsaKeySz = MIN_RSAKEY_SZ; + #endif + #ifdef HAVE_ECC + cm->minEccKeySz = MIN_ECCKEY_SZ; + #endif + cm->heap = heap; + } + + return cm; +} + + +WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void) +{ + return wolfSSL_CertManagerNew_ex(NULL); +} + + +void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerFree"); + + if (cm) { + #ifdef HAVE_CRL + if (cm->crl) + FreeCRL(cm->crl, 1); + #endif + #ifdef HAVE_OCSP + if (cm->ocsp) + FreeOCSP(cm->ocsp, 1); + XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL); + #if !defined(NO_WOLFSSL_SERVER) && \ + (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + if (cm->ocsp_stapling) + FreeOCSP(cm->ocsp_stapling, 1); + #endif + #endif + FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); + wc_FreeMutex(&cm->caLock); + + #ifdef WOLFSSL_TRUST_PEER_CERT + FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap); + wc_FreeMutex(&cm->tpLock); + #endif + + XFREE(cm, cm->heap, DYNAMIC_TYPE_CERT_MANAGER); + } + +} + +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) +#if defined(WOLFSSL_SIGNER_DER_CERT) +/****************************************************************************** +* wolfSSL_CertManagerGetCerts - retrieve stack of X509 certificates in a +* certificate manager (CM). +* +* RETURNS: +* returns stack of X509 certs on success, otherwise returns a NULL. +*/ +WOLFSSL_STACK* wolfSSL_CertManagerGetCerts(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_STACK* sk = NULL; + Signer* signers = NULL; + word32 row = 0; + DecodedCert* dCert = NULL; + WOLFSSL_X509* x509 = NULL; + int found = 0; + + if (cm == NULL) + return NULL; + + sk = wolfSSL_sk_X509_new(); + + if (sk == NULL) { + return NULL; + } + + if (wc_LockMutex(&cm->caLock) != 0) { + goto error_init; + } + + for (row = 0; row < CA_TABLE_SIZE; row++) { + signers = cm->caTable[row]; + while (signers && signers->derCert && signers->derCert->buffer) { + + dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, + DYNAMIC_TYPE_DCERT); + if (dCert == NULL) { + goto error; + } + + XMEMSET(dCert, 0, sizeof(DecodedCert)); + + InitDecodedCert(dCert, signers->derCert->buffer, + signers->derCert->length, cm->heap); + + /* Parse Certificate */ + if (ParseCert(dCert, CERT_TYPE, NO_VERIFY, cm)) { + goto error; + } + + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), cm->heap, + DYNAMIC_TYPE_X509); + + if (x509 == NULL) { + goto error; + } + + InitX509(x509, 1, NULL); + + if (CopyDecodedToX509(x509, dCert) == 0) { + + if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) { + WOLFSSL_MSG("Unable to load x509 into stack"); + FreeX509(x509); + XFREE(x509, cm->heap, DYNAMIC_TYPE_X509); + goto error; + } + } + else { + goto error; + } + + found = 1; + + signers = signers->next; + + FreeDecodedCert(dCert); + XFREE(dCert, cm->heap, DYNAMIC_TYPE_DCERT); + dCert = NULL; + } + } + wc_UnLockMutex(&cm->caLock); + + if (!found) { + goto error_init; + } + + return sk; + +error: + wc_UnLockMutex(&cm->caLock); + +error_init: + + if (dCert) { + FreeDecodedCert(dCert); + XFREE(dCert, cm->heap, DYNAMIC_TYPE_DCERT); + } + + if (sk) + wolfSSL_sk_X509_free(sk); + + return NULL; +} +#endif /* WOLFSSL_SIGNER_DER_CERT */ + +/****************************************************************************** +* wolfSSL_X509_STORE_GetCerts - retrieve stack of X509 in a certificate store ctx +* +* This API can be used in SSL verify callback function to view cert chain +* See examples/client/client.c and myVerify() function in test.h +* +* RETURNS: +* returns stack of X509 certs on success, otherwise returns a NULL. +*/ +WOLFSSL_STACK* wolfSSL_X509_STORE_GetCerts(WOLFSSL_X509_STORE_CTX* s) +{ + int certIdx = 0; + WOLFSSL_BUFFER_INFO* cert = NULL; + DecodedCert* dCert = NULL; + WOLFSSL_X509* x509 = NULL; + WOLFSSL_STACK* sk = NULL; + int found = 0; + + if (s == NULL) { + return NULL; + } + + sk = wolfSSL_sk_X509_new(); + + if (sk == NULL) { + return NULL; + } + + for (certIdx = s->totalCerts - 1; certIdx >= 0; certIdx--) { + /* get certificate buffer */ + cert = &s->certs[certIdx]; + + dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + + if (dCert == NULL) { + goto error; + } + XMEMSET(dCert, 0, sizeof(DecodedCert)); + + InitDecodedCert(dCert, cert->buffer, cert->length, NULL); + + /* Parse Certificate */ + if (ParseCert(dCert, CERT_TYPE, NO_VERIFY, NULL)){ + goto error; + } + x509 = wolfSSL_X509_new(); + + if (x509 == NULL) { + goto error; + } + InitX509(x509, 1, NULL); + + if (CopyDecodedToX509(x509, dCert) == 0) { + + if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) { + WOLFSSL_MSG("Unable to load x509 into stack"); + wolfSSL_X509_free(x509); + goto error; + } + } + else { + goto error; + } + found = 1; + + FreeDecodedCert(dCert); + XFREE(dCert, NULL, DYNAMIC_TYPE_DCERT); + dCert = NULL; + } + + if (!found) { + wolfSSL_sk_X509_free(sk); + sk = NULL; + } + return sk; + +error: + if (dCert) { + FreeDecodedCert(dCert); + XFREE(dCert, NULL, DYNAMIC_TYPE_DCERT); + } + + if (sk) + wolfSSL_sk_X509_free(sk); + + return NULL; +} +#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM */ + +/* Unload the CA signer list */ +int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerUnloadCAs"); + + if (cm == NULL) + return BAD_FUNC_ARG; + + if (wc_LockMutex(&cm->caLock) != 0) + return BAD_MUTEX_E; + + FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); + + wc_UnLockMutex(&cm->caLock); + + + return WOLFSSL_SUCCESS; +} + + +#ifdef WOLFSSL_TRUST_PEER_CERT +int wolfSSL_CertManagerUnload_trust_peers(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerUnload_trust_peers"); + + if (cm == NULL) + return BAD_FUNC_ARG; + + if (wc_LockMutex(&cm->tpLock) != 0) + return BAD_MUTEX_E; + + FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap); + + wc_UnLockMutex(&cm->tpLock); + + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +#endif /* NO_CERTS */ + +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) + +void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) +{ + char data[WOLFSSL_MAX_ERROR_SZ + 1]; + + WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); + SetErrorString(err, data); + fprintf(fp, "%s", data); +} + +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) +void wolfSSL_ERR_dump_errors_fp(XFILE fp) +{ + wc_ERR_print_errors_fp(fp); +} + +void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, + void *u), void *u) +{ + wc_ERR_print_errors_cb(cb, u); +} +#endif +#endif + +WOLFSSL_ABI +int wolfSSL_pending(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_pending"); + return ssl->buffers.clearOutputBuffer.length; +} + + +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for context */ +int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->groupMessages = 1; + + return WOLFSSL_SUCCESS; +} +#endif + + +#ifndef NO_WOLFSSL_CLIENT +/* connect enough to get peer cert chain */ +int wolfSSL_connect_cert(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->options.certOnly = 1; + ret = wolfSSL_connect(ssl); + ssl->options.certOnly = 0; + + return ret; +} +#endif + + +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for ssl object */ +int wolfSSL_set_group_messages(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.groupMessages = 1; + + return WOLFSSL_SUCCESS; +} + + +/* make minVersion the internal equivalent SSL version */ +static int SetMinVersionHelper(byte* minVersion, int version) +{ +#ifdef NO_TLS + (void)minVersion; +#endif + + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + *minVersion = SSLv3_MINOR; + break; +#endif + +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + *minVersion = TLSv1_MINOR; + break; + #endif + + case WOLFSSL_TLSV1_1: + *minVersion = TLSv1_1_MINOR; + break; + #endif + #ifndef WOLFSSL_NO_TLS12 + case WOLFSSL_TLSV1_2: + *minVersion = TLSv1_2_MINOR; + break; + #endif +#endif + #ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + *minVersion = TLSv1_3_MINOR; + break; + #endif + + default: + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } + + return WOLFSSL_SUCCESS; +} + + +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); + + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } + + return SetMinVersionHelper(&ctx->minDowngrade, version); +} + + +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) +{ + WOLFSSL_ENTER("wolfSSL_SetMinVersion"); + + if (ssl == NULL) { + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } + + return SetMinVersionHelper(&ssl->options.minDowngrade, version); +} + + +/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ +int wolfSSL_GetVersion(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (ssl->version.major == SSLv3_MAJOR) { + switch (ssl->version.minor) { + case SSLv3_MINOR : + return WOLFSSL_SSLV3; + case TLSv1_MINOR : + return WOLFSSL_TLSV1; + case TLSv1_1_MINOR : + return WOLFSSL_TLSV1_1; + case TLSv1_2_MINOR : + return WOLFSSL_TLSV1_2; + case TLSv1_3_MINOR : + return WOLFSSL_TLSV1_3; + default: + break; + } + } + + return VERSION_ERROR; +} + +int wolfSSL_SetVersion(WOLFSSL* ssl, int version) +{ + word16 haveRSA = 1; + word16 havePSK = 0; + int keySz = 0; + + WOLFSSL_ENTER("wolfSSL_SetVersion"); + + if (ssl == NULL) { + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } + + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + ssl->version = MakeSSLv3(); + break; +#endif + +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + ssl->version = MakeTLSv1(); + break; + #endif + + case WOLFSSL_TLSV1_1: + ssl->version = MakeTLSv1_1(); + break; + #endif + #ifndef WOLFSSL_NO_TLS12 + case WOLFSSL_TLSV1_2: + ssl->version = MakeTLSv1_2(); + break; + #endif +#endif +#ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + ssl->version = MakeTLSv1_3(); + break; + +#endif + + default: + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + + return WOLFSSL_SUCCESS; +} +#endif /* !leanpsk */ + + +#if !defined(NO_CERTS) || !defined(NO_SESSION_CACHE) + +/* Make a work from the front of random hash */ +static WC_INLINE word32 MakeWordFromHash(const byte* hashID) +{ + return ((word32)hashID[0] << 24) | ((word32)hashID[1] << 16) | + (hashID[2] << 8) | hashID[3]; +} + +#endif /* !NO_CERTS || !NO_SESSION_CACHE */ + + +#ifndef NO_CERTS + +/* hash is the SHA digest of name, just use first 32 bits as hash */ +static WC_INLINE word32 HashSigner(const byte* hash) +{ + return MakeWordFromHash(hash) % CA_TABLE_SIZE; +} + + +/* does CA already exist on signer list */ +int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash) +{ + Signer* signers; + int ret = 0; + word32 row; + + if (cm == NULL || hash == NULL) { + return ret; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return ret; + } + signers = cm->caTable[row]; + while (signers) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = signers->subjectKeyIdHash; + #else + subjectHash = signers->subjectNameHash; + #endif + + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = 1; /* success */ + break; + } + signers = signers->next; + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} + + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* hash is the SHA digest of name, just use first 32 bits as hash */ +static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash) +{ + return MakeWordFromHash(hash) % TP_TABLE_SIZE; +} + +/* does trusted peer already exist on signer list */ +int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, byte* hash) +{ + TrustedPeerCert* tp; + int ret = 0; + word32 row = TrustedPeerHashSigner(hash); + + if (wc_LockMutex(&cm->tpLock) != 0) + return ret; + tp = cm->tpTable[row]; + while (tp) { + byte* subjectHash; + #ifndef NO_SKID + subjectHash = tp->subjectKeyIdHash; + #else + subjectHash = tp->subjectNameHash; + #endif + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = 1; + break; + } + tp = tp->next; + } + wc_UnLockMutex(&cm->tpLock); + + return ret; +} + + +/* return Trusted Peer if found, otherwise NULL + type is what to match on + */ +TrustedPeerCert* GetTrustedPeer(void* vp, byte* hash, int type) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + TrustedPeerCert* ret = NULL; + TrustedPeerCert* tp = NULL; + word32 row; + + if (cm == NULL || hash == NULL) + return NULL; + + row = TrustedPeerHashSigner(hash); + + if (wc_LockMutex(&cm->tpLock) != 0) + return ret; + + tp = cm->tpTable[row]; + while (tp) { + byte* subjectHash; + switch (type) { + #ifndef NO_SKID + case WC_MATCH_SKID: + subjectHash = tp->subjectKeyIdHash; + break; + #endif + case WC_MATCH_NAME: + subjectHash = tp->subjectNameHash; + break; + default: + WOLFSSL_MSG("Unknown search type"); + wc_UnLockMutex(&cm->tpLock); + return NULL; + } + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = tp; + break; + } + tp = tp->next; + } + wc_UnLockMutex(&cm->tpLock); + + return ret; +} + + +int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert) +{ + if (tp == NULL || cert == NULL) + return BAD_FUNC_ARG; + + /* subject key id or subject hash has been compared when searching + tpTable for the cert from function GetTrustedPeer */ + + /* compare signatures */ + if (tp->sigLen == cert->sigLength) { + if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) { + return WOLFSSL_FAILURE; + } + } + else { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + + +/* return CA if found, otherwise NULL */ +Signer* GetCA(void* vp, byte* hash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + word32 row = HashSigner(hash); + + if (cm == NULL) + return NULL; + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + signers = cm->caTable[row]; + while (signers) { + byte* subjectHash; + #ifndef NO_SKID + subjectHash = signers->subjectKeyIdHash; + #else + subjectHash = signers->subjectNameHash; + #endif + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + break; + } + signers = signers->next; + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} + + +#ifndef NO_SKID +/* return CA if found, otherwise NULL. Walk through hash table. */ +Signer* GetCAByName(void* vp, byte* hash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + word32 row; + + if (cm == NULL) + return NULL; + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + signers = cm->caTable[row]; + while (signers && ret == NULL) { + if (XMEMCMP(hash, signers->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + } + signers = signers->next; + } + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} +#endif + + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* add a trusted peer cert to linked list */ +int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) +{ + int ret, row; + TrustedPeerCert* peerCert; + DecodedCert* cert; + DerBuffer* der = *pDer; + byte* subjectHash = NULL; + + WOLFSSL_MSG("Adding a Trusted Peer Cert"); + + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; + + InitDecodedCert(cert, der->buffer, der->length, cm->heap); + if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) { + FreeDecodedCert(cert); + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + return ret; + } + WOLFSSL_MSG("\tParsed new trusted peer cert"); + + peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap, + DYNAMIC_TYPE_CERT); + if (peerCert == NULL) { + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + return MEMORY_E; + } + XMEMSET(peerCert, 0, sizeof(TrustedPeerCert)); + +#ifndef NO_SKID + if (cert->extAuthKeyIdSet) { + subjectHash = cert->extSubjKeyId; + } + else { + subjectHash = cert->subjectHash; + } +#else + subjectHash = cert->subjectHash; +#endif + + #ifndef IGNORE_NAME_CONSTRAINTS + if (peerCert->permittedNames) + FreeNameSubtrees(peerCert->permittedNames, cm->heap); + if (peerCert->excludedNames) + FreeNameSubtrees(peerCert->excludedNames, cm->heap); + #endif + + if (AlreadyTrustedPeer(cm, subjectHash)) { + WOLFSSL_MSG("\tAlready have this CA, not adding again"); + FreeTrustedPeer(peerCert, cm->heap); + (void)ret; + } + else { + /* add trusted peer signature */ + peerCert->sigLen = cert->sigLength; + peerCert->sig = XMALLOC(cert->sigLength, cm->heap, + DYNAMIC_TYPE_SIGNATURE); + if (peerCert->sig == NULL) { + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeTrustedPeer(peerCert, cm->heap); + return MEMORY_E; + } + XMEMCPY(peerCert->sig, cert->signature, cert->sigLength); + + /* add trusted peer name */ + peerCert->nameLen = cert->subjectCNLen; + peerCert->name = cert->subjectCN; + #ifndef IGNORE_NAME_CONSTRAINTS + peerCert->permittedNames = cert->permittedNames; + peerCert->excludedNames = cert->excludedNames; + #endif + + /* add SKID when available and hash of name */ + #ifndef NO_SKID + XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId, + SIGNER_DIGEST_SIZE); + #endif + XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, + SIGNER_DIGEST_SIZE); + peerCert->next = NULL; /* If Key Usage not set, all uses valid. */ + cert->subjectCN = 0; + #ifndef IGNORE_NAME_CONSTRAINTS + cert->permittedNames = NULL; + cert->excludedNames = NULL; + #endif + + #ifndef NO_SKID + if (cert->extAuthKeyIdSet) { + row = TrustedPeerHashSigner(peerCert->subjectKeyIdHash); + } + else { + row = TrustedPeerHashSigner(peerCert->subjectNameHash); + } + #else + row = TrustedPeerHashSigner(peerCert->subjectNameHash); + #endif + + if (wc_LockMutex(&cm->tpLock) == 0) { + peerCert->next = cm->tpTable[row]; + cm->tpTable[row] = peerCert; /* takes ownership */ + wc_UnLockMutex(&cm->tpLock); + } + else { + WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed"); + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeTrustedPeer(peerCert, cm->heap); + return BAD_MUTEX_E; + } + } + + WOLFSSL_MSG("\tFreeing parsed trusted peer cert"); + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + WOLFSSL_MSG("\tFreeing der trusted peer cert"); + FreeDer(&der); + WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert"); + WOLFSSL_LEAVE("AddTrustedPeer", ret); + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + + +/* owns der, internal now uses too */ +/* type flag ids from user or from chain received during verify + don't allow chain ones to be added w/o isCA extension */ +int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) +{ + int ret; + Signer* signer = NULL; + word32 row; + byte* subjectHash; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; +#else + DecodedCert cert[1]; +#endif + DerBuffer* der = *pDer; + + WOLFSSL_MSG("Adding a CA"); + + if (cm == NULL) { + FreeDer(pDer); + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) { + FreeDer(pDer); + return MEMORY_E; + } +#endif + + InitDecodedCert(cert, der->buffer, der->length, cm->heap); + ret = ParseCert(cert, CA_TYPE, verify, cm); + WOLFSSL_MSG("\tParsed new CA"); + +#ifndef NO_SKID + subjectHash = cert->extSubjKeyId; +#else + subjectHash = cert->subjectHash; +#endif + + /* check CA key size */ + if (verify) { + switch (cert->keyOID) { + #ifndef NO_RSA + case RSAk: + if (cm->minRsaKeySz < 0 || + cert->pubKeySize < (word16)cm->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("\tCA RSA key size error"); + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (cm->minEccKeySz < 0 || + cert->pubKeySize < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (cm->minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + if (cm->minEccKeySz < 0 || + ED448_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED448 */ + + default: + WOLFSSL_MSG("\tNo key size check done on CA"); + break; /* no size check if key type is not in switch */ + } + } + + if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA) { + WOLFSSL_MSG("\tCan't add as CA if not actually one"); + ret = NOT_CA_ERROR; + } +#ifndef ALLOW_INVALID_CERTSIGN + else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && + !cert->selfSigned && (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { + /* Intermediate CA certs are required to have the keyCertSign + * extension set. User loaded root certs are not. */ + WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); + ret = NOT_CA_ERROR; + } +#endif + else if (ret == 0 && AlreadySigner(cm, subjectHash)) { + WOLFSSL_MSG("\tAlready have this CA, not adding again"); + (void)ret; + } + else if (ret == 0) { + /* take over signer parts */ + signer = MakeSigner(cm->heap); + if (!signer) + ret = MEMORY_ERROR; + } + if (ret == 0 && signer != NULL) { + #ifdef WOLFSSL_SIGNER_DER_CERT + ret = AllocDer(&signer->derCert, der->length, der->type, NULL); + } + if (ret == 0 && signer != NULL) { + XMEMCPY(signer->derCert->buffer, der->buffer, der->length); + #endif + signer->keyOID = cert->keyOID; + if (cert->pubKeyStored) { + signer->publicKey = cert->publicKey; + signer->pubKeySize = cert->pubKeySize; + } + if (cert->subjectCNStored) { + signer->nameLen = cert->subjectCNLen; + signer->name = cert->subjectCN; + } + signer->pathLength = cert->pathLength; + signer->maxPathLen = cert->maxPathLen; + signer->pathLengthSet = cert->pathLengthSet; + signer->selfSigned = cert->selfSigned; + #ifndef IGNORE_NAME_CONSTRAINTS + signer->permittedNames = cert->permittedNames; + signer->excludedNames = cert->excludedNames; + #endif + #ifndef NO_SKID + XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId, + SIGNER_DIGEST_SIZE); + #endif + XMEMCPY(signer->subjectNameHash, cert->subjectHash, + SIGNER_DIGEST_SIZE); + #ifdef HAVE_OCSP + XMEMCPY(signer->subjectKeyHash, cert->subjectKeyHash, + KEYID_SIZE); + #endif + signer->keyUsage = cert->extKeyUsageSet ? cert->extKeyUsage + : 0xFFFF; + signer->next = NULL; /* If Key Usage not set, all uses valid. */ + cert->publicKey = 0; /* in case lock fails don't free here. */ + cert->subjectCN = 0; + #ifndef IGNORE_NAME_CONSTRAINTS + cert->permittedNames = NULL; + cert->excludedNames = NULL; + #endif + + #ifndef NO_SKID + row = HashSigner(signer->subjectKeyIdHash); + #else + row = HashSigner(signer->subjectNameHash); + #endif + + if (wc_LockMutex(&cm->caLock) == 0) { + signer->next = cm->caTable[row]; + cm->caTable[row] = signer; /* takes ownership */ + wc_UnLockMutex(&cm->caLock); + if (cm->caCacheCallback) + cm->caCacheCallback(der->buffer, (int)der->length, type); + } + else { + WOLFSSL_MSG("\tCA Mutex Lock failed"); + ret = BAD_MUTEX_E; + FreeSigner(signer, cm->heap); + } + } +#if defined(WOLFSSL_RENESAS_TSIP_TLS) + /* Verify CA by TSIP so that generated tsip key is going to be able to */ + /* be used for peer's cert verification */ + /* TSIP is only able to handle USER CA, and only one CA. */ + /* Therefore, it doesn't need to call TSIP again if there is already */ + /* verified CA. */ + if ( ret == 0 && signer != NULL ) { + signer->cm_idx = row; + if (type == WOLFSSL_USER_CA && tsip_rootCAverified() == 0 ) { + if ((ret = tsip_tls_RootCertVerify(cert->source, cert->maxIdx, + cert->sigCtx.pubkey_n_start, cert->sigCtx.pubkey_n_len - 1, + cert->sigCtx.pubkey_e_start, cert->sigCtx.pubkey_e_len - 1, + row/* cm index */)) + != 0) + WOLFSSL_MSG("tsip_tls_RootCertVerify() failed"); + else + WOLFSSL_MSG("tsip_tls_RootCertVerify() succeed"); + } + } +#endif + WOLFSSL_MSG("\tFreeing Parsed CA"); + FreeDecodedCert(cert); +#ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); +#endif + WOLFSSL_MSG("\tFreeing der CA"); + FreeDer(pDer); + WOLFSSL_MSG("\t\tOK Freeing der CA"); + + WOLFSSL_LEAVE("AddCA", ret); + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + +#endif /* !NO_CERTS */ + + +#ifndef NO_SESSION_CACHE + + /* basic config gives a cache with 33 sessions, adequate for clients and + embedded servers + + TITAN_SESSION_CACHE allows just over 2 million sessions, for servers + with titanic amounts of memory with long session ID timeouts and high + levels of traffic. + + HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load, + allows over 13,000 new sessions per minute or over 200 new sessions per + second + + BIG_SESSION_CACHE yields 20,027 sessions + + MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that + aren't under heavy load, basically allows 200 new sessions per minute + + SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients + or systems where the default of nearly 3kB is too much RAM, this define + uses less than 500 bytes RAM + + default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined) + */ + #if defined(TITAN_SESSION_CACHE) + #define SESSIONS_PER_ROW 31 + #define SESSION_ROWS 64937 + #elif defined(HUGE_SESSION_CACHE) + #define SESSIONS_PER_ROW 11 + #define SESSION_ROWS 5981 + #elif defined(BIG_SESSION_CACHE) + #define SESSIONS_PER_ROW 7 + #define SESSION_ROWS 2861 + #elif defined(MEDIUM_SESSION_CACHE) + #define SESSIONS_PER_ROW 5 + #define SESSION_ROWS 211 + #elif defined(SMALL_SESSION_CACHE) + #define SESSIONS_PER_ROW 2 + #define SESSION_ROWS 3 + #else + #define SESSIONS_PER_ROW 3 + #define SESSION_ROWS 11 + #endif + + typedef struct SessionRow { + int nextIdx; /* where to place next one */ + int totalCount; /* sessions ever on this row */ + WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW]; + } SessionRow; + + static WOLFSSL_GLOBAL SessionRow SessionCache[SESSION_ROWS]; + + #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) + static WOLFSSL_GLOBAL word32 PeakSessions; + #endif + + static WOLFSSL_GLOBAL wolfSSL_Mutex session_mutex; /* SessionCache mutex */ + + #ifndef NO_CLIENT_CACHE + + typedef struct ClientSession { + word16 serverRow; /* SessionCache Row id */ + word16 serverIdx; /* SessionCache Idx (column) */ + } ClientSession; + + typedef struct ClientRow { + int nextIdx; /* where to place next one */ + int totalCount; /* sessions ever on this row */ + ClientSession Clients[SESSIONS_PER_ROW]; + } ClientRow; + + static WOLFSSL_GLOBAL ClientRow ClientCache[SESSION_ROWS]; + /* Client Cache */ + /* uses session mutex */ + #endif /* NO_CLIENT_CACHE */ + +#endif /* NO_SESSION_CACHE */ + +WOLFSSL_ABI +int wolfSSL_Init(void) +{ + WOLFSSL_ENTER("wolfSSL_Init"); + + if (initRefCount == 0) { + /* Initialize crypto for use with TLS connection */ + if (wolfCrypt_Init() != 0) { + WOLFSSL_MSG("Bad wolfCrypt Init"); + return WC_INIT_E; + } + +#ifdef OPENSSL_EXTRA + if (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_RAND_Seed failed"); + return WC_INIT_E; + } +#endif + +#ifndef NO_SESSION_CACHE + if (wc_InitMutex(&session_mutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + return BAD_MUTEX_E; + } +#endif + if (wc_InitMutex(&count_mutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex count"); + return BAD_MUTEX_E; + } + } + + if (wc_LockMutex(&count_mutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex count"); + return BAD_MUTEX_E; + } + + initRefCount++; + wc_UnLockMutex(&count_mutex); + + return WOLFSSL_SUCCESS; +} + + + +#ifndef NO_CERTS + +/* process user cert chain to pass during the handshake */ +static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, int format, int type, WOLFSSL* ssl, + long* used, EncryptedInfo* info, int verify) +{ + int ret = 0; + void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); +#ifdef WOLFSSL_TLS13 + int cnt = 0; +#endif + + if ((type == CA_TYPE) && (ctx == NULL)) { + WOLFSSL_MSG("Need context for CA load"); + return BAD_FUNC_ARG; + } + + /* we may have a user cert chain, try to consume */ + if ((type == CERT_TYPE || type == CA_TYPE) && (info->consumed < sz)) { + #ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ + #else + byte staticBuffer[FILE_BUFFER_SIZE]; /* tmp chain buffer */ + #endif + byte* chainBuffer = staticBuffer; + int dynamicBuffer = 0; + word32 bufferSz; + long consumed = info->consumed; + word32 idx = 0; + int gotOne = 0; + + /* Calculate max possible size, including max headers */ + bufferSz = (word32)(sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH); + if (bufferSz > sizeof(staticBuffer)) { + WOLFSSL_MSG("Growing Tmp Chain Buffer"); + /* will shrink to actual size */ + chainBuffer = (byte*)XMALLOC(bufferSz, heap, DYNAMIC_TYPE_FILE); + if (chainBuffer == NULL) { + return MEMORY_E; + } + dynamicBuffer = 1; + } + + WOLFSSL_MSG("Processing Cert Chain"); + while (consumed < sz) { + DerBuffer* part = NULL; + word32 remain = (word32)(sz - consumed); + info->consumed = 0; + + if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buff + consumed, remain, type, &part, + heap, info, NULL); + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + int length = remain; + if (format == WOLFSSL_FILETYPE_ASN1) { + /* get length of der (read sequence) */ + word32 inOutIdx = 0; + if (GetSequence(buff + consumed, &inOutIdx, &length, + remain) < 0) { + ret = ASN_NO_PEM_HEADER; + } + length += inOutIdx; /* include leading sequence */ + } + info->consumed = length; + if (ret == 0) { + ret = AllocDer(&part, length, type, heap); + if (ret == 0) { + XMEMCPY(part->buffer, buff + consumed, length); + } + } + } + if (ret == 0) { + gotOne = 1; +#ifdef WOLFSSL_TLS13 + cnt++; +#endif + if ((idx + part->length + CERT_HEADER_SZ) > bufferSz) { + WOLFSSL_MSG(" Cert Chain bigger than buffer"); + ret = BUFFER_E; + } + else { + c32to24(part->length, &chainBuffer[idx]); + idx += CERT_HEADER_SZ; + XMEMCPY(&chainBuffer[idx], part->buffer, part->length); + idx += part->length; + consumed += info->consumed; + if (used) + *used += info->consumed; + } + + /* add CA's to certificate manager */ + if (type == CA_TYPE) { + /* verify CA unless user set to no verify */ + ret = AddCA(ctx->cm, &part, WOLFSSL_USER_CA, verify); + gotOne = 0; /* don't exit loop for CA type */ + } + } + + FreeDer(&part); + + if (ret == ASN_NO_PEM_HEADER && gotOne) { + WOLFSSL_MSG("We got one good cert, so stuff at end ok"); + break; + } + + if (ret < 0) { + WOLFSSL_MSG(" Error in Cert in Chain"); + if (dynamicBuffer) + XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); + return ret; + } + WOLFSSL_MSG(" Consumed another Cert in Chain"); + } + WOLFSSL_MSG("Finished Processing Cert Chain"); + + /* only retain actual size used */ + ret = 0; + if (idx > 0) { + if (ssl) { + if (ssl->buffers.weOwnCertChain) { + FreeDer(&ssl->buffers.certChain); + } + ret = AllocDer(&ssl->buffers.certChain, idx, type, heap); + if (ret == 0) { + XMEMCPY(ssl->buffers.certChain->buffer, chainBuffer, + idx); + ssl->buffers.weOwnCertChain = 1; + } + #ifdef WOLFSSL_TLS13 + ssl->buffers.certChainCnt = cnt; + #endif + } else if (ctx) { + FreeDer(&ctx->certChain); + ret = AllocDer(&ctx->certChain, idx, type, heap); + if (ret == 0) { + XMEMCPY(ctx->certChain->buffer, chainBuffer, idx); + } + #ifdef WOLFSSL_TLS13 + ctx->certChainCnt = cnt; + #endif + } + } + + if (dynamicBuffer) + XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); + } + + return ret; +} + +static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der, + int* keySz, word32* idx, int* resetSuites, int* keyFormat, void* heap, int devId) +{ + int ret = 0; + + (void)heap; + (void)devId; + + if (ctx == NULL && ssl == NULL) + ret = BAD_FUNC_ARG; + if (!der || !keySz || !idx || !resetSuites || !keyFormat) + ret = BAD_FUNC_ARG; + +#ifndef NO_RSA + if (ret == 0 && (*keyFormat == 0 || *keyFormat == RSAk)) { + /* make sure RSA key can be used */ + #ifdef WOLFSSL_SMALL_STACK + RsaKey* key; + #else + RsaKey key[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); + if (key == NULL) + return MEMORY_E; + #endif + + ret = wc_InitRsaKey_ex(key, heap, devId); + if (ret == 0) { + *idx = 0; + if (wc_RsaPrivateKeyDecode(der->buffer, idx, key, der->length) + != 0) { + #if !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ + !defined(HAVE_ED448) + WOLFSSL_MSG("RSA decode failed and ECC/ED25519/ED448 not " + "enabled to try"); + ret = WOLFSSL_BAD_FILE; + #endif + } + else { + /* check that the size of the RSA key is enough */ + int minRsaSz = ssl ? ssl->options.minRsaKeySz : + ctx->minRsaKeySz; + *keySz = wc_RsaEncryptSize((RsaKey*)key); + if (*keySz < minRsaSz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Private Key size too small"); + } + + if (ssl) { + ssl->buffers.keyType = rsa_sa_algo; + ssl->buffers.keySz = *keySz; + } + else { + ctx->privateKeyType = rsa_sa_algo; + ctx->privateKeySz = *keySz; + } + + *keyFormat = RSAk; + + if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.haveStaticECC = 0; + *resetSuites = 1; + } + } + + wc_FreeRsaKey(key); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(key, heap, DYNAMIC_TYPE_RSA); + #endif + } +#endif +#ifdef HAVE_ECC + if (ret == 0 && (*keyFormat == 0 || *keyFormat == ECDSAk)) { + /* make sure ECC key can be used */ + #ifdef WOLFSSL_SMALL_STACK + ecc_key* key; + #else + ecc_key key[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); + if (key == NULL) + return MEMORY_E; + #endif + + if (wc_ecc_init_ex(key, heap, devId) == 0) { + *idx = 0; + if (wc_EccPrivateKeyDecode(der->buffer, idx, key, + der->length) == 0) { + /* check for minimum ECC key size and then free */ + int minKeySz = ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz; + *keySz = wc_ecc_size(key); + if (*keySz < minKeySz) { + WOLFSSL_MSG("ECC private key too small"); + ret = ECC_KEY_SIZE_E; + } + + *keyFormat = ECDSAk; + if (ssl) { + ssl->options.haveStaticECC = 1; + ssl->buffers.keyType = ecc_dsa_sa_algo; + ssl->buffers.keySz = *keySz; + } + else { + ctx->haveStaticECC = 1; + ctx->privateKeyType = ecc_dsa_sa_algo; + ctx->privateKeySz = *keySz; + } + + if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { + *resetSuites = 1; + } + } + + wc_ecc_free(key); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(key, heap, DYNAMIC_TYPE_ECC); + #endif + } +#endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 + if (ret == 0 && (*keyFormat == 0 || *keyFormat == ED25519k)) { + /* make sure Ed25519 key can be used */ + #ifdef WOLFSSL_SMALL_STACK + ed25519_key* key; + #else + ed25519_key key[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, + DYNAMIC_TYPE_ED25519); + if (key == NULL) + return MEMORY_E; + #endif + + ret = wc_ed25519_init(key); + if (ret == 0) { + *idx = 0; + if (wc_Ed25519PrivateKeyDecode(der->buffer, idx, key, + der->length) == 0) { + /* check for minimum key size and then free */ + int minKeySz = ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz; + *keySz = ED25519_KEY_SIZE; + if (*keySz < minKeySz) { + WOLFSSL_MSG("ED25519 private key too small"); + ret = ECC_KEY_SIZE_E; + } + if (ret == 0) { + if (ssl) { + ssl->buffers.keyType = ed25519_sa_algo; + ssl->buffers.keySz = *keySz; + } + else if (ctx) { + ctx->privateKeyType = ed25519_sa_algo; + ctx->privateKeySz = *keySz; + } + + *keyFormat = ED25519k; + if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { + *resetSuites = 1; + } + } + } + + wc_ed25519_free(key); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(key, heap, DYNAMIC_TYPE_ED25519); + #endif + } +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + if (ret == 0 && (*keyFormat == 0 || *keyFormat == ED448k)) { + /* make sure Ed448 key can be used */ + #ifdef WOLFSSL_SMALL_STACK + ed448_key* key = NULL; + #else + ed448_key key[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); + if (key == NULL) + return MEMORY_E; + #endif + + ret = wc_ed448_init(key); + if (ret == 0) { + *idx = 0; + if (wc_Ed448PrivateKeyDecode(der->buffer, idx, key, + der->length) != 0) { + ret = WOLFSSL_BAD_FILE; + } + + if (ret == 0) { + /* check for minimum key size and then free */ + int minKeySz = ssl ? ssl->options.minEccKeySz : + ctx->minEccKeySz; + *keySz = ED448_KEY_SIZE; + if (*keySz < minKeySz) { + WOLFSSL_MSG("ED448 private key too small"); + ret = ECC_KEY_SIZE_E; + } + } + if (ret == 0) { + if (ssl) { + ssl->buffers.keyType = ed448_sa_algo; + ssl->buffers.keySz = *keySz; + } + else if (ctx) { + ctx->privateKeyType = ed448_sa_algo; + ctx->privateKeySz = *keySz; + } + + *keyFormat = ED448k; + if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { + *resetSuites = 1; + } + } + + wc_ed448_free(key); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(key, heap, DYNAMIC_TYPE_ED448); + #endif + } +#endif /* HAVE_ED448 */ + return ret; +} + +/* process the buffer buff, length sz, into ctx of format and type + used tracks bytes consumed, userChain specifies a user cert chain + to pass during the handshake */ +int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, int format, int type, WOLFSSL* ssl, + long* used, int userChain, int verify) +{ + DerBuffer* der = NULL; /* holds DER or RAW (for NTRU) */ + int ret = 0; + int done = 0; + int keyFormat = 0; + int resetSuites = 0; + void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); + int devId = wolfSSL_CTX_GetDevId(ctx, ssl); + word32 idx = 0; + int keySz = 0; +#if (defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)) || \ + defined(HAVE_PKCS8) + word32 algId = 0; +#endif +#ifdef WOLFSSL_SMALL_STACK + EncryptedInfo* info = NULL; +#else + EncryptedInfo info[1]; +#endif + + (void)devId; + (void)idx; + (void)keySz; + + if (used) + *used = sz; /* used bytes default to sz, PEM chain may shorten*/ + + /* check args */ + if (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM + && format != WOLFSSL_FILETYPE_RAW) + return WOLFSSL_BAD_FILETYPE; + + if (ctx == NULL && ssl == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap, + DYNAMIC_TYPE_ENCRYPTEDINFO); + if (info == NULL) + return MEMORY_E; +#endif + + XMEMSET(info, 0, sizeof(EncryptedInfo)); +#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) + if (ctx) { + info->passwd_cb = ctx->passwd_cb; + info->passwd_userdata = ctx->passwd_userdata; + } +#endif + + if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buff, sz, type, &der, heap, info, &keyFormat); + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + /* ASN1 (DER) or RAW (NTRU) */ + int length = (int)sz; + if (format == WOLFSSL_FILETYPE_ASN1) { + /* get length of der (read sequence or octet string) */ + word32 inOutIdx = 0; + if (GetSequence(buff, &inOutIdx, &length, (word32)sz) >= 0) { + length += inOutIdx; /* include leading sequence */ + } + /* get length using octect string (allowed for private key types) */ + else if (type == PRIVATEKEY_TYPE && + GetOctetString(buff, &inOutIdx, &length, (word32)sz) >= 0) { + length += inOutIdx; /* include leading oct string */ + } + else { + ret = ASN_PARSE_E; + } + } + + info->consumed = length; + + if (ret == 0) { + ret = AllocDer(&der, (word32)length, type, heap); + if (ret == 0) { + XMEMCPY(der->buffer, buff, length); + } + + #ifdef HAVE_PKCS8 + /* if private key try and remove PKCS8 header */ + if (type == PRIVATEKEY_TYPE) { + if ((ret = ToTraditional_ex(der->buffer, der->length, &algId)) > 0) { + /* Found PKCS8 header */ + /* ToTraditional_ex moves buff and returns adjusted length */ + der->length = ret; + } + ret = 0; /* failures should be ignored */ + } + #endif + } + } + + if (used) { + *used = info->consumed; + } + + /* process user chain */ + if (ret >= 0) { + /* Chain should have server cert first, then intermediates, then root. + * First certificate in chain is processed below after ProcessUserChain + * and is loaded into ssl->buffers.certificate. + * Remainder are processed using ProcessUserChain and are loaded into + * ssl->buffers.certChain. */ + if (userChain) { + ret = ProcessUserChain(ctx, buff, sz, format, type, ssl, used, info, + verify); + } + } + + /* info is only used for private key with DER or PEM, so free now */ + if (ret < 0 || type != PRIVATEKEY_TYPE || format == WOLFSSL_FILETYPE_RAW) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); + #endif + } + + /* check for error */ + if (ret < 0) { + FreeDer(&der); + done = 1; + } + + if (done == 1) { + /* No operation, just skip the next section */ + } + /* Handle DER owner */ + else if (type == CA_TYPE) { + if (ctx == NULL) { + WOLFSSL_MSG("Need context for CA load"); + FreeDer(&der); + return BAD_FUNC_ARG; + } + /* verify CA unless user set to no verify */ + ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify); + done = 1; + } +#ifdef WOLFSSL_TRUST_PEER_CERT + else if (type == TRUSTED_PEER_TYPE) { + if (ctx == NULL) { + WOLFSSL_MSG("Need context for trusted peer cert load"); + FreeDer(&der); + return BAD_FUNC_ARG; + } + /* add trusted peer cert */ + ret = AddTrustedPeer(ctx->cm, &der, !ctx->verifyNone); + done = 1; + } +#endif /* WOLFSSL_TRUST_PEER_CERT */ + else if (type == CERT_TYPE) { + if (ssl) { + /* Make sure previous is free'd */ + if (ssl->buffers.weOwnCert) { + FreeDer(&ssl->buffers.certificate); + #ifdef KEEP_OUR_CERT + FreeX509(ssl->ourCert); + if (ssl->ourCert) { + XFREE(ssl->ourCert, ssl->heap, DYNAMIC_TYPE_X509); + ssl->ourCert = NULL; + } + #endif + } + ssl->buffers.certificate = der; + #ifdef KEEP_OUR_CERT + ssl->keepCert = 1; /* hold cert for ssl lifetime */ + #endif + ssl->buffers.weOwnCert = 1; + } + else if (ctx) { + FreeDer(&ctx->certificate); /* Make sure previous is free'd */ + #ifdef KEEP_OUR_CERT + if (ctx->ourCert) { + if (ctx->ownOurCert) { + FreeX509(ctx->ourCert); + XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509); + } + ctx->ourCert = NULL; + } + #endif + ctx->certificate = der; + } + } + else if (type == PRIVATEKEY_TYPE) { + if (ssl) { + /* Make sure previous is free'd */ + if (ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + } + ssl->buffers.key = der; + ssl->buffers.weOwnKey = 1; + } + else if (ctx) { + FreeDer(&ctx->privateKey); + ctx->privateKey = der; + } + } + else { + FreeDer(&der); + return WOLFSSL_BAD_CERTTYPE; + } + + if (done == 1) { + /* No operation, just skip the next section */ + } + else if (type == PRIVATEKEY_TYPE && format != WOLFSSL_FILETYPE_RAW) { + #if defined(WOLFSSL_ENCRYPTED_KEYS) || defined(HAVE_PKCS8) + keyFormat = algId; + #endif + + ret = ProcessBufferTryDecode(ctx, ssl, der, &keySz, &idx, &resetSuites, + &keyFormat, heap, devId); + + #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) + /* for WOLFSSL_FILETYPE_PEM, PemToDer manages the decryption */ + /* If private key type PKCS8 header wasn't already removed (algoId == 0) */ + if ((ret != 0 || keyFormat == 0) + && format != WOLFSSL_FILETYPE_PEM && info->passwd_cb && algId == 0) + { + int passwordSz = NAME_SZ; + #ifndef WOLFSSL_SMALL_STACK + char password[NAME_SZ]; + #else + char* password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING); + if (password == NULL) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); + #endif + FreeDer(&der); + return MEMORY_E; + } + #endif + /* get password */ + ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ, + info->passwd_userdata); + if (ret >= 0) { + passwordSz = ret; + + /* PKCS8 decrypt */ + ret = ToTraditionalEnc(der->buffer, der->length, + password, passwordSz, &algId); + if (ret >= 0) { + der->length = ret; + } + /* ignore failures and try parsing as unencrypted */ + + ForceZero(password, passwordSz); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(password, heap, DYNAMIC_TYPE_STRING); + #endif + ret = ProcessBufferTryDecode(ctx, ssl, der, &keySz, &idx, + &resetSuites, &keyFormat, heap, devId); + } + #endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */ + + #ifdef WOLFSSL_SMALL_STACK + XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); + #endif + + if (ret != 0) + return ret; + if (keyFormat == 0) + return WOLFSSL_BAD_FILE; + + (void)devId; + } + else if (type == CERT_TYPE) { + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + #ifdef HAVE_PK_CALLBACKS + int keyType = 0; + #endif + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; + #endif + + WOLFSSL_MSG("Checking cert signature type"); + InitDecodedCert(cert, der->buffer, der->length, heap); + + if (DecodeToKey(cert, 0) < 0) { + WOLFSSL_MSG("Decode to key failed"); + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, heap, DYNAMIC_TYPE_DCERT); + #endif + return WOLFSSL_BAD_FILE; + } + + if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { + resetSuites = 1; + } + if (ssl && ssl->ctx->haveECDSAsig) { + WOLFSSL_MSG("SSL layer setting cert, CTX had ECDSA, turning off"); + ssl->options.haveECDSAsig = 0; /* may turn back on next */ + } + + switch (cert->signatureOID) { + case CTC_SHAwECDSA: + case CTC_SHA256wECDSA: + case CTC_SHA384wECDSA: + case CTC_SHA512wECDSA: + WOLFSSL_MSG("ECDSA cert signature"); + if (ssl) + ssl->options.haveECDSAsig = 1; + else if (ctx) + ctx->haveECDSAsig = 1; + break; + case CTC_ED25519: + WOLFSSL_MSG("ED25519 cert signature"); + if (ssl) + ssl->options.haveECDSAsig = 1; + else if (ctx) + ctx->haveECDSAsig = 1; + break; + case CTC_ED448: + WOLFSSL_MSG("ED448 cert signature"); + if (ssl) + ssl->options.haveECDSAsig = 1; + else if (ctx) + ctx->haveECDSAsig = 1; + break; + default: + WOLFSSL_MSG("Not ECDSA cert signature"); + break; + } + + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + if (ssl) { + ssl->pkCurveOID = cert->pkCurveOID; + #ifndef WC_STRICT_SIG + if (cert->keyOID == ECDSAk) { + ssl->options.haveECC = 1; + } + #ifdef HAVE_ED25519 + else if (cert->keyOID == ED25519k) { + ssl->options.haveECC = 1; + } + #endif + #ifdef HAVE_ED448 + else if (cert->keyOID == ED448k) { + ssl->options.haveECC = 1; + } + #endif + #else + ssl->options.haveECC = ssl->options.haveECDSAsig; + #endif + } + else if (ctx) { + ctx->pkCurveOID = cert->pkCurveOID; + #ifndef WC_STRICT_SIG + if (cert->keyOID == ECDSAk) { + ctx->haveECC = 1; + } + #ifdef HAVE_ED25519 + else if (cert->keyOID == ED25519k) { + ctx->haveECC = 1; + } + #endif + #ifdef HAVE_ED448 + else if (cert->keyOID == ED448k) { + ctx->haveECC = 1; + } + #endif + #else + ctx->haveECC = ctx->haveECDSAsig; + #endif + } + #endif + + /* check key size of cert unless specified not to */ + switch (cert->keyOID) { + #ifndef NO_RSA + case RSAk: + #ifdef HAVE_PK_CALLBACKS + keyType = rsa_sa_algo; + #endif + #ifdef HAVE_PKCS11 + if (ctx) { + ctx->privateKeyType = rsa_sa_algo; + } + else { + ssl->buffers.keyType = rsa_sa_algo; + } + #endif + /* Determine RSA key size by parsing public key */ + idx = 0; + ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx, + cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL); + if (ret < 0) + break; + + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minRsaKeySz < 0 || + keySz < (int)ssl->options.minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Certificate RSA key size too small"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minRsaKeySz < 0 || + keySz < (int)ctx->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Certificate RSA key size too small"); + } + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + #ifdef HAVE_PK_CALLBACKS + keyType = ecc_dsa_sa_algo; + #endif + #ifdef HAVE_PKCS11 + if (ctx) { + ctx->privateKeyType = ecc_dsa_sa_algo; + } + else { + ssl->buffers.keyType = ecc_dsa_sa_algo; + } + #endif + /* Determine ECC key size based on curve */ + keySz = wc_ecc_get_curve_size_from_id( + wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); + + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + #ifdef HAVE_PK_CALLBACKS + keyType = ed25519_sa_algo; + #endif + #ifdef HAVE_PKCS11 + if (ctx) { + ctx->privateKeyType = ed25519_sa_algo; + } + else { + ssl->buffers.keyType = ed25519_sa_algo; + } + #endif + /* ED25519 is fixed key size */ + keySz = ED25519_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Ed key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + #ifdef HAVE_PK_CALLBACKS + keyType = ed448_sa_algo; + #endif + #ifdef HAVE_PKCS11 + if (ctx) { + ctx->privateKeyType = ed448_sa_algo; + } + else { + ssl->buffers.keyType = ed448_sa_algo; + } + #endif + /* ED448 is fixed key size */ + keySz = ED448_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Ed key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ED448 */ + + default: + WOLFSSL_MSG("No key size check done on certificate"); + break; /* do no check if not a case for the key */ + } + + #ifdef HAVE_PK_CALLBACKS + if (ssl && ssl->buffers.keyType == 0) { + ssl->buffers.keyType = keyType; + ssl->buffers.keySz = keySz; + } + else if (ctx && ctx->privateKeyType == 0) { + ctx->privateKeyType = keyType; + ctx->privateKeySz = keySz; + } + #endif + + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, heap, DYNAMIC_TYPE_DCERT); + #endif + + if (ret != 0) { + done = 1; + } + } + + if (done == 1) { + #ifndef NO_WOLFSSL_CM_VERIFY + if ((type == CA_TYPE) || (type == CERT_TYPE)) { + /* Call to over-ride status */ + if ((ctx != NULL) && (ctx->cm != NULL) && + (ctx->cm->verifyCallback != NULL)) { + ret = CM_VerifyBuffer_ex(ctx->cm, buff, + sz, format, (ret == WOLFSSL_SUCCESS ? 0 : ret)); + } + } + #endif /* NO_WOLFSSL_CM_VERIFY */ + + return ret; + } + + + if (ssl && resetSuites) { + word16 havePSK = 0; + word16 haveRSA = 0; + + #ifndef NO_PSK + if (ssl->options.havePSK) { + havePSK = 1; + } + #endif + #ifndef NO_RSA + haveRSA = 1; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + + /* let's reset suites */ + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, + havePSK, ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + + return WOLFSSL_SUCCESS; +} + + +/* CA PEM file for verification, may have multiple/chain certs to process */ +static int ProcessChainBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, int format, int type, WOLFSSL* ssl, int verify) +{ + long used = 0; + int ret = 0; + int gotOne = 0; + + WOLFSSL_MSG("Processing CA PEM file"); + while (used < sz) { + long consumed = 0; + + ret = ProcessBuffer(ctx, buff + used, sz - used, format, type, ssl, + &consumed, 0, verify); + + if (ret < 0) { +#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL) + DerBuffer* der = NULL; + EncryptedInfo info; + + WOLFSSL_MSG("Trying a CRL"); + if (PemToDer(buff + used, sz - used, CRL_TYPE, &der, NULL, &info, + NULL) == 0) { + WOLFSSL_MSG(" Processed a CRL"); + wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, + der->length, WOLFSSL_FILETYPE_ASN1); + FreeDer(&der); + used += info.consumed; + continue; + } +#endif + + if (consumed > 0) { /* Made progress in file */ + WOLFSSL_ERROR(ret); + WOLFSSL_MSG("CA Parse failed, with progress in file."); + WOLFSSL_MSG("Search for other certs in file"); + } + else { + WOLFSSL_MSG("CA Parse failed, no progress in file."); + WOLFSSL_MSG("Do not continue search for other certs in file"); + break; + } + } + else { + WOLFSSL_MSG(" Processed a CA"); + gotOne = 1; + } + used += consumed; + } + + if (gotOne) { + WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK"); + return WOLFSSL_SUCCESS; + } + return ret; +} + + +static WC_INLINE WOLFSSL_METHOD* cm_pick_method(void) +{ + #ifndef NO_WOLFSSL_CLIENT + #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) + return wolfSSLv3_client_method(); + #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) + return wolfTLSv1_client_method(); + #elif !defined(NO_OLD_TLS) + return wolfTLSv1_1_client_method(); + #elif !defined(WOLFSSL_NO_TLS12) + return wolfTLSv1_2_client_method(); + #elif defined(WOLFSSL_TLS13) + return wolfTLSv1_3_client_method(); + #else + return NULL; + #endif + #elif !defined(NO_WOLFSSL_SERVER) + #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) + return wolfSSLv3_server_method(); + #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) + return wolfTLSv1_server_method(); + #elif !defined(NO_OLD_TLS) + return wolfTLSv1_1_server_method(); + #elif !defined(WOLFSSL_NO_TLS12) + return wolfTLSv1_2_server_method(); + #elif defined(WOLFSSL_TLS13) + return wolfTLSv1_3_server_method(); + #else + return NULL; + #endif + #else + return NULL; + #endif +} + + +/* like load verify locations, 1 for success, < 0 for error */ +int wolfSSL_CertManagerLoadCABuffer(WOLFSSL_CERT_MANAGER* cm, + const unsigned char* in, long sz, int format) +{ + int ret = WOLFSSL_FATAL_ERROR; + WOLFSSL_CTX* tmp; + + WOLFSSL_ENTER("wolfSSL_CertManagerLoadCABuffer"); + + if (cm == NULL) { + WOLFSSL_MSG("No CertManager error"); + return ret; + } + tmp = wolfSSL_CTX_new(cm_pick_method()); + + if (tmp == NULL) { + WOLFSSL_MSG("CTX new failed"); + return ret; + } + + /* for tmp use */ + wolfSSL_CertManagerFree(tmp->cm); + tmp->cm = cm; + + ret = wolfSSL_CTX_load_verify_buffer(tmp, in, sz, format); + + /* don't loose our good one */ + tmp->cm = NULL; + wolfSSL_CTX_free(tmp); + + return ret; +} + +#ifdef HAVE_CRL + +int wolfSSL_CertManagerLoadCRLBuffer(WOLFSSL_CERT_MANAGER* cm, + const unsigned char* buff, long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLBuffer"); + if (cm == NULL) + return BAD_FUNC_ARG; + + if (cm->crl == NULL) { + if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Enable CRL failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + return BufferLoadCRL(cm->crl, buff, sz, type, VERIFY); +} + +int wolfSSL_CertManagerFreeCRL(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerFreeCRL"); + if (cm == NULL) + return BAD_FUNC_ARG; + if (cm->crl != NULL){ + FreeCRL(cm->crl, 1); + cm->crl = NULL; + } + return WOLFSSL_SUCCESS; +} + +int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRLBuffer"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, buff, sz, type); +} + + +int wolfSSL_LoadCRLBuffer(WOLFSSL* ssl, const unsigned char* buff, + long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRLBuffer"); + + if (ssl == NULL || ssl->ctx == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_CertManagerLoadCRLBuffer(ssl->ctx->cm, buff, sz, type); +} + + +#endif /* HAVE_CRL */ + +/* turn on CRL if off and compiled in, set options */ +int wolfSSL_CertManagerEnableCRL(WOLFSSL_CERT_MANAGER* cm, int options) +{ + int ret = WOLFSSL_SUCCESS; + + (void)options; + + WOLFSSL_ENTER("wolfSSL_CertManagerEnableCRL"); + if (cm == NULL) + return BAD_FUNC_ARG; + + #ifdef HAVE_CRL + if (cm->crl == NULL) { + cm->crl = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), cm->heap, + DYNAMIC_TYPE_CRL); + if (cm->crl == NULL) + return MEMORY_E; + + if (InitCRL(cm->crl, cm) != 0) { + WOLFSSL_MSG("Init CRL failed"); + FreeCRL(cm->crl, 1); + cm->crl = NULL; + return WOLFSSL_FAILURE; + } + + #ifdef HAVE_CRL_IO + cm->crl->crlIOCb = EmbedCrlLookup; + #endif + } + + cm->crlEnabled = 1; + if (options & WOLFSSL_CRL_CHECKALL) + cm->crlCheckAll = 1; + #else + ret = NOT_COMPILED_IN; + #endif + + return ret; +} + + +int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerDisableCRL"); + if (cm == NULL) + return BAD_FUNC_ARG; + + cm->crlEnabled = 0; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_CM_VERIFY +void wolfSSL_CertManagerSetVerify(WOLFSSL_CERT_MANAGER* cm, VerifyCallback vc) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerSetVerify"); + if (cm == NULL) + return; + + cm->verifyCallback = vc; +} +#endif /* NO_WOLFSSL_CM_VERIFY */ + +/* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */ +int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const byte* buff, + long sz, int format, int err_val) +{ + int ret = 0; + DerBuffer* der = NULL; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; +#else + DecodedCert cert[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_CertManagerVerifyBuffer"); + +#ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; +#endif + + if (format == WOLFSSL_FILETYPE_PEM) { +#ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, NULL, NULL); + if (ret != 0) { + FreeDer(&der); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + #endif + return ret; + } + InitDecodedCert(cert, der->buffer, der->length, cm->heap); +#else + ret = NOT_COMPILED_IN; +#endif + } + else { + InitDecodedCert(cert, (byte*)buff, (word32)sz, cm->heap); + } + + if (ret == 0) + ret = ParseCertRelative(cert, CERT_TYPE, 1, cm); + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + /* ret needs to be self-singer error for Qt compat */ + if (ret == ASN_NO_SIGNER_E && cert->selfSigned) + ret = ASN_SELF_SIGNED_E; +#endif + +#ifdef HAVE_CRL + if (ret == 0 && cm->crlEnabled) + ret = CheckCertCRL(cm->crl, cert); +#endif + +#ifndef NO_WOLFSSL_CM_VERIFY + /* if verify callback has been set */ + if (cm->verifyCallback) { + buffer certBuf; + #ifdef WOLFSSL_SMALL_STACK + ProcPeerCertArgs* args; + args = (ProcPeerCertArgs*)XMALLOC( + sizeof(ProcPeerCertArgs), cm->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (args == NULL) { + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + return MEMORY_E; + } + #else + ProcPeerCertArgs args[1]; + #endif + + certBuf.buffer = (byte*)buff; + certBuf.length = (unsigned int)sz; + XMEMSET(args, 0, sizeof(ProcPeerCertArgs)); + + args->totalCerts = 1; + args->certs = &certBuf; + args->dCert = cert; + args->dCertInit = 1; + + if (err_val != 0) { + ret = err_val; + } + ret = DoVerifyCallback(cm, NULL, ret, args); + #ifdef WOLFSSL_SMALL_STACK + XFREE(args, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + } +#else + (void)err_val; +#endif + + FreeDecodedCert(cert); + FreeDer(&der); +#ifdef WOLFSSL_SMALL_STACK + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); +#endif + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + +/* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */ +int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm, const byte* buff, + long sz, int format) +{ + return CM_VerifyBuffer_ex(cm, buff, sz, format, 0); +} +/* turn on OCSP if off and compiled in, set options */ +int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options) +{ + int ret = WOLFSSL_SUCCESS; + + (void)options; + + WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSP"); + if (cm == NULL) + return BAD_FUNC_ARG; + + #ifdef HAVE_OCSP + if (cm->ocsp == NULL) { + cm->ocsp = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), cm->heap, + DYNAMIC_TYPE_OCSP); + if (cm->ocsp == NULL) + return MEMORY_E; + + if (InitOCSP(cm->ocsp, cm) != 0) { + WOLFSSL_MSG("Init OCSP failed"); + FreeOCSP(cm->ocsp, 1); + cm->ocsp = NULL; + return WOLFSSL_FAILURE; + } + } + cm->ocspEnabled = 1; + if (options & WOLFSSL_OCSP_URL_OVERRIDE) + cm->ocspUseOverrideURL = 1; + if (options & WOLFSSL_OCSP_NO_NONCE) + cm->ocspSendNonce = 0; + else + cm->ocspSendNonce = 1; + if (options & WOLFSSL_OCSP_CHECKALL) + cm->ocspCheckAll = 1; + #ifndef WOLFSSL_USER_IO + cm->ocspIOCb = EmbedOcspLookup; + cm->ocspRespFreeCb = EmbedOcspRespFree; + cm->ocspIOCtx = cm->heap; + #endif /* WOLFSSL_USER_IO */ + #else + ret = NOT_COMPILED_IN; + #endif + + return ret; +} + + +int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSP"); + if (cm == NULL) + return BAD_FUNC_ARG; + + cm->ocspEnabled = 0; + + return WOLFSSL_SUCCESS; +} + +/* turn on OCSP Stapling if off and compiled in, set options */ +int wolfSSL_CertManagerEnableOCSPStapling(WOLFSSL_CERT_MANAGER* cm) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPStapling"); + + if (cm == NULL) + return BAD_FUNC_ARG; + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + #ifndef NO_WOLFSSL_SERVER + if (cm->ocsp_stapling == NULL) { + cm->ocsp_stapling = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), + cm->heap, DYNAMIC_TYPE_OCSP); + if (cm->ocsp_stapling == NULL) + return MEMORY_E; + + if (InitOCSP(cm->ocsp_stapling, cm) != 0) { + WOLFSSL_MSG("Init OCSP failed"); + FreeOCSP(cm->ocsp_stapling, 1); + cm->ocsp_stapling = NULL; + return WOLFSSL_FAILURE; + } + } + + #ifndef WOLFSSL_USER_IO + cm->ocspIOCb = EmbedOcspLookup; + cm->ocspRespFreeCb = EmbedOcspRespFree; + cm->ocspIOCtx = cm->heap; + #endif /* WOLFSSL_USER_IO */ + #endif /* NO_WOLFSSL_SERVER */ + cm->ocspStaplingEnabled = 1; +#else + ret = NOT_COMPILED_IN; +#endif + + return ret; +} + +int wolfSSL_CertManagerDisableOCSPStapling(WOLFSSL_CERT_MANAGER* cm) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPStapling"); + + if (cm == NULL) + return BAD_FUNC_ARG; + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + cm->ocspStaplingEnabled = 0; +#else + ret = NOT_COMPILED_IN; +#endif + return ret; +} + +#ifdef HAVE_OCSP +/* check CRL if enabled, WOLFSSL_SUCCESS */ +int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; +#else + DecodedCert cert[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSP"); + + if (cm == NULL) + return BAD_FUNC_ARG; + + if (cm->ocspEnabled == 0) + return WOLFSSL_SUCCESS; + +#ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; +#endif + + InitDecodedCert(cert, der, sz, NULL); + + if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_OCSP, cm)) != 0) { + WOLFSSL_MSG("ParseCert failed"); + } + else if ((ret = CheckCertOCSP(cm->ocsp, cert, NULL)) != 0) { + WOLFSSL_MSG("CheckCertOCSP failed"); + } + + FreeDecodedCert(cert); +#ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); +#endif + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + +WOLFSSL_API int wolfSSL_CertManagerCheckOCSPResponse(WOLFSSL_CERT_MANAGER *cm, + byte *response, int responseSz, buffer *responseBuffer, + CertStatus *status, OcspEntry *entry, OcspRequest *ocspRequest) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSP_Staple"); + if (cm == NULL || response == NULL) + return BAD_FUNC_ARG; + if (cm->ocspEnabled == 0) + return WOLFSSL_SUCCESS; + + ret = CheckOcspResponse(cm->ocsp, response, responseSz, responseBuffer, status, + entry, ocspRequest); + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + +int wolfSSL_CertManagerSetOCSPOverrideURL(WOLFSSL_CERT_MANAGER* cm, + const char* url) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSPOverrideURL"); + if (cm == NULL) + return BAD_FUNC_ARG; + + XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL); + if (url != NULL) { + int urlSz = (int)XSTRLEN(url) + 1; + cm->ocspOverrideURL = (char*)XMALLOC(urlSz, cm->heap, DYNAMIC_TYPE_URL); + if (cm->ocspOverrideURL != NULL) { + XMEMCPY(cm->ocspOverrideURL, url, urlSz); + } + else + return MEMORY_E; + } + else + cm->ocspOverrideURL = NULL; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm, + CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSP_Cb"); + if (cm == NULL) + return BAD_FUNC_ARG; + + cm->ocspIOCb = ioCb; + cm->ocspRespFreeCb = respFreeCb; + cm->ocspIOCtx = ioCbCtx; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options) +{ + WOLFSSL_ENTER("wolfSSL_EnableOCSP"); + if (ssl) + return wolfSSL_CertManagerEnableOCSP(ssl->ctx->cm, options); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_DisableOCSP(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableOCSP"); + if (ssl) + return wolfSSL_CertManagerDisableOCSP(ssl->ctx->cm); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_EnableOCSPStapling(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_EnableOCSPStapling"); + if (ssl) + return wolfSSL_CertManagerEnableOCSPStapling(ssl->ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_DisableOCSPStapling(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableOCSPStapling"); + if (ssl) + return wolfSSL_CertManagerDisableOCSPStapling(ssl->ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); + if (ssl) + return wolfSSL_CertManagerSetOCSPOverrideURL(ssl->ctx->cm, url); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, + CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb"); + if (ssl) { + ssl->ocspIOCtx = ioCbCtx; /* use SSL specific ioCbCtx */ + return wolfSSL_CertManagerSetOCSP_Cb(ssl->ctx->cm, + ioCb, respFreeCb, NULL); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); + if (ctx) + return wolfSSL_CertManagerEnableOCSP(ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP"); + if (ctx) + return wolfSSL_CertManagerDisableOCSP(ctx->cm); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); + if (ctx) + return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb, + CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb"); + if (ctx) + return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, + respFreeCb, ioCbCtx); + else + return BAD_FUNC_ARG; +} + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling"); + if (ctx) + return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_DisableOCSPStapling(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPStapling"); + if (ctx) + return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm); + else + return BAD_FUNC_ARG; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +#endif /* HAVE_OCSP */ + +/* macro to get verify settings for AddCA */ +#define GET_VERIFY_SETTING_CTX(ctx) \ + (ctx && ctx->verifyNone ? NO_VERIFY : VERIFY) +#define GET_VERIFY_SETTING_SSL(ssl) \ + (ssl && ssl->options.verifyNone ? NO_VERIFY : VERIFY) + +#ifndef NO_FILESYSTEM + +/* process a file with name fname into ctx of format and type + userChain specifies a user certificate chain to pass during handshake */ +int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type, + WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl, int verify) +{ +#ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ +#else + byte staticBuffer[FILE_BUFFER_SIZE]; +#endif + byte* myBuffer = staticBuffer; + int dynamic = 0; + int ret; + long sz = 0; + XFILE file; + void* heapHint = wolfSSL_CTX_GetHeap(ctx, ssl); + const char* header = NULL; + const char* footer = NULL; + + (void)crl; + (void)heapHint; + + if (fname == NULL) return WOLFSSL_BAD_FILE; + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) return WOLFSSL_BAD_FILE; + if (XFSEEK(file, 0, XSEEK_END) != 0) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { + WOLFSSL_MSG("ProcessFile file size error"); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + + if (sz > (long)sizeof(staticBuffer)) { + WOLFSSL_MSG("Getting dynamic buffer"); + myBuffer = (byte*)XMALLOC(sz, heapHint, DYNAMIC_TYPE_FILE); + if (myBuffer == NULL) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + dynamic = 1; + } + + if ( (ret = (int)XFREAD(myBuffer, 1, sz, file)) != sz) + ret = WOLFSSL_BAD_FILE; + else { + /* Try to detect type by parsing cert header and footer */ + if (type == DETECT_CERT_TYPE) { + if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { + type = CA_TYPE; + } +#ifdef HAVE_CRL + else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { + type = CRL_TYPE; + } +#endif + else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { + type = CERT_TYPE; + } + else { + WOLFSSL_MSG("Failed to detect certificate type"); + if (dynamic) + XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE); + XFCLOSE(file); + return WOLFSSL_BAD_CERTTYPE; + } + } + if ((type == CA_TYPE || type == TRUSTED_PEER_TYPE) + && format == WOLFSSL_FILETYPE_PEM) { + ret = ProcessChainBuffer(ctx, myBuffer, sz, format, type, ssl, + verify); + } +#ifdef HAVE_CRL + else if (type == CRL_TYPE) + ret = BufferLoadCRL(crl, myBuffer, sz, format, verify); +#endif + else + ret = ProcessBuffer(ctx, myBuffer, sz, format, type, ssl, NULL, + userChain, verify); + } + + XFCLOSE(file); + if (dynamic) + XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE); + + return ret; +} + +/* loads file then loads each file in path, no c_rehash */ +int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file, + const char* path, word32 flags) +{ + int ret = WOLFSSL_SUCCESS; +#ifndef NO_WOLFSSL_DIR + int fileRet; + int successCount = 0; + int failCount = 0; +#endif + int verify; + + WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex"); + + if (ctx == NULL || (file == NULL && path == NULL)) { + return WOLFSSL_FAILURE; + } + + verify = GET_VERIFY_SETTING_CTX(ctx); + if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) + verify = VERIFY_SKIP_DATE; + + if (file) { + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, + NULL, verify); +#ifndef NO_WOLFSSL_DIR + if (ret == WOLFSSL_SUCCESS) + successCount++; +#endif + } + + if (ret == WOLFSSL_SUCCESS && path) { +#ifndef NO_WOLFSSL_DIR + char* name = NULL; + #ifdef WOLFSSL_SMALL_STACK + ReadDirCtx* readCtx; + readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap, + DYNAMIC_TYPE_DIRCTX); + if (readCtx == NULL) + return MEMORY_E; + #else + ReadDirCtx readCtx[1]; + #endif + + /* try to load each regular file in path */ + fileRet = wc_ReadDirFirst(readCtx, path, &name); + while (fileRet == 0 && name) { + WOLFSSL_MSG(name); /* log file name */ + ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, + NULL, 0, NULL, verify); + if (ret != WOLFSSL_SUCCESS) { + /* handle flags for ignoring errors, skipping expired certs or + by PEM certificate header error */ + if ( (flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) || + ((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) && + (ret == ASN_NO_PEM_HEADER))) { + /* Do not fail here if a certificate fails to load, + continue to next file */ + ret = WOLFSSL_SUCCESS; + } + else { + WOLFSSL_ERROR(ret); + WOLFSSL_MSG("Load CA file failed, continuing"); + failCount++; + } + } + else { + successCount++; + } + fileRet = wc_ReadDirNext(readCtx, path, &name); + } + wc_ReadDirClose(readCtx); + + /* pass directory read failure to response code */ + if (fileRet != WC_READDIR_NOFILE) { + ret = fileRet; + } + /* report failure if no files were loaded or there were failures */ + else if (successCount == 0 || failCount > 0) { + /* use existing error code if exists */ + if (ret == WOLFSSL_SUCCESS) + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_SUCCESS; + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX); + #endif +#else + ret = NOT_COMPILED_IN; + (void)flags; +#endif + } + + return ret; +} + +WOLFSSL_ABI +int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, + const char* path) +{ + return wolfSSL_CTX_load_verify_locations_ex(ctx, file, path, + WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); +} + + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* Used to specify a peer cert to match when connecting + ctx : the ctx structure to load in peer cert + file: the string name of cert file + type: type of format such as PEM/DER + */ +int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int type) +{ + WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert"); + + if (ctx == NULL || file == NULL) { + return WOLFSSL_FAILURE; + } + + return ProcessFile(ctx, file, type, TRUSTED_PEER_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)); +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + + +/* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */ +int wolfSSL_CertManagerVerify(WOLFSSL_CERT_MANAGER* cm, const char* fname, + int format) +{ + int ret = WOLFSSL_FATAL_ERROR; +#ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ +#else + byte staticBuffer[FILE_BUFFER_SIZE]; +#endif + byte* myBuffer = staticBuffer; + int dynamic = 0; + long sz = 0; + XFILE file = XFOPEN(fname, "rb"); + + WOLFSSL_ENTER("wolfSSL_CertManagerVerify"); + + if (file == XBADFILE) return WOLFSSL_BAD_FILE; + if(XFSEEK(file, 0, XSEEK_END) != 0) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { + WOLFSSL_MSG("CertManagerVerify file size error"); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + + if (sz > (long)sizeof(staticBuffer)) { + WOLFSSL_MSG("Getting dynamic buffer"); + myBuffer = (byte*) XMALLOC(sz, cm->heap, DYNAMIC_TYPE_FILE); + if (myBuffer == NULL) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + dynamic = 1; + } + + if ( (ret = (int)XFREAD(myBuffer, 1, sz, file)) != sz) + ret = WOLFSSL_BAD_FILE; + else + ret = wolfSSL_CertManagerVerifyBuffer(cm, myBuffer, sz, format); + + XFCLOSE(file); + if (dynamic) + XFREE(myBuffer, cm->heap, DYNAMIC_TYPE_FILE); + + return ret; +} + + +/* like load verify locations, 1 for success, < 0 for error */ +int wolfSSL_CertManagerLoadCA(WOLFSSL_CERT_MANAGER* cm, const char* file, + const char* path) +{ + int ret = WOLFSSL_FATAL_ERROR; + WOLFSSL_CTX* tmp; + + WOLFSSL_ENTER("wolfSSL_CertManagerLoadCA"); + + if (cm == NULL) { + WOLFSSL_MSG("No CertManager error"); + return ret; + } + tmp = wolfSSL_CTX_new(cm_pick_method()); + + if (tmp == NULL) { + WOLFSSL_MSG("CTX new failed"); + return ret; + } + + /* for tmp use */ + wolfSSL_CertManagerFree(tmp->cm); + tmp->cm = cm; + + ret = wolfSSL_CTX_load_verify_locations(tmp, file, path); + + /* don't lose our good one */ + tmp->cm = NULL; + wolfSSL_CTX_free(tmp); + + return ret; +} + +#ifndef NO_CHECK_PRIVATE_KEY +/* Check private against public in certificate for match + * + * ctx WOLFSSL_CTX structure to check private key in + * + * Returns SSL_SUCCESS on good private key and SSL_FAILURE if miss matched. */ +int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) +{ +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* der = NULL; +#else + DecodedCert der[1]; +#endif + word32 size; + byte* buff; + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_check_private_key"); + + if (ctx == NULL) { + return WOLFSSL_FAILURE; + } + +#ifndef NO_CERTS +#ifdef WOLFSSL_SMALL_STACK + der = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + if (der == NULL) + return MEMORY_E; +#endif + + size = ctx->certificate->length; + buff = ctx->certificate->buffer; + InitDecodedCert(der, buff, size, ctx->heap); + if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL) != 0) { + FreeDecodedCert(der); + #ifdef WOLFSSL_SMALL_STACK + XFREE(der, NULL, DYNAMIC_TYPE_DCERT); + #endif + return WOLFSSL_FAILURE; + } + + size = ctx->privateKey->length; + buff = ctx->privateKey->buffer; + ret = wc_CheckPrivateKey(buff, size, der); + FreeDecodedCert(der); +#ifdef WOLFSSL_SMALL_STACK + XFREE(der, NULL, DYNAMIC_TYPE_DCERT); +#endif + + if (ret == 1) { + return WOLFSSL_SUCCESS; + } + else { + return WOLFSSL_FAILURE; + } +#else + WOLFSSL_MSG("NO_CERTS is defined, can not check private key"); + return WOLFSSL_FAILURE; +#endif +} +#endif /* !NO_CHECK_PRIVATE_KEY */ + + +#ifdef HAVE_CRL + +/* check CRL if enabled, WOLFSSL_SUCCESS */ +int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz) +{ + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; +#else + DecodedCert cert[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL"); + + if (cm == NULL) + return BAD_FUNC_ARG; + + if (cm->crlEnabled == 0) + return WOLFSSL_SUCCESS; + +#ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; +#endif + + InitDecodedCert(cert, der, sz, NULL); + + if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_CRL, cm)) != 0) { + WOLFSSL_MSG("ParseCert failed"); + } + else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) { + WOLFSSL_MSG("CheckCertCRL failed"); + } + + FreeDecodedCert(cert); +#ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); +#endif + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + + +int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb"); + if (cm == NULL) + return BAD_FUNC_ARG; + + cm->cbMissingCRL = cb; + + return WOLFSSL_SUCCESS; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb) +{ + if (cm == NULL) + return BAD_FUNC_ARG; + + cm->crl->crlIOCb = cb; + + return WOLFSSL_SUCCESS; +} +#endif + +int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path, + int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL"); + if (cm == NULL) + return BAD_FUNC_ARG; + + if (cm->crl == NULL) { + if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Enable CRL failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + return LoadCRL(cm->crl, path, type, monitor); +} + +int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) +{ + WOLFSSL_ENTER("wolfSSL_EnableCRL"); + if (ssl) + return wolfSSL_CertManagerEnableCRL(ssl->ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_DisableCRL(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableCRL"); + if (ssl) + return wolfSSL_CertManagerDisableCRL(ssl->ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRL"); + if (ssl) + return wolfSSL_CertManagerLoadCRL(ssl->ctx->cm, path, type, monitor); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) + return wolfSSL_CertManagerSetCRL_Cb(ssl->ctx->cm, cb); + else + return BAD_FUNC_ARG; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) + return wolfSSL_CertManagerSetCRL_IOCb(ssl->ctx->cm, cb); + else + return BAD_FUNC_ARG; +} +#endif + +int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL"); + if (ctx) + return wolfSSL_CertManagerEnableCRL(ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL"); + if (ctx) + return wolfSSL_CertManagerDisableCRL(ctx->cm); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, + int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); + if (ctx) + return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb); + else + return BAD_FUNC_ARG; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb); + else + return BAD_FUNC_ARG; +} +#endif + + +#endif /* HAVE_CRL */ + + +#ifdef WOLFSSL_DER_LOAD + +/* Add format parameter to allow DER load of CA files */ +int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations"); + if (ctx == NULL || file == NULL) + return WOLFSSL_FAILURE; + + if (ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + +#endif /* WOLFSSL_DER_LOAD */ + + + +WOLFSSL_ABI +int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file"); + + if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +WOLFSSL_ABI +int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file, + int format) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file"); + + if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL, + GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +/* Sets the max chain depth when verifying a certificate chain. Default depth + * is set to MAX_CHAIN_DEPTH. + * + * ctx WOLFSSL_CTX structure to set depth in + * depth max depth + */ +void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) { + WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); + + if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) { + WOLFSSL_MSG("Bad depth argument, too large or less than 0"); + return; + } + + ctx->verifyDepth = (byte)depth; +} + + +/* get cert chaining depth using ssl struct */ +long wolfSSL_get_verify_depth(WOLFSSL* ssl) +{ + if(ssl == NULL) { + return BAD_FUNC_ARG; + } +#ifndef OPENSSL_EXTRA + return MAX_CHAIN_DEPTH; +#else + return ssl->options.verifyDepth; +#endif +} + + +/* get cert chaining depth using ctx struct */ +long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } +#ifndef OPENSSL_EXTRA + return MAX_CHAIN_DEPTH; +#else + return ctx->verifyDepth; +#endif +} + + +WOLFSSL_ABI +int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file) +{ + /* process up to MAX_CHAIN_DEPTH plus subject cert */ + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file"); + + if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL, + GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx, + const char* file, int format) +{ + /* process up to MAX_CHAIN_DEPTH plus subject cert */ + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format"); + + if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL, + GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +#ifndef NO_DH + +/* server Diffie-Hellman parameters */ +static int wolfSSL_SetTmpDH_file_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const char* fname, int format) +{ +#ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ +#else + byte staticBuffer[FILE_BUFFER_SIZE]; +#endif + byte* myBuffer = staticBuffer; + int dynamic = 0; + int ret; + long sz = 0; + XFILE file; + + if (ctx == NULL || fname == NULL) + return BAD_FUNC_ARG; + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) return WOLFSSL_BAD_FILE; + if(XFSEEK(file, 0, XSEEK_END) != 0) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { + WOLFSSL_MSG("SetTmpDH file size error"); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + + if (sz > (long)sizeof(staticBuffer)) { + WOLFSSL_MSG("Getting dynamic buffer"); + myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); + if (myBuffer == NULL) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + dynamic = 1; + } + + if ( (ret = (int)XFREAD(myBuffer, 1, sz, file)) != sz) + ret = WOLFSSL_BAD_FILE; + else { + if (ssl) + ret = wolfSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format); + else + ret = wolfSSL_CTX_SetTmpDH_buffer(ctx, myBuffer, sz, format); + } + + XFCLOSE(file); + if (dynamic) + XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); + + return ret; +} + +/* server Diffie-Hellman parameters */ +int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format); +} + + +/* server Diffie-Hellman parameters */ +int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format) +{ + return wolfSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format); +} + +#endif /* NO_DH */ + +#endif /* NO_FILESYSTEM */ + +#ifdef OPENSSL_EXTRA +/* put SSL type in extra for now, not very common */ + +/* Converts a DER format key read from "bio" to a PKCS8 structure. + * + * bio input bio to read DER from + * pkey If not NULL then this pointer will be overwritten with a new PKCS8 + * structure. + * + * returns a WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success and NULL in fail + * case. + */ +WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio, + WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey) +{ + WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; +#ifdef WOLFSSL_PEM_TO_DER + unsigned char* mem = NULL; + int memSz; + int keySz; + word32 algId; + + WOLFSSL_MSG("wolfSSL_d2i_PKCS8_PKEY_bio()"); + + if (bio == NULL) { + return NULL; + } + + if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { + return NULL; + } + + if ((keySz = wc_KeyPemToDer(mem, memSz, mem, memSz, NULL)) < 0) { + WOLFSSL_MSG("Not PEM format"); + keySz = memSz; + if ((keySz = ToTraditional_ex((byte*)mem, (word32)keySz, &algId)) < 0) { + return NULL; + } + } + + pkcs8 = wolfSSL_EVP_PKEY_new(); + if (pkcs8 == NULL) { + return NULL; + } + + pkcs8->pkey.ptr = (char*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + if (pkcs8->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkcs8); + return NULL; + } + XMEMCPY(pkcs8->pkey.ptr, mem, keySz); + pkcs8->pkey_sz = keySz; + + if (pkey != NULL) { + *pkey = pkcs8; + } +#else + (void)bio; + (void)pkey; +#endif /* WOLFSSL_PEM_TO_DER */ + + return pkcs8; +} + + +/* expecting DER format public key + * + * bio input bio to read DER from + * out If not NULL then this pointer will be overwritten with a new + * WOLFSSL_EVP_PKEY pointer + * + * returns a WOLFSSL_EVP_PKEY pointer on success and NULL in fail case. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** out) +{ + unsigned char* mem; + long memSz; + WOLFSSL_EVP_PKEY* pkey = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio()"); + + if (bio == NULL) { + return NULL; + } + (void)out; + + memSz = wolfSSL_BIO_pending(bio); + if (memSz <= 0) { + return NULL; + } + + mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + return NULL; + } + + if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { + pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz); + if (out != NULL && pkey != NULL) { + *out = pkey; + } + } + + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return pkey; +} + + + +/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure. + * + * out pointer to new WOLFSSL_EVP_PKEY structure. Can be NULL + * in DER buffer to convert + * inSz size of in buffer + * + * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL + * on fail + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, + const unsigned char** in, long inSz) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* mem; + long memSz = inSz; + + WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY"); + + if (in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + mem = *in; + + #if !defined(NO_RSA) + { + RsaKey rsa; + word32 keyIdx = 0; + + /* test if RSA key */ + if (wc_InitRsaKey(&rsa, NULL) == 0 && + wc_RsaPublicKeyDecode(mem, &keyIdx, &rsa, (word32)memSz) == 0) { + wc_FreeRsaKey(&rsa); + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey != NULL) { + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_RSA; + if (out != NULL) { + *out = pkey; + } + + pkey->ownRsa = 1; + pkey->rsa = wolfSSL_RSA_new(); + if (pkey->rsa == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + if (wolfSSL_RSA_LoadDer_ex(pkey->rsa, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, WOLFSSL_RSA_LOAD_PUBLIC) != 1) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; + } + } + wc_FreeRsaKey(&rsa); + } + #endif /* NO_RSA */ + + #ifdef HAVE_ECC + { + word32 keyIdx = 0; + ecc_key ecc; + + if (wc_ecc_init(&ecc) == 0 && + wc_EccPublicKeyDecode(mem, &keyIdx, &ecc, (word32)memSz) == 0) { + wc_ecc_free(&ecc); + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey != NULL) { + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_EC; + if (out != NULL) { + *out = pkey; + } + + pkey->ownEcc = 1; + pkey->ecc = wolfSSL_EC_KEY_new(); + if (pkey->ecc == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + if (wolfSSL_EC_KEY_LoadDer_ex(pkey->ecc, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; + } + } + wc_ecc_free(&ecc); + } + #endif /* HAVE_ECC */ + + #if !defined(NO_DSA) + { + DsaKey dsa; + word32 keyIdx = 0; + + /* test if DSA key */ + if (wc_InitDsaKey(&dsa) == 0 && + wc_DsaPublicKeyDecode(mem, &keyIdx, &dsa, (word32)memSz) == 0) { + wc_FreeDsaKey(&dsa); + pkey = wolfSSL_EVP_PKEY_new(); + + if (pkey != NULL) { + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_DSA; + if (out != NULL) { + *out = pkey; + } + + pkey->ownDsa = 1; + pkey->dsa = wolfSSL_DSA_new(); + if (pkey->dsa == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + + if (wolfSSL_DSA_LoadDer_ex(pkey->dsa, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, WOLFSSL_DSA_LOAD_PUBLIC) != 1) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; + } + } + wc_FreeDsaKey(&dsa); + } + #endif /* NO_DSA */ + + #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) + { + DhKey dh; + word32 keyIdx = 0; + + /* test if DH key */ + if (wc_InitDhKey(&dh) == 0 && + wc_DhKeyDecode(mem, &keyIdx, &dh, (word32)memSz) == 0) { + wc_FreeDhKey(&dh); + pkey = wolfSSL_EVP_PKEY_new(); + + if (pkey != NULL) { + pkey->pkey_sz = (int)memSz; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, mem, memSz); + pkey->type = EVP_PKEY_DH; + if (out != NULL) { + *out = pkey; + } + + pkey->ownDh = 1; + pkey->dh = wolfSSL_DH_new(); + if (pkey->dh == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + if (wolfSSL_DH_LoadDer(pkey->dh, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz) != WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; + } + } + wc_FreeDhKey(&dh); + } + #endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + + return pkey; +} + + +/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. + * + * type type of key + * out newly created WOLFSSL_EVP_PKEY structure + * in pointer to input key DER + * inSz size of in buffer + * + * On success a non null pointer is returned and the pointer in is advanced the + * same number of bytes read. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz) +{ + WOLFSSL_EVP_PKEY* local; + word32 idx = 0; + int ret; + word32 algId; + + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey"); + + if (in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. */ + if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, (word32)inSz, + &algId)) > 0) { + WOLFSSL_MSG("Found and removed PKCS8 header"); + } + else { + if (ret != ASN_PARSE_E) { + WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); + return NULL; + } + } + + if (out != NULL && *out != NULL) { + wolfSSL_EVP_PKEY_free(*out); + *out = NULL; + } + local = wolfSSL_EVP_PKEY_new(); + if (local == NULL) { + return NULL; + } + + /* sanity check on idx before use */ + if ((int)idx > inSz) { + WOLFSSL_MSG("Issue with index pointer"); + wolfSSL_EVP_PKEY_free(local); + local = NULL; + return NULL; + } + + local->type = type; + local->pkey_sz = (int)inSz - idx; + local->pkey.ptr = (char*)XMALLOC(inSz - idx, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + if (local->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(local); + local = NULL; + return NULL; + } + else { + XMEMCPY(local->pkey.ptr, *in + idx, inSz - idx); + } + + switch (type) { +#ifndef NO_RSA + case EVP_PKEY_RSA: + local->ownRsa = 1; + local->rsa = wolfSSL_RSA_new(); + if (local->rsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wolfSSL_RSA_LoadDer_ex(local->rsa, + (const unsigned char*)local->pkey.ptr, local->pkey_sz, + WOLFSSL_RSA_LOAD_PRIVATE) != SSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* NO_RSA */ +#ifdef HAVE_ECC + case EVP_PKEY_EC: + local->ownEcc = 1; + local->ecc = wolfSSL_EC_KEY_new(); + if (local->ecc == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wolfSSL_EC_KEY_LoadDer(local->ecc, + (const unsigned char*)local->pkey.ptr, local->pkey_sz) + != SSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* HAVE_ECC */ +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +#ifndef NO_DSA + case EVP_PKEY_DSA: + local->ownDsa = 1; + local->dsa = wolfSSL_DSA_new(); + if (local->dsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wolfSSL_DSA_LoadDer(local->dsa, + (const unsigned char*)local->pkey.ptr, local->pkey_sz) + != SSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* NO_DSA */ +#ifndef NO_DH + case EVP_PKEY_DH: + local->ownDh = 1; + local->dh = wolfSSL_DH_new(); + if (local->dh == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wolfSSL_DH_LoadDer(local->dh, + (const unsigned char*)local->pkey.ptr, local->pkey_sz) + != SSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* HAVE_DH */ +#endif /* WOLFSSL_QT || OPENSSL_ALL */ + default: + WOLFSSL_MSG("Unsupported key type"); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + + /* advance pointer with success */ + if (local != NULL) { + if ((idx + local->pkey_sz) <= (word32)inSz) { + *in = *in + idx + local->pkey_sz; + } + + if (out != NULL) { + *out = local; + } + } + + return local; +} + +#ifndef NO_CERTS + +int wolfSSL_check_private_key(const WOLFSSL* ssl) +{ + DecodedCert der; + word32 size; + byte* buff; + int ret; + + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + + size = ssl->buffers.certificate->length; + buff = ssl->buffers.certificate->buffer; + InitDecodedCert(&der, buff, size, ssl->heap); +#ifdef HAVE_PK_CALLBACKS + ret = InitSigPkCb((WOLFSSL*)ssl, &der.sigCtx); + if (ret != 0) { + FreeDecodedCert(&der); + return ret; + } +#endif + + if (ParseCertRelative(&der, CERT_TYPE, NO_VERIFY, NULL) != 0) { + FreeDecodedCert(&der); + return WOLFSSL_FAILURE; + } + + size = ssl->buffers.key->length; + buff = ssl->buffers.key->buffer; + ret = wc_CheckPrivateKey(buff, size, &der); + FreeDecodedCert(&der); + return ret; +} + +#if defined(OPENSSL_ALL) +/* Returns the number of X509V3 extensions in X509 object, or 0 on failure */ +int wolfSSL_X509_get_ext_count(const WOLFSSL_X509* passedCert) +{ + int extCount = 0; + int length = 0; + int outSz = 0; + const byte* rawCert; + int sz = 0; + word32 idx = 0; + DecodedCert cert; + const byte* input; + + WOLFSSL_ENTER("wolfSSL_X509_get_ext_count()"); + if (passedCert == NULL) { + WOLFSSL_MSG("\tNot passed a certificate"); + return WOLFSSL_FAILURE; + } + + rawCert = wolfSSL_X509_get_der((WOLFSSL_X509*)passedCert, &outSz); + if (rawCert == NULL) { + WOLFSSL_MSG("\tpassedCert has no internal DerBuffer set."); + return WOLFSSL_FAILURE; + } + InitDecodedCert(&cert, rawCert, (word32)outSz, 0); + + if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) { + WOLFSSL_MSG("\tCertificate parsing failed"); + return WOLFSSL_FAILURE; + } + + input = cert.extensions; + sz = cert.extensionsSz; + + if (input == NULL || sz == 0) { + WOLFSSL_MSG("\tsz or input NULL error"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } + + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } + + while (idx < (word32)sz) { + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE"); + FreeDecodedCert(&cert); + return WOLFSSL_FAILURE; + } + idx += length; + extCount++; + } + FreeDecodedCert(&cert); + return extCount; +} + +/* Creates and returns pointer to a new X509_EXTENSION object in memory */ +WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_new(void) +{ + WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_new"); + + WOLFSSL_X509_EXTENSION* newExt; + newExt = (WOLFSSL_X509_EXTENSION*)XMALLOC(sizeof(WOLFSSL_X509_EXTENSION), + NULL, DYNAMIC_TYPE_X509_EXT); + if (newExt == NULL) + return NULL; + XMEMSET(newExt, 0, sizeof(WOLFSSL_X509_EXTENSION)); + + return newExt; +} + +void wolfSSL_X509_EXTENSION_free(WOLFSSL_X509_EXTENSION* x) +{ + WOLFSSL_ASN1_STRING asn1; + WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_free"); + if (x == NULL) + return; + + if (x->obj != NULL) + wolfSSL_ASN1_OBJECT_free(x->obj); + + asn1 = x->value; + if (asn1.length > 0 && asn1.data != NULL && asn1.isDynamic) + XFREE(asn1.data, NULL, DYNAMIC_TYPE_OPENSSL); + + wolfSSL_sk_free(x->ext_sk); + + XFREE(x, NULL, DYNAMIC_TYPE_X509_EXT); +} + +/* Creates and returns a new WOLFSSL_X509_EXTENSION stack. */ +WOLFSSL_STACK* wolfSSL_sk_new_x509_ext(void) +{ + WOLFSSL_STACK* sk; + WOLFSSL_ENTER("wolfSSL_sk_new_x509_ext"); + + sk = wolfSSL_sk_new_null(); + if (sk) { + sk->type = STACK_TYPE_X509_EXT; + } + return sk; +} + +/* return 1 on success 0 on fail */ +int wolfSSL_sk_X509_EXTENSION_push(WOLFSSL_STACK* sk,WOLFSSL_X509_EXTENSION* ext) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_X509_EXTENSION_push"); + + if (sk == NULL || ext == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.ext == NULL) { + sk->data.ext = ext; + sk->num += 1; + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_X509); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new obj onto head of stack */ + node->data.ext = sk->data.ext; + node->next = sk->next; + node->type = sk->type; + sk->next = node; + sk->data.ext = ext; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} + +/* Free the structure for X509_EXTENSION stack + * + * sk stack to free nodes in + */ +void wolfSSL_sk_X509_EXTENSION_free(WOLFSSL_STACK* sk) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_X509_EXTENSION_free"); + + if (sk == NULL) { + return; + } + + /* parse through stack freeing each node */ + node = sk->next; + while ((node != NULL) && (sk->num > 1)) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + wolfSSL_X509_EXTENSION_free(tmp->data.ext); + XFREE(tmp, NULL, DYNAMIC_TYPE_X509); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + wolfSSL_X509_EXTENSION_free(sk->data.ext); + } + XFREE(sk, NULL, DYNAMIC_TYPE_X509); +} + +int wolfSSL_ASN1_BIT_STRING_set_bit(WOLFSSL_ASN1_BIT_STRING* str, int pos, + int val) +{ + int bytes_cnt, bit; + byte* temp; + + if (!str || (val != 0 && val != 1) || pos < 0) { + return WOLFSSL_FAILURE; + } + + bytes_cnt = pos/8; + bit = 1<<(7-(pos%8)); + + if (bytes_cnt+1 > str->length) { + if (!(temp = (byte*)XREALLOC(str->data, bytes_cnt+1, NULL, + DYNAMIC_TYPE_OPENSSL))) { + return WOLFSSL_FAILURE; + } + XMEMSET(temp+str->length, 0, bytes_cnt+1 - str->length); + str->data = temp; + str->length = bytes_cnt+1; + } + + str->data[bytes_cnt] &= ~bit; + str->data[bytes_cnt] |= val ? bit : 0; + + return WOLFSSL_SUCCESS; +} + +/* Gets the X509_EXTENSION* ext based on it's location in WOLFSSL_X509* x509. + * + * x509 : The X509 structure to look for the extension. + * loc : Location of the extension. If the extension is found at the given + * location, a new X509_EXTENSION structure is populated with extension-specific + * data based on the extension type. + + * Returns NULL on error or pointer to X509_EXTENSION structure containing the + * extension. The returned X509_EXTENSION should not be free'd by caller. + * The returned X509_EXTENSION is pushed onto a stack inside the x509 argument. + * This is later free'd when x509 is free'd. + * + * NOTE: for unknown extension NIDs, a X509_EXTENSION is populated with the + * extension oid as the ASN1_OBJECT (QT compatibility) + */ +WOLFSSL_X509_EXTENSION* wolfSSL_X509_get_ext(const WOLFSSL_X509* x509, int loc) +{ + WOLFSSL_X509_EXTENSION* ext = NULL; + WOLFSSL_ENTER("wolfSSL_X509_get_ext"); + if (x509 == NULL) + return NULL; + + ext = wolfSSL_X509_set_ext((WOLFSSL_X509*) x509, loc); + return ext; +} + +/* Pushes a new X509_EXTENSION* ext onto the stack inside WOLFSSL_X509* x509. + * This is currently a helper function for wolfSSL_X509_get_ext + * Caller does not free the returned WOLFSSL_X509_EXTENSION* + */ +WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x509, int loc) +{ + int extCount = 0, length = 0, outSz = 0, sz = 0, ret = 0; + int objSz = 0, isSet = 0; + const byte* rawCert; + const byte* input; + byte* oidBuf; + word32 oid, idx = 0, tmpIdx = 0; + WOLFSSL_X509_EXTENSION* ext = NULL; + WOLFSSL_ASN1_INTEGER* a; + WOLFSSL_STACK* sk; + DecodedCert cert; + + WOLFSSL_ENTER("wolfSSL_X509_set_ext"); + + if(x509 == NULL){ + WOLFSSL_MSG("\tNot passed a certificate"); + return NULL; + } + + if(loc <0 || (loc > wolfSSL_X509_get_ext_count(x509))){ + WOLFSSL_MSG("\tBad location argument"); + return NULL; + } + + ext = wolfSSL_X509_EXTENSION_new(); + if (ext == NULL) { + WOLFSSL_MSG("\tX509_EXTENSION_new() failed"); + return NULL; + } + + rawCert = wolfSSL_X509_get_der((WOLFSSL_X509*)x509, &outSz); + if (rawCert == NULL) { + WOLFSSL_MSG("\tX509_get_der() failed"); + wolfSSL_X509_EXTENSION_free(ext); + return NULL; + } + + InitDecodedCert( &cert, rawCert, (word32)outSz, 0); + + if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) { + WOLFSSL_MSG("\tCertificate parsing failed"); + wolfSSL_X509_EXTENSION_free(ext); + return NULL; + } + + input = cert.extensions; + sz = cert.extensionsSz; + + if (input == NULL || sz == 0) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + + while (idx < (word32)sz) { + oid = 0; + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + + tmpIdx = idx; + ret = GetObjectId(input, &idx, &oid, oidCertExtType, sz); + if (ret < 0) { + WOLFSSL_MSG("\tfail: OBJECT ID"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + idx = tmpIdx; + + /* Continue while loop until extCount == loc or idx > sz */ + if (extCount != loc) { + idx += length; + extCount++; + continue; + } + /* extCount == loc. Now get the extension. */ + /* Check if extension has been set */ + isSet = wolfSSL_X509_ext_isSet_by_NID((WOLFSSL_X509*)x509, oid); + ext->obj = wolfSSL_OBJ_nid2obj(oid); + if (ext->obj == NULL) { + WOLFSSL_MSG("\tfail: Invalid OBJECT"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + ext->obj->nid = oid; + + switch (oid) { + case BASIC_CA_OID: + if (!isSet) + break; + /* Set pathlength */ + a = wolfSSL_ASN1_INTEGER_new(); + if (a == NULL) { + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + a->length = x509->pathLength; + + /* Save ASN1_INTEGER in x509 extension */ + ext->obj->pathlen = a; + + ext->obj->ca = x509->isCa; + ext->crit = x509->basicConstCrit; + break; + + case AUTH_INFO_OID: + if (!isSet) + break; + + /* Create a stack to hold both the caIssuer and ocsp objects + in X509_EXTENSION structure */ + sk = (WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)*)XMALLOC( + sizeof(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)), + NULL, DYNAMIC_TYPE_ASN1); + if (sk == NULL) { + WOLFSSL_MSG("Failed to malloc stack"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + XMEMSET(sk, 0, sizeof(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT))); + sk->type = STACK_TYPE_OBJ; + + /* Add CaIssuers object to stack */ + if (x509->authInfoCaIssuer != NULL && + x509->authInfoCaIssuerSz > 0) + { + WOLFSSL_ASN1_OBJECT* obj; + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Error creating ASN1 object"); + wolfSSL_sk_ASN1_OBJECT_free(sk); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + obj->obj = (byte*)x509->authInfoCaIssuer; + obj->objSz = x509->authInfoCaIssuerSz; + obj->grp = oidCertAuthInfoType; + obj->nid = AIA_CA_ISSUER_OID; + + ret = wolfSSL_sk_ASN1_OBJECT_push(sk, obj); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing ASN1 object onto stack"); + wolfSSL_ASN1_OBJECT_free(obj); + wolfSSL_sk_ASN1_OBJECT_free(sk); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + } + + /* Add OCSP object to stack */ + if (x509->authInfo != NULL && + x509->authInfoSz > 0) + { + WOLFSSL_ASN1_OBJECT* obj; + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Error creating ASN1 object"); + wolfSSL_sk_ASN1_OBJECT_free(sk); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + obj->obj = x509->authInfo; + obj->objSz = x509->authInfoSz; + obj->grp = oidCertAuthInfoType; + obj->nid = AIA_OCSP_OID; + + ret = wolfSSL_sk_ASN1_OBJECT_push(sk, obj); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing ASN1 object onto stack"); + wolfSSL_ASN1_OBJECT_free(obj); + wolfSSL_sk_ASN1_OBJECT_free(sk); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + } + ext->ext_sk = sk; + ext->crit = x509->authInfoCrit; + break; + + case AUTH_KEY_OID: + if (!isSet) + break; + + ret = wolfSSL_ASN1_STRING_set(&ext->value, x509->authKeyId, + x509->authKeyIdSz); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + ext->crit = x509->authKeyIdCrit; + break; + + case SUBJ_KEY_OID: + if (!isSet) + break; + + ret = wolfSSL_ASN1_STRING_set(&ext->value, x509->subjKeyId, + x509->subjKeyIdSz); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + ext->crit = x509->subjKeyIdCrit; + break; + + case CERT_POLICY_OID: + if (!isSet) + break; + ext->crit = x509->certPolicyCrit; + break; + + case KEY_USAGE_OID: + if (!isSet) + break; + + ret = wolfSSL_ASN1_STRING_set(&ext->value, + (byte*)&(x509->keyUsage), sizeof(word16)); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + ext->crit = x509->keyUsageCrit; + break; + + case EXT_KEY_USAGE_OID: + if (!isSet) + break; + ext->crit = x509->keyUsageCrit; + break; + + case CRL_DIST_OID: + if (!isSet) + break; + ext->crit = x509->CRLdistCrit; + break; + + case ALT_NAMES_OID: + { + WOLFSSL_GENERAL_NAME* gn = NULL; + DNS_entry* dns = NULL; + if (!isSet) + break; + + sk = (WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)*)XMALLOC( + sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)), NULL, + DYNAMIC_TYPE_ASN1); + if (sk == NULL) { + return NULL; + } + XMEMSET(sk, 0, sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME))); + sk->type = STACK_TYPE_GEN_NAME; + + if (x509->subjAltNameSet && x509->altNames != NULL) { + /* alt names are DNS_entry structs */ + dns = x509->altNames; + /* Currently only support GEN_DNS type */ + while (dns != NULL) { + gn = wolfSSL_GENERAL_NAME_new(); + if (gn == NULL) { + WOLFSSL_MSG("Error creating GENERAL_NAME"); + wolfSSL_sk_free(sk); + return NULL; + } + + gn->type = dns->type; + gn->d.ia5->length = dns->len; + if (wolfSSL_ASN1_STRING_set(gn->d.ia5, dns->name, + gn->d.ia5->length) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set failed"); + wolfSSL_GENERAL_NAME_free(gn); + wolfSSL_sk_free(sk); + return NULL; + } + + dns = dns->next; + /* last dns in list add at end of function */ + if (dns != NULL) { + if (wolfSSL_sk_GENERAL_NAME_push(sk, gn) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing onto stack"); + wolfSSL_GENERAL_NAME_free(gn); + wolfSSL_sk_free(sk); + sk = NULL; + } + } + } + if (wolfSSL_sk_GENERAL_NAME_push(sk,gn) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing onto stack"); + wolfSSL_GENERAL_NAME_free(gn); + wolfSSL_sk_free(sk); + sk = NULL; + } + } + ext->ext_sk = sk; + ext->crit = x509->subjAltNameCrit; + break; + } + + default: + WOLFSSL_MSG("Unknown extension type found, parsing OID"); + /* If the extension type is not recognized/supported, + set the ASN1_OBJECT in the extension with the + parsed oid for access in later function calls */ + + /* Get OID from input */ + if (GetASNObjectId(input, &idx, &length, sz) != 0) { + WOLFSSL_MSG("Failed to Get ASN Object Id"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + oidBuf = (byte*)XMALLOC(length+1+MAX_LENGTH_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (oidBuf == NULL) { + WOLFSSL_MSG("Failed to malloc tmp buffer"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + oidBuf[0] = ASN_OBJECT_ID; + objSz++; + objSz += SetLength(length, oidBuf + 1); + objSz += length; + + /* Set object size and reallocate space in object buffer */ + ext->obj->objSz = objSz; + if(((ext->obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) || + (ext->obj->obj == NULL)) { + ext->obj->obj =(byte*)XREALLOC((byte*)ext->obj->obj, + ext->obj->objSz, + NULL,DYNAMIC_TYPE_ASN1); + if (ext->obj->obj == NULL) { + wolfSSL_ASN1_OBJECT_free(ext->obj); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + ext->obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; + } else { + ext->obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + } + /* Get OID from input and copy to ASN1_OBJECT buffer */ + XMEMCPY(oidBuf+2, input+idx, length); + XMEMCPY((byte*)ext->obj->obj, oidBuf, ext->obj->objSz); + XFREE(oidBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + oidBuf = NULL; + ext->obj->grp = oidCertExtType; + ext->crit = 0; + + /* Get extension data and copy as ASN1_STRING */ + tmpIdx = idx + length; + if ((tmpIdx >= (word32)sz) || (input[tmpIdx++] != ASN_OCTET_STRING)) { + WOLFSSL_MSG("Error decoding unknown extension data"); + wolfSSL_ASN1_OBJECT_free(ext->obj); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + + if (GetLength(input, &tmpIdx, &length, sz) <= 0) { + WOLFSSL_MSG("Error: Invalid Input Length."); + wolfSSL_ASN1_OBJECT_free(ext->obj); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + ext->value.data = (char*)XMALLOC(length, NULL, DYNAMIC_TYPE_ASN1); + ext->value.isDynamic = 1; + if (ext->value.data == NULL) { + WOLFSSL_MSG("Failed to malloc ASN1_STRING data"); + wolfSSL_X509_EXTENSION_free(ext); + FreeDecodedCert(&cert); + return NULL; + } + XMEMCPY(ext->value.data,input+tmpIdx,length); + ext->value.length = length; + } /* switch(oid) */ + + break; /* Got the Extension. Now exit while loop. */ + + } /* while(idx < sz) */ + + /* Store the new extension in a stack inside x509 + * The extensions on the stack are free'd internally when FreeX509 is called + */ + if (x509->ext_sk == NULL) + x509->ext_sk = wolfSSL_sk_new_x509_ext(); + if (x509->ext_sk != NULL) + wolfSSL_sk_X509_EXTENSION_push(x509->ext_sk, ext); + + FreeDecodedCert(&cert); + return ext; +} + +/* Return 0 on success and 1 on failure. Copies ext data to bio, using indent + * to pad the output. flag is ignored. */ +int wolfSSL_X509V3_EXT_print(WOLFSSL_BIO *out, WOLFSSL_X509_EXTENSION *ext, + unsigned long flag, int indent) +{ + ASN1_OBJECT* obj; + ASN1_STRING* str; + int nid; + const int sz = CTC_NAME_SIZE*2; + int rc = WOLFSSL_FAILURE; + char tmp[CTC_NAME_SIZE*2]; + WOLFSSL_ENTER("wolfSSL_X509V3_EXT_print"); + + if ((out == NULL) || (ext == NULL)) { + WOLFSSL_MSG("NULL parameter error"); + return rc; + } + + obj = wolfSSL_X509_EXTENSION_get_object(ext); + if (obj == NULL) { + WOLFSSL_MSG("Error getting ASN1_OBJECT from X509_EXTENSION"); + return rc; + } + + str = wolfSSL_X509_EXTENSION_get_data(ext); + if (obj == NULL) { + WOLFSSL_MSG("Error getting ASN1_STRING from X509_EXTENSION"); + return rc; + } + + /* Print extension based on the type */ + nid = wolfSSL_OBJ_obj2nid(obj); + switch (nid) { + case BASIC_CA_OID: + { + char isCa[] = "TRUE"; + char notCa[] = "FALSE"; + XSNPRINTF(tmp, sz, "%*sCA:%s", indent, "", + obj->ca ? isCa : notCa); + break; + } + case ALT_NAMES_OID: + { + WOLFSSL_STACK* sk; + char* val; + int len; + tmp[0] = '\0'; /* Make sure tmp is null-terminated */ + + sk = ext->ext_sk; + while (sk != NULL) { + if (sk->type == STACK_TYPE_GEN_NAME && sk->data.gn) { + /* str is GENERAL_NAME for subject alternative name ext */ + str = sk->data.gn->d.ia5; + len = str->length + 2; /* + 2 for NULL char and "," */ + if (len > sz) { + WOLFSSL_MSG("len greater than buffer size"); + return rc; + } + + val = (char*)XMALLOC(len + indent, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (val == NULL) { + WOLFSSL_MSG("Memory error"); + return rc; + } + if (sk->next) + XSNPRINTF(val, len, "%*s%s, ", indent, "", str->strData); + else + XSNPRINTF(val, len, "%*s%s", indent, "", str->strData); + + XSTRNCAT(tmp, val, len); + XFREE(val, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + sk = sk->next; + } + break; + } + case AUTH_KEY_OID: + case SUBJ_KEY_OID: + { + char* asn1str; + asn1str = wolfSSL_i2s_ASN1_STRING(NULL, str); + XSNPRINTF(tmp, sz, "%*s%s", indent, "", asn1str); + XFREE(asn1str, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + } + case AUTH_INFO_OID: + case CERT_POLICY_OID: + case CRL_DIST_OID: + case KEY_USAGE_OID: + WOLFSSL_MSG("X509V3_EXT_print not yet implemented for ext type"); + break; + + default: + XSNPRINTF(tmp, sz, "%*s%s", indent, "", str->strData); + } + + if (wolfSSL_BIO_write(out, tmp, (int)XSTRLEN(tmp)) == (int)XSTRLEN(tmp)) { + rc = WOLFSSL_SUCCESS; + } + (void) flag; + + return rc; +} + +/* Returns crit flag in X509_EXTENSION object */ +int wolfSSL_X509_EXTENSION_get_critical(const WOLFSSL_X509_EXTENSION* ex) +{ + WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_get_critical"); + if (ex == NULL) + return BAD_FUNC_ARG; + return ex->crit; +} + +/* Creates v3_ext_method for a given X509v3 extension + * + * ex : The X509_EXTENSION used to create v3_ext_method. If the extension is + * not NULL, get the NID of the extension object and populate the + * extension type-specific X509V3_EXT_* function(s) in v3_ext_method. + * + * Returns NULL on error or pointer to the v3_ext_method populated with extension + * type-specific X509V3_EXT_* function(s). + * + * NOTE: NID_subject_key_identifier is currently the only extension implementing + * the X509V3_EXT_* functions, as it is the only type called directly by QT. The + * other extension types return a pointer to a v3_ext_method struct that contains + * only the NID. + */ +const WOLFSSL_v3_ext_method* wolfSSL_X509V3_EXT_get(WOLFSSL_X509_EXTENSION* ex) +{ + int nid; + WOLFSSL_v3_ext_method method; + + WOLFSSL_ENTER("wolfSSL_X509V3_EXT_get"); + if ((ex == NULL) || (ex->obj == NULL)) { + WOLFSSL_MSG("Passed an invalid X509_EXTENSION*"); + return NULL; + } + /* Initialize all methods to NULL */ + method.d2i = NULL; + method.i2v = NULL; + method.i2s = NULL; + method.i2r = NULL; + + nid = ex->obj->nid; + if (nid <= 0) { + WOLFSSL_MSG("Failed to get nid from passed extension object"); + return NULL; + } + + switch (nid) { + case NID_basic_constraints: + break; + case NID_subject_key_identifier: + method.i2s = (X509V3_EXT_I2S)wolfSSL_i2s_ASN1_STRING; + break; + case NID_key_usage: + WOLFSSL_MSG("i2v function not yet implemented for Key Usage"); + break; + case NID_authority_key_identifier: + WOLFSSL_MSG("i2v function not yet implemented for Auth Key Id"); + break; + case NID_info_access: + WOLFSSL_MSG("i2v function not yet implemented for Info Access"); + break; + case NID_ext_key_usage: + WOLFSSL_MSG("i2v function not yet implemented for Ext Key Usage"); + break; + case NID_certificate_policies: + WOLFSSL_MSG("r2i function not yet implemented for Cert Policies"); + break; + case NID_crl_distribution_points: + WOLFSSL_MSG("r2i function not yet implemented for CRL Dist Points"); + break; + default: + /* If extension type is unknown, return NULL -- QT makes call to + X509_EXTENSION_get_data() if there is no v3_ext_method */ + WOLFSSL_MSG("X509V3_EXT_get(): Unknown extension type found"); + return NULL; + } + + method.ext_nid = nid; + ex->ext_method = method; + + return (const WOLFSSL_v3_ext_method*)&ex->ext_method; +} + +/* Parses and returns an x509v3 extension internal structure. + * + * ext : The X509_EXTENSION for parsing internal structure. If extension is + * not NULL, get the NID of the extension object and create a new + * extension-specific internal structure based on the extension type. + * + * Returns NULL on error or if NID is not found, otherwise returns a pointer to + * the extension type-specific X509_EXTENSION internal structure. + * Return is expected to be free'd by caller. + */ +void* wolfSSL_X509V3_EXT_d2i(WOLFSSL_X509_EXTENSION* ext) +{ + const WOLFSSL_v3_ext_method* method; + int ret; + WOLFSSL_ASN1_OBJECT* object; + WOLFSSL_BASIC_CONSTRAINTS* bc; + WOLFSSL_AUTHORITY_KEYID* akey; + WOLFSSL_ASN1_STRING* asn1String, *newString; + WOLFSSL_AUTHORITY_INFO_ACCESS* aia; + WOLFSSL_STACK* sk; + + WOLFSSL_ENTER("wolfSSL_X509V3_EXT_d2i"); + + if(ext == NULL) { + WOLFSSL_MSG("Bad function Argument"); + return NULL; + } + + /* extract extension info */ + method = wolfSSL_X509V3_EXT_get(ext); + if (method == NULL) { + WOLFSSL_MSG("wolfSSL_X509V3_EXT_get error"); + return NULL; + } + object = wolfSSL_X509_EXTENSION_get_object(ext); + if (object == NULL) { + WOLFSSL_MSG("X509_EXTENSION_get_object failed"); + return NULL; + } + + /* Return pointer to proper internal structure based on NID */ + switch (object->type) { + /* basicConstraints */ + case (NID_basic_constraints): + WOLFSSL_MSG("basicConstraints"); + /* Allocate new BASIC_CONSTRAINTS structure */ + bc = (WOLFSSL_BASIC_CONSTRAINTS*) + XMALLOC(sizeof(WOLFSSL_BASIC_CONSTRAINTS), NULL, + DYNAMIC_TYPE_X509_EXT); + if (bc == NULL) { + WOLFSSL_MSG("Failed to malloc basic constraints"); + return NULL; + } + /* Copy pathlen and CA into BASIC_CONSTRAINTS from object */ + bc->ca = object->ca; + if (object->pathlen->length > 0) { + bc->pathlen = wolfSSL_ASN1_INTEGER_dup(object->pathlen); + if (bc->pathlen == NULL) { + WOLFSSL_MSG("Failed to duplicate ASN1_INTEGER"); + XFREE(bc, NULL, DYNAMIC_TYPE_X509_EXT); + return NULL; + } + } + else + bc->pathlen = NULL; + return bc; + + /* subjectKeyIdentifier */ + case (NID_subject_key_identifier): + WOLFSSL_MSG("subjectKeyIdentifier"); + asn1String = wolfSSL_X509_EXTENSION_get_data(ext); + if (asn1String == NULL) { + WOLFSSL_MSG("X509_EXTENSION_get_data() failed"); + return NULL; + } + newString = wolfSSL_ASN1_STRING_new(); + if (newString == NULL) { + WOLFSSL_MSG("Failed to malloc ASN1_STRING"); + return NULL; + } + ret = wolfSSL_ASN1_STRING_set(newString, asn1String->data, + asn1String->length); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_ASN1_STRING_free(newString); + return NULL; + }; + newString->type = asn1String->type; + return newString; + + /* authorityKeyIdentifier */ + case (NID_authority_key_identifier): + WOLFSSL_MSG("AuthorityKeyIdentifier"); + + akey = (WOLFSSL_AUTHORITY_KEYID*) + XMALLOC(sizeof(WOLFSSL_AUTHORITY_KEYID), NULL, + DYNAMIC_TYPE_X509_EXT); + if (akey == NULL) { + WOLFSSL_MSG("Failed to malloc authority key id"); + return NULL; + } + + akey->keyid = wolfSSL_ASN1_STRING_new(); + if (akey->keyid == NULL) { + WOLFSSL_MSG("ASN1_STRING_new() failed"); + wolfSSL_AUTHORITY_KEYID_free(akey); + return NULL; + } + + asn1String = wolfSSL_X509_EXTENSION_get_data(ext); + if (asn1String == NULL) { + WOLFSSL_MSG("X509_EXTENSION_get_data() failed"); + wolfSSL_AUTHORITY_KEYID_free(akey); + return NULL; + } + + ret = wolfSSL_ASN1_STRING_set(akey->keyid, asn1String->data, + asn1String->length); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_AUTHORITY_KEYID_free(akey); + return NULL; + }; + akey->keyid->type = asn1String->type; + + /* For now, set issuer and serial to NULL. This may need to be + updated for future use */ + akey->issuer = NULL; + akey->serial = NULL; + return akey; + + /* keyUsage */ + case (NID_key_usage): + WOLFSSL_MSG("keyUsage"); + /* This may need to be updated for future use. The i2v method for + keyUsage is not currently set. For now, return the ASN1_STRING + representation of KeyUsage bit string */ + asn1String = wolfSSL_X509_EXTENSION_get_data(ext); + if (asn1String == NULL) { + WOLFSSL_MSG("X509_EXTENSION_get_data() failed"); + return NULL; + } + newString = wolfSSL_ASN1_STRING_new(); + if (newString == NULL) { + WOLFSSL_MSG("Failed to malloc ASN1_STRING"); + return NULL; + } + ret = wolfSSL_ASN1_STRING_set(newString, asn1String->data, + asn1String->length); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_ASN1_STRING_free(newString); + return NULL; + }; + newString->type = asn1String->type; + return newString; + + /* extKeyUsage */ + case (NID_ext_key_usage): + WOLFSSL_MSG("extKeyUsage not supported yet"); + return NULL; + + /* certificatePolicies */ + case (NID_certificate_policies): + WOLFSSL_MSG("certificatePolicies not supported yet"); + return NULL; + + /* cRLDistributionPoints */ + case (NID_crl_distribution_points): + WOLFSSL_MSG("cRLDistributionPoints not supported yet"); + return NULL; + + /* authorityInfoAccess */ + case (NID_info_access): + WOLFSSL_MSG("AuthorityInfoAccess"); + + sk = ext->ext_sk; + if (sk == NULL) { + WOLFSSL_MSG("ACCESS_DESCRIPTION stack NULL"); + return NULL; + } + + /* AUTHORITY_INFO_ACCESS is a stack of ACCESS_DESCRIPTION entries */ + aia = wolfSSL_sk_new_null(); + if (aia == NULL) { + WOLFSSL_MSG("Failed to malloc AUTHORITY_INFO_ACCESS"); + return NULL; + } + aia->type = STACK_TYPE_ACCESS_DESCRIPTION; + + while (sk) { + WOLFSSL_ACCESS_DESCRIPTION* ad; + WOLFSSL_ASN1_OBJECT* aiaEntry; + + if (sk->type != STACK_TYPE_OBJ) { + sk = sk->next; + continue; + } + + aiaEntry = sk->data.obj; + + /* ACCESS_DESCRIPTION has two members, method and location. + Method: ASN1_OBJECT as either AIA_OCSP_OID or AIA_CA_ISSUER_OID + Location: GENERAL_NAME structure containing the URI. */ + + ad = (WOLFSSL_ACCESS_DESCRIPTION*) + XMALLOC(sizeof(WOLFSSL_ACCESS_DESCRIPTION), NULL, + DYNAMIC_TYPE_X509_EXT); + if (ad == NULL) { + WOLFSSL_MSG("Failed to malloc ACCESS_DESCRIPTION"); + XFREE(aia, NULL, DYNAMIC_TYPE_X509_EXT); + return NULL; + } + XMEMSET(ad, 0, sizeof(WOLFSSL_ACCESS_DESCRIPTION)); + + /* Create new ASN1_OBJECT from oid */ + ad->method = wolfSSL_OBJ_nid2obj(aiaEntry->nid); + if (ad->method == NULL) { + WOLFSSL_MSG("OBJ_nid2obj() failed"); + XFREE(aia, NULL, DYNAMIC_TYPE_X509_EXT); + XFREE(ad, NULL, DYNAMIC_TYPE_X509_EXT); + return NULL; + } + + /* Allocate memory for GENERAL NAME */ + ad->location = (WOLFSSL_GENERAL_NAME*) + XMALLOC(sizeof(WOLFSSL_GENERAL_NAME), NULL, + DYNAMIC_TYPE_OPENSSL); + if (ad->location == NULL) { + WOLFSSL_MSG("Failed to malloc GENERAL_NAME"); + wolfSSL_ASN1_OBJECT_free(ad->method); + XFREE(aia, NULL, DYNAMIC_TYPE_X509_EXT); + XFREE(ad, NULL, DYNAMIC_TYPE_X509_EXT); + return NULL; + } + XMEMSET(ad->location, 0, sizeof(WOLFSSL_GENERAL_NAME)); + ad->location->type = GEN_URI; + ad->location->d.uniformResourceIdentifier = + wolfSSL_ASN1_STRING_new(); + /* Set the URI in GENERAL_NAME */ + ret = wolfSSL_ASN1_STRING_set( + ad->location->d.uniformResourceIdentifier, + aiaEntry->obj, aiaEntry->objSz); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set() failed"); + wolfSSL_ASN1_OBJECT_free(ad->method); + XFREE(aia, NULL, DYNAMIC_TYPE_X509_EXT); + XFREE(ad, NULL, DYNAMIC_TYPE_X509_EXT); + return NULL; + } + /* Push to AUTHORITY_INFO_ACCESS stack */ + ret = wolfSSL_sk_ACCESS_DESCRIPTION_push(aia, ad); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing ASN1 AD onto stack"); + wolfSSL_sk_ACCESS_DESCRIPTION_pop_free(aia, NULL); + wolfSSL_ASN1_OBJECT_free(ad->method); + XFREE(aia, NULL, DYNAMIC_TYPE_X509_EXT); + XFREE(ad, NULL, DYNAMIC_TYPE_X509_EXT); + return NULL; + } + + sk = sk->next; + } + return aia; + + default: + WOLFSSL_MSG("Extension NID not in table, returning NULL"); + break; + } + return NULL; +} + +/* Looks for the extension matching the passed in nid + * + * x509 : certificate to get parse through for extension. + * nid : Extension OID to be found. + * lastPos : Start search from extension after lastPos. + * Set to -1 to search from index 0. + * return >= 0 If successful the extension index is returned. + * return -1 If extension is not found or error is encountered. + */ +int wolfSSL_X509_get_ext_by_NID(const WOLFSSL_X509* x509, int nid, int lastPos) +{ + int extCount = 0, length = 0, outSz = 0, sz = 0, ret = 0; + int isSet = 0, found = 0, loc; + const byte* rawCert; + const byte* input; + word32 oid, idx = 0, tmpIdx = 0; + DecodedCert cert; + + WOLFSSL_ENTER("wolfSSL_X509_get_ext_by_NID"); + + if(x509 == NULL){ + WOLFSSL_MSG("\tNot passed a certificate"); + return WOLFSSL_FATAL_ERROR; + } + + if(lastPos < -1 || (lastPos > (wolfSSL_X509_get_ext_count(x509) - 1))){ + WOLFSSL_MSG("\tBad location argument"); + return WOLFSSL_FATAL_ERROR; + } + + loc = lastPos + 1; + + rawCert = wolfSSL_X509_get_der((WOLFSSL_X509*)x509, &outSz); + if (rawCert == NULL) { + WOLFSSL_MSG("\tX509_get_der() failed"); + return WOLFSSL_FATAL_ERROR; + } + + InitDecodedCert( &cert, rawCert, (word32)outSz, 0); + + if (ParseCert(&cert, CA_TYPE, NO_VERIFY, NULL) < 0) { + WOLFSSL_MSG("\tCertificate parsing failed"); + return WOLFSSL_FATAL_ERROR; + } + + input = cert.extensions; + sz = cert.extensionsSz; + + if (input == NULL || sz == 0) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } + + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } + + while (idx < (word32)sz) { + oid = 0; + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } + + tmpIdx = idx; + ret = GetObjectId(input, &idx, &oid, oidCertExtType, sz); + if (ret < 0) { + WOLFSSL_MSG("\tfail: OBJECT ID"); + FreeDecodedCert(&cert); + return WOLFSSL_FATAL_ERROR; + } + idx = tmpIdx; + + if (extCount >= loc) { + /* extCount >= loc. Now check if extension has been set */ + isSet = wolfSSL_X509_ext_isSet_by_NID((WOLFSSL_X509*)x509, oid); + + if (isSet && ((word32)nid == oid)) { + found = 1; + break; + } + } + + idx += length; + extCount++; + } /* while(idx < sz) */ + + FreeDecodedCert(&cert); + + return found ? extCount : WOLFSSL_FATAL_ERROR; +} + + +#endif /* OPENSSL_ALL */ + +WOLFSSL_ASN1_BIT_STRING* wolfSSL_ASN1_BIT_STRING_new(void) +{ + WOLFSSL_ASN1_BIT_STRING* str; + + str = (WOLFSSL_ASN1_BIT_STRING*)XMALLOC(sizeof(WOLFSSL_ASN1_BIT_STRING), + NULL, DYNAMIC_TYPE_OPENSSL); + if (str) { + XMEMSET(str, 0, sizeof(WOLFSSL_ASN1_BIT_STRING)); + } + return str; +} + +void wolfSSL_ASN1_BIT_STRING_free(WOLFSSL_ASN1_BIT_STRING* str) +{ + if (str) { + if (str->data) { + XFREE(str->data, NULL, DYNAMIC_TYPE_OPENSSL); + str->data = NULL; + } + XFREE(str, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +int wolfSSL_ASN1_BIT_STRING_get_bit(const WOLFSSL_ASN1_BIT_STRING* str, int i) +{ + if (!str || !str->data || str->length <= (i/8) || i < 0) { + return WOLFSSL_FAILURE; + } + + return (str->data[i/8] & (1<<(7-(i%8)))) ? 1 : 0; +} + +/* Looks for the extension matching the passed in nid + * + * c : if not null then is set to status value -2 if multiple occurrences + * of the extension are found, -1 if not found, 0 if found and not + * critical, and 1 if found and critical. + * nid : Extension OID to be found. + * idx : if NULL return first extension found match, otherwise start search at + * idx location and set idx to the location of extension returned. + * returns NULL or a pointer to an WOLFSSL_ASN1_BIT_STRING (for KEY_USAGE_OID) + * or WOLFSSL_STACK (for other) + * holding extension structure + * + * NOTE code for decoding extensions is in asn.c DecodeCertExtensions -- + * use already decoded extension in this function to avoid decoding twice. + * Currently we do not make use of idx since getting pre decoded extensions. + */ +void* wolfSSL_X509_get_ext_d2i(const WOLFSSL_X509* x509, int nid, int* c, + int* idx) +{ + void* ret = NULL; + WOLFSSL_STACK* sk = NULL; + WOLFSSL_ASN1_OBJECT* obj = NULL; + WOLFSSL_GENERAL_NAME* gn = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_get_ext_d2i"); + + if (x509 == NULL) { + return NULL; + } + + if (c != NULL) { + *c = -1; /* default to not found */ + } + + switch (nid) { + case BASIC_CA_OID: + if (x509->basicConstSet) { + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + if (c != NULL) { + *c = x509->basicConstCrit; + } + obj->type = BASIC_CA_OID; + obj->grp = oidCertExtType; + obj->nid = nid; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \ + defined(WOLFSSL_APACHE_HTTPD) + obj->ca = x509->isCa; + #endif + } + else { + WOLFSSL_MSG("No Basic Constraint set"); + } + return obj; + + case ALT_NAMES_OID: + { + DNS_entry* dns = NULL; + /* Malloc GENERAL_NAME stack */ + sk = (WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)*)XMALLOC( + sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)), NULL, + DYNAMIC_TYPE_ASN1); + if (sk == NULL) { + return NULL; + } + XMEMSET(sk, 0, sizeof(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME))); + sk->type = STACK_TYPE_GEN_NAME; + + if (x509->subjAltNameSet && x509->altNames != NULL) { + /* alt names are DNS_entry structs */ + if (c != NULL) { + if (x509->altNames->next != NULL) { + *c = -2; /* more then one found */ + } + else { + *c = x509->subjAltNameCrit; + } + } + + dns = x509->altNames; + /* Currently only support GEN_DNS type */ + while (dns != NULL) { + gn = wolfSSL_GENERAL_NAME_new(); + if (gn == NULL) { + WOLFSSL_MSG("Error creating GENERAL_NAME"); + wolfSSL_sk_free(sk); + return NULL; + } + + gn->type = dns->type; + gn->d.ia5->length = dns->len; + if (wolfSSL_ASN1_STRING_set(gn->d.ia5, dns->name, + gn->d.ia5->length) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ASN1_STRING_set failed"); + wolfSSL_GENERAL_NAME_free(gn); + wolfSSL_sk_free(sk); + return NULL; + } + + dns = dns->next; + /* last dns in list add at end of function */ + if (dns != NULL) { + if (wolfSSL_sk_GENERAL_NAME_push(sk, gn) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing ASN1 object onto stack"); + wolfSSL_GENERAL_NAME_free(gn); + wolfSSL_sk_free(sk); + sk = NULL; + } + } + } + } + else { + WOLFSSL_MSG("No Alt Names set"); + } + + break; + } + + case CRL_DIST_OID: + if (x509->CRLdistSet && x509->CRLInfo != NULL) { + if (c != NULL) { + *c = x509->CRLdistCrit; + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->type = CRL_DIST_OID; + obj->grp = oidCertExtType; + obj->obj = x509->CRLInfo; + obj->objSz = x509->CRLInfoSz; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ; + } + else { + WOLFSSL_MSG("No CRL dist set"); + } + break; + + case AUTH_INFO_OID: + if (x509->authInfoSet && x509->authInfo != NULL) { + if (c != NULL) { + *c = x509->authInfoCrit; + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->type = AUTH_INFO_OID; + obj->grp = oidCertExtType; + obj->obj = x509->authInfo; + obj->objSz = x509->authInfoSz; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + } + else { + WOLFSSL_MSG("No Auth Info set"); + } + break; + + case AUTH_KEY_OID: + if (x509->authKeyIdSet) { + if (c != NULL) { + *c = x509->authKeyIdCrit; + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->type = AUTH_KEY_OID; + obj->grp = oidCertExtType; + obj->obj = x509->authKeyId; + obj->objSz = x509->authKeyIdSz; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + } + else { + WOLFSSL_MSG("No Auth Key set"); + } + break; + + case SUBJ_KEY_OID: + if (x509->subjKeyIdSet) { + if (c != NULL) { + *c = x509->subjKeyIdCrit; + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->type = SUBJ_KEY_OID; + obj->grp = oidCertExtType; + obj->obj = x509->subjKeyId; + obj->objSz = x509->subjKeyIdSz; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + } + else { + WOLFSSL_MSG("No Subject Key set"); + } + break; + + case CERT_POLICY_OID: + { + #ifdef WOLFSSL_CERT_EXT + int i; + + if (x509->certPoliciesNb > 0) { + if (c != NULL) { + if (x509->certPoliciesNb > 1) { + *c = -2; + } + else { + *c = 0; + } + } + + sk = wolfSSL_sk_new_asn1_obj(); + if (sk == NULL) { + return NULL; + } + + for (i = 0; i < x509->certPoliciesNb - 1; i++) { + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + wolfSSL_sk_ASN1_OBJECT_free(sk); + return NULL; + } + obj->type = CERT_POLICY_OID; + obj->grp = oidCertExtType; + obj->obj = (byte*)(x509->certPolicies[i]); + obj->objSz = MAX_CERTPOL_SZ; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + if (wolfSSL_sk_ASN1_OBJECT_push(sk, obj) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error pushing ASN1 object onto stack"); + wolfSSL_ASN1_OBJECT_free(obj); + wolfSSL_sk_ASN1_OBJECT_free(sk); + sk = NULL; + } + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + wolfSSL_sk_ASN1_OBJECT_free(sk); + return NULL; + } + obj->type = CERT_POLICY_OID; + obj->grp = oidCertExtType; + obj->obj = (byte*)(x509->certPolicies[i]); + obj->objSz = MAX_CERTPOL_SZ; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + } + else { + WOLFSSL_MSG("No Cert Policy set"); + } + #elif defined(WOLFSSL_SEP) + if (x509->certPolicySet) { + if (c != NULL) { + *c = x509->certPolicyCrit; + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->type = CERT_POLICY_OID; + obj->grp = oidCertExtType; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + } + else { + WOLFSSL_MSG("No Cert Policy set"); + } + #else + WOLFSSL_MSG("wolfSSL not built with WOLFSSL_SEP or WOLFSSL_CERT_EXT"); + #endif + break; + } + case KEY_USAGE_OID: + { + WOLFSSL_ASN1_BIT_STRING* bit_str = NULL; + if (x509->keyUsageSet) { + if (c != NULL) { + *c = x509->keyUsageCrit; + } + + bit_str = wolfSSL_ASN1_BIT_STRING_new(); + if (bit_str == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_BIT_STRING struct"); + return NULL; + } + + bit_str->type = KEY_USAGE_OID; + bit_str->flags = 0; + bit_str->length = sizeof(word16); + bit_str->data = (byte*)XMALLOC(bit_str->length, NULL, DYNAMIC_TYPE_OPENSSL); + if (bit_str->data == NULL) { + wolfSSL_ASN1_BIT_STRING_free(bit_str); + return NULL; + } + XMEMCPY(bit_str->data, &x509->keyUsage, bit_str->length); + } + else { + WOLFSSL_MSG("No Key Usage set"); + } + /* don't add stack of and return bit string directly */ + return bit_str; + } + case INHIBIT_ANY_OID: + WOLFSSL_MSG("INHIBIT ANY extension not supported"); + break; + + case EXT_KEY_USAGE_OID: + if (x509->extKeyUsageSrc != NULL) { + if (c != NULL) { + if (x509->extKeyUsageCount > 1) { + *c = -2; + } + else { + *c = x509->extKeyUsageCrit; + } + } + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->type = EXT_KEY_USAGE_OID; + obj->grp = oidCertExtType; + obj->obj = x509->extKeyUsageSrc; + obj->objSz = x509->extKeyUsageSz; + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA; + } + else { + WOLFSSL_MSG("No Extended Key Usage set"); + } + break; + + case NAME_CONS_OID: + WOLFSSL_MSG("Name Constraint OID extension not supported"); + break; + + case PRIV_KEY_USAGE_PERIOD_OID: + WOLFSSL_MSG("Private Key Usage Period extension not supported"); + break; + + case SUBJECT_INFO_ACCESS: + WOLFSSL_MSG("Subject Info Access extension not supported"); + break; + + case POLICY_MAP_OID: + WOLFSSL_MSG("Policy Map extension not supported"); + break; + + case POLICY_CONST_OID: + WOLFSSL_MSG("Policy Constraint extension not supported"); + break; + + case ISSUE_ALT_NAMES_OID: + WOLFSSL_MSG("Issue Alt Names extension not supported"); + break; + + case TLS_FEATURE_OID: + WOLFSSL_MSG("TLS Feature extension not supported"); + break; + + default: + WOLFSSL_MSG("Unsupported/Unknown extension OID"); + } + + /* make sure stack of is allocated */ + if ((obj || gn) && sk == NULL) { + sk = wolfSSL_sk_new_asn1_obj(); + if (sk == NULL) { + goto err; + } + } + if (obj && wolfSSL_sk_ASN1_OBJECT_push(sk, obj) == WOLFSSL_SUCCESS) { + /* obj pushed successfully on stack */ + } + else if (gn && wolfSSL_sk_GENERAL_NAME_push(sk, gn) == WOLFSSL_SUCCESS) { + /* gn pushed successfully on stack */ + } + else { + /* Nothing to push or push failed */ + WOLFSSL_MSG("Error pushing ASN1_OBJECT or GENERAL_NAME object onto stack " + "or nothing to push."); + goto err; + } + ret = sk; + + (void)idx; + + return ret; + +err: + if (obj) { + wolfSSL_ASN1_OBJECT_free(obj); + } + if (gn) { + wolfSSL_GENERAL_NAME_free(gn); + } + if (sk) { + wolfSSL_sk_ASN1_OBJECT_free(sk); + } + return NULL; +} + + +int wolfSSL_X509_add_altname(WOLFSSL_X509* x509, const char* name, int type) +{ + DNS_entry* newAltName = NULL; + char* nameCopy = NULL; + word32 nameSz; + + if (x509 == NULL) + return WOLFSSL_FAILURE; + + if (name == NULL) + return WOLFSSL_SUCCESS; + + nameSz = (word32)XSTRLEN(name); + if (nameSz == 0) + return WOLFSSL_SUCCESS; + + newAltName = (DNS_entry*)XMALLOC(sizeof(DNS_entry), + x509->heap, DYNAMIC_TYPE_ALTNAME); + if (newAltName == NULL) + return WOLFSSL_FAILURE; + + nameCopy = (char*)XMALLOC(nameSz + 1, x509->heap, DYNAMIC_TYPE_ALTNAME); + if (nameCopy == NULL) { + XFREE(newAltName, x509->heap, DYNAMIC_TYPE_ALTNAME); + return WOLFSSL_FAILURE; + } + + XMEMCPY(nameCopy, name, nameSz + 1); + + newAltName->next = x509->altNames; + newAltName->type = type; + newAltName->len = nameSz; + newAltName->name = nameCopy; + x509->altNames = newAltName; + + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int loc) +{ + WOLFSSL_STUB("wolfSSL_X509_add_ext"); + (void)x509; + (void)ext; + (void)loc; + return WOLFSSL_FAILURE; +} + +/* currently LHASH is not implemented (and not needed for Apache port) */ +WOLFSSL_X509_EXTENSION* wolfSSL_X509V3_EXT_conf_nid( + WOLF_LHASH_OF(CONF_VALUE)* conf, WOLFSSL_X509V3_CTX* ctx, int nid, + char* value) +{ + WOLFSSL_STUB("wolfSSL_X509V3_EXT_conf_nid"); + + if (conf != NULL) { + WOLFSSL_MSG("Handling LHASH not implemented yet"); + return NULL; + } + + (void)conf; + (void)ctx; + (void)nid; + (void)value; + return NULL; +} + +void wolfSSL_X509V3_set_ctx_nodb(WOLFSSL_X509V3_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_X509V3_set_ctx_nodb"); + (void)ctx; +} +#endif /* !NO_WOLFSSL_STUB */ + +/* Returns pointer to ASN1_OBJECT from an X509_EXTENSION object */ +WOLFSSL_ASN1_OBJECT* wolfSSL_X509_EXTENSION_get_object \ + (WOLFSSL_X509_EXTENSION* ext) +{ + WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_get_object"); + if(ext == NULL) + return NULL; + return ext->obj; +} + +/* Returns pointer to ASN1_STRING in X509_EXTENSION object */ +WOLFSSL_ASN1_STRING* wolfSSL_X509_EXTENSION_get_data(WOLFSSL_X509_EXTENSION* ext) +{ + WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_get_data"); + if (ext == NULL) + return NULL; + return &ext->value; +} + +#if !defined(NO_PWDBASED) +int wolfSSL_X509_digest(const WOLFSSL_X509* x509, const WOLFSSL_EVP_MD* digest, + unsigned char* buf, unsigned int* len) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_X509_digest"); + + if (x509 == NULL || digest == NULL) { + WOLFSSL_MSG("Null argument found"); + return WOLFSSL_FAILURE; + } + + if (x509->derCert == NULL) { + WOLFSSL_MSG("No DER certificate stored in X509"); + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_EVP_Digest(x509->derCert->buffer, x509->derCert->length, buf, + len, digest, NULL); + WOLFSSL_LEAVE("wolfSSL_X509_digest", ret); + return ret; +} +#endif + +int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey) +{ + WOLFSSL_ENTER("wolfSSL_use_PrivateKey"); + if (ssl == NULL || pkey == NULL ) { + return WOLFSSL_FAILURE; + } + + return wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1); +} + + +int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl, const unsigned char* der, + long derSz) +{ + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_ASN1"); + if (ssl == NULL || der == NULL ) { + return WOLFSSL_FAILURE; + } + + (void)pri; /* type of private key */ + return wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, WOLFSSL_FILETYPE_ASN1); +} +/****************************************************************************** +* wolfSSL_CTX_use_PrivateKey_ASN1 - loads a private key buffer into the SSL ctx +* +* RETURNS: +* returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE +*/ + +int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx, + unsigned char* der, long derSz) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_ASN1"); + if (ctx == NULL || der == NULL ) { + return WOLFSSL_FAILURE; + } + + (void)pri; /* type of private key */ + return wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1); +} + + +#ifndef NO_RSA +int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz) +{ + WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1"); + if (ssl == NULL || der == NULL ) { + return WOLFSSL_FAILURE; + } + + return wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, WOLFSSL_FILETYPE_ASN1); +} +#endif + +int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + long idx; + + WOLFSSL_ENTER("wolfSSL_use_certificate"); + if (x509 != NULL && ssl != NULL && x509->derCert != NULL) { + if (ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length, + WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0, + GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + } + + (void)idx; + return WOLFSSL_FAILURE; +} + +#endif /* NO_CERTS */ + +#endif /* OPENSSL_EXTRA */ + +#ifndef NO_CERTS +int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der, + int derSz) +{ + long idx; + + WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1"); + if (der != NULL && ssl != NULL) { + if (ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, + ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + } + + (void)idx; + return WOLFSSL_FAILURE; +} + +#ifndef NO_FILESYSTEM + +WOLFSSL_ABI +int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format) +{ + WOLFSSL_ENTER("wolfSSL_use_certificate_file"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, + ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +WOLFSSL_ABI +int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format) +{ + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + if (ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, + ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + + +WOLFSSL_ABI +int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file) +{ + /* process up to MAX_CHAIN_DEPTH plus subject cert */ + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + if (ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, + ssl, 1, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + +int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file, + int format) +{ + /* process up to MAX_CHAIN_DEPTH plus subject cert */ + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, + NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + +#endif /* !NO_FILESYSTEM */ +#endif /* !NO_CERTS */ + +#ifdef HAVE_ECC + +/* Set Temp CTX EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */ +int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + if (sz == 0) { + /* applies only to ECDSA */ + if (ctx->privateKeyType != ecc_dsa_sa_algo) + return WOLFSSL_SUCCESS; + + if (ctx->privateKeySz == 0) { + WOLFSSL_MSG("Must set private key/cert first"); + return BAD_FUNC_ARG; + } + + sz = (word16)ctx->privateKeySz; + } + + /* check size */ + if (sz < ECC_MINSIZE || sz > ECC_MAXSIZE) + return BAD_FUNC_ARG; + + ctx->eccTempKeySz = sz; + + return WOLFSSL_SUCCESS; +} + + +/* Set Temp SSL EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */ +int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) +{ + if (ssl == NULL || sz < ECC_MINSIZE || sz > ECC_MAXSIZE) + return BAD_FUNC_ARG; + + ssl->eccTempKeySz = sz; + + return WOLFSSL_SUCCESS; +} + +#endif /* HAVE_ECC */ + + +#ifdef OPENSSL_EXTRA + +#ifndef NO_FILESYSTEM +int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file, + int format) +{ + WOLFSSL_ENTER("SSL_CTX_use_RSAPrivateKey_file"); + + return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format); +} + + +int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format) +{ + WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file"); + + return wolfSSL_use_PrivateKey_file(ssl, file, format); +} +#endif /* NO_FILESYSTEM */ + + +/* Copies the master secret over to out buffer. If outSz is 0 returns the size + * of master secret. + * + * ses : a session from completed TLS/SSL handshake + * out : buffer to hold copy of master secret + * outSz : size of out buffer + * returns : number of bytes copied into out buffer on success + * less then or equal to 0 is considered a failure case + */ +int wolfSSL_SESSION_get_master_key(const WOLFSSL_SESSION* ses, + unsigned char* out, int outSz) +{ + int size; + + if (outSz == 0) { + return SECRET_LEN; + } + + if (ses == NULL || out == NULL || outSz < 0) { + return 0; + } + + if (outSz > SECRET_LEN) { + size = SECRET_LEN; + } + else { + size = outSz; + } + + XMEMCPY(out, ses->masterSecret, size); + return size; +} + + +int wolfSSL_SESSION_get_master_key_length(const WOLFSSL_SESSION* ses) +{ + (void)ses; + return SECRET_LEN; +} + +#endif /* OPENSSL_EXTRA */ + +#ifndef NO_FILESYSTEM +#ifdef HAVE_NTRU + +int wolfSSL_CTX_use_NTRUPrivateKey_file(WOLFSSL_CTX* ctx, const char* file) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_NTRUPrivateKey_file"); + + if (ctx == NULL) + return WOLFSSL_FAILURE; + + if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_RAW, PRIVATEKEY_TYPE, NULL, 0, + NULL, GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { + ctx->haveNTRU = 1; + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + +#endif /* HAVE_NTRU */ + + +#endif /* NO_FILESYSTEM */ + + +void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, VerifyCallback vc) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); + if (ctx == NULL) + return; + + if (mode & WOLFSSL_VERIFY_PEER) { + ctx->verifyPeer = 1; + ctx->verifyNone = 0; /* in case previously set */ + } + + if (mode == WOLFSSL_VERIFY_NONE) { + ctx->verifyNone = 1; + ctx->verifyPeer = 0; /* in case previously set */ + } + + if (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) { + ctx->failNoCert = 1; + } + + if (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) { + ctx->failNoCert = 0; /* fail on all is set to fail on PSK */ + ctx->failNoCertxPSK = 1; + } + + ctx->verifyCallback = vc; +} + +#ifdef OPENSSL_ALL +void wolfSSL_CTX_set_cert_verify_callback(WOLFSSL_CTX* ctx, + CertVerifyCallback cb, void* arg) +{ + WOLFSSL_ENTER("SSL_CTX_set_cert_verify_callback"); + if (ctx == NULL) + return; + + ctx->verifyCertCb = cb; + ctx->verifyCertCbArg = arg; +} +#endif + + +void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback vc) +{ + WOLFSSL_ENTER("wolfSSL_set_verify"); + if (ssl == NULL) + return; + + if (mode & WOLFSSL_VERIFY_PEER) { + ssl->options.verifyPeer = 1; + ssl->options.verifyNone = 0; /* in case previously set */ + } + + if (mode == WOLFSSL_VERIFY_NONE) { + ssl->options.verifyNone = 1; + ssl->options.verifyPeer = 0; /* in case previously set */ + } + + if (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) + ssl->options.failNoCert = 1; + + if (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) { + ssl->options.failNoCert = 0; /* fail on all is set to fail on PSK */ + ssl->options.failNoCertxPSK = 1; + } + + ssl->verifyCallback = vc; +} + +void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) +{ + WOLFSSL_ENTER("wolfSSL_set_verify_result"); + + if (ssl == NULL) + return; + +#ifdef OPENSSL_ALL + ssl->verifyCallbackResult = v; +#else + (void)v; + WOLFSSL_STUB("wolfSSL_set_verify_result"); +#endif +} + +/* store user ctx for verify callback */ +void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); + if (ssl) + ssl->verifyCbCtx = ctx; +} + + +/* store context CA Cache addition callback */ +void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) +{ + if (ctx && ctx->cm) + ctx->cm->caCacheCallback = cb; +} + + +#if defined(PERSIST_CERT_CACHE) + +#if !defined(NO_FILESYSTEM) + +/* Persist cert cache to file */ +int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +{ + WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); + + if (ctx == NULL || fname == NULL) + return BAD_FUNC_ARG; + + return CM_SaveCertCache(ctx->cm, fname); +} + + +/* Persist cert cache from file */ +int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +{ + WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); + + if (ctx == NULL || fname == NULL) + return BAD_FUNC_ARG; + + return CM_RestoreCertCache(ctx->cm, fname); +} + +#endif /* NO_FILESYSTEM */ + +/* Persist cert cache to memory */ +int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, + int sz, int* used) +{ + WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); + + if (ctx == NULL || mem == NULL || used == NULL || sz <= 0) + return BAD_FUNC_ARG; + + return CM_MemSaveCertCache(ctx->cm, mem, sz, used); +} + + +/* Restore cert cache from memory */ +int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) +{ + WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache"); + + if (ctx == NULL || mem == NULL || sz <= 0) + return BAD_FUNC_ARG; + + return CM_MemRestoreCertCache(ctx->cm, mem, sz); +} + + +/* get how big the the cert cache save buffer needs to be */ +int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + return CM_GetCertCacheMemSize(ctx->cm); +} + +#endif /* PERSIST_CERT_CACHE */ +#endif /* !NO_CERTS */ + + +#ifndef NO_SESSION_CACHE + +WOLFSSL_ABI +WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_get_session"); + if (ssl) + return GetSession(ssl, 0, 1); + + return NULL; +} + + +WOLFSSL_ABI +int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("SSL_set_session"); + if (session) + return SetSession(ssl, session); + + return WOLFSSL_FAILURE; +} + + +#ifndef NO_CLIENT_CACHE + +/* Associate client session with serverID, find existing or store for saving + if newSession flag on, don't reuse existing session + WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession) +{ + WOLFSSL_SESSION* session = NULL; + + WOLFSSL_ENTER("wolfSSL_SetServerID"); + + if (ssl == NULL || id == NULL || len <= 0) + return BAD_FUNC_ARG; + + if (newSession == 0) { + session = GetSessionClient(ssl, id, len); + if (session) { + if (SetSession(ssl, session) != WOLFSSL_SUCCESS) { + #ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(session); + #endif + WOLFSSL_MSG("SetSession failed"); + session = NULL; + } + } + } + + if (session == NULL) { + WOLFSSL_MSG("Valid ServerID not cached already"); + + ssl->session.idLen = (word16)min(SERVER_ID_LEN, (word32)len); + XMEMCPY(ssl->session.serverID, id, ssl->session.idLen); + } + #ifdef HAVE_EXT_CACHE + else + wolfSSL_SESSION_free(session); + #endif + + return WOLFSSL_SUCCESS; +} + +#endif /* NO_CLIENT_CACHE */ + +#if defined(PERSIST_SESSION_CACHE) + +/* for persistence, if changes to layout need to increment and modify + save_session_cache() and restore_session_cache and memory versions too */ +#define WOLFSSL_CACHE_VERSION 2 + +/* Session Cache Header information */ +typedef struct { + int version; /* cache layout version id */ + int rows; /* session rows */ + int columns; /* session columns */ + int sessionSz; /* sizeof WOLFSSL_SESSION */ +} cache_header_t; + +/* current persistence layout is: + + 1) cache_header_t + 2) SessionCache + 3) ClientCache + + update WOLFSSL_CACHE_VERSION if change layout for the following + PERSISTENT_SESSION_CACHE functions +*/ + + +/* get how big the the session cache save buffer needs to be */ +int wolfSSL_get_session_cache_memsize(void) +{ + int sz = (int)(sizeof(SessionCache) + sizeof(cache_header_t)); + + #ifndef NO_CLIENT_CACHE + sz += (int)(sizeof(ClientCache)); + #endif + + return sz; +} + + +/* Persist session cache to memory */ +int wolfSSL_memsave_session_cache(void* mem, int sz) +{ + int i; + cache_header_t cache_header; + SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); +#ifndef NO_CLIENT_CACHE + ClientRow* clRow; +#endif + + WOLFSSL_ENTER("wolfSSL_memsave_session_cache"); + + if (sz < wolfSSL_get_session_cache_memsize()) { + WOLFSSL_MSG("Memory buffer too small"); + return BUFFER_E; + } + + cache_header.version = WOLFSSL_CACHE_VERSION; + cache_header.rows = SESSION_ROWS; + cache_header.columns = SESSIONS_PER_ROW; + cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); + XMEMCPY(mem, &cache_header, sizeof(cache_header)); + + if (wc_LockMutex(&session_mutex) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + return BAD_MUTEX_E; + } + + for (i = 0; i < cache_header.rows; ++i) + XMEMCPY(row++, SessionCache + i, sizeof(SessionRow)); + +#ifndef NO_CLIENT_CACHE + clRow = (ClientRow*)row; + for (i = 0; i < cache_header.rows; ++i) + XMEMCPY(clRow++, ClientCache + i, sizeof(ClientRow)); +#endif + + wc_UnLockMutex(&session_mutex); + + WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", WOLFSSL_SUCCESS); + + return WOLFSSL_SUCCESS; +} + + +/* Restore the persistent session cache from memory */ +int wolfSSL_memrestore_session_cache(const void* mem, int sz) +{ + int i; + cache_header_t cache_header; + SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); +#ifndef NO_CLIENT_CACHE + ClientRow* clRow; +#endif + + WOLFSSL_ENTER("wolfSSL_memrestore_session_cache"); + + if (sz < wolfSSL_get_session_cache_memsize()) { + WOLFSSL_MSG("Memory buffer too small"); + return BUFFER_E; + } + + XMEMCPY(&cache_header, mem, sizeof(cache_header)); + if (cache_header.version != WOLFSSL_CACHE_VERSION || + cache_header.rows != SESSION_ROWS || + cache_header.columns != SESSIONS_PER_ROW || + cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { + + WOLFSSL_MSG("Session cache header match failed"); + return CACHE_MATCH_ERROR; + } + + if (wc_LockMutex(&session_mutex) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + return BAD_MUTEX_E; + } + + for (i = 0; i < cache_header.rows; ++i) + XMEMCPY(SessionCache + i, row++, sizeof(SessionRow)); + +#ifndef NO_CLIENT_CACHE + clRow = (ClientRow*)row; + for (i = 0; i < cache_header.rows; ++i) + XMEMCPY(ClientCache + i, clRow++, sizeof(ClientRow)); +#endif + + wc_UnLockMutex(&session_mutex); + + WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", WOLFSSL_SUCCESS); + + return WOLFSSL_SUCCESS; +} + +#if !defined(NO_FILESYSTEM) + +/* Persist session cache to file */ +/* doesn't use memsave because of additional memory use */ +int wolfSSL_save_session_cache(const char *fname) +{ + XFILE file; + int ret; + int rc = WOLFSSL_SUCCESS; + int i; + cache_header_t cache_header; + + WOLFSSL_ENTER("wolfSSL_save_session_cache"); + + file = XFOPEN(fname, "w+b"); + if (file == XBADFILE) { + WOLFSSL_MSG("Couldn't open session cache save file"); + return WOLFSSL_BAD_FILE; + } + cache_header.version = WOLFSSL_CACHE_VERSION; + cache_header.rows = SESSION_ROWS; + cache_header.columns = SESSIONS_PER_ROW; + cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); + + /* cache header */ + ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file); + if (ret != 1) { + WOLFSSL_MSG("Session cache header file write failed"); + XFCLOSE(file); + return FWRITE_ERROR; + } + + if (wc_LockMutex(&session_mutex) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + + /* session cache */ + for (i = 0; i < cache_header.rows; ++i) { + ret = (int)XFWRITE(SessionCache + i, sizeof(SessionRow), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Session cache member file write failed"); + rc = FWRITE_ERROR; + break; + } + } + +#ifndef NO_CLIENT_CACHE + /* client cache */ + for (i = 0; i < cache_header.rows; ++i) { + ret = (int)XFWRITE(ClientCache + i, sizeof(ClientRow), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Client cache member file write failed"); + rc = FWRITE_ERROR; + break; + } + } +#endif /* NO_CLIENT_CACHE */ + + wc_UnLockMutex(&session_mutex); + + XFCLOSE(file); + WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc); + + return rc; +} + + +/* Restore the persistent session cache from file */ +/* doesn't use memstore because of additional memory use */ +int wolfSSL_restore_session_cache(const char *fname) +{ + XFILE file; + int rc = WOLFSSL_SUCCESS; + int ret; + int i; + cache_header_t cache_header; + + WOLFSSL_ENTER("wolfSSL_restore_session_cache"); + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) { + WOLFSSL_MSG("Couldn't open session cache save file"); + return WOLFSSL_BAD_FILE; + } + /* cache header */ + ret = (int)XFREAD(&cache_header, sizeof cache_header, 1, file); + if (ret != 1) { + WOLFSSL_MSG("Session cache header file read failed"); + XFCLOSE(file); + return FREAD_ERROR; + } + if (cache_header.version != WOLFSSL_CACHE_VERSION || + cache_header.rows != SESSION_ROWS || + cache_header.columns != SESSIONS_PER_ROW || + cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { + + WOLFSSL_MSG("Session cache header match failed"); + XFCLOSE(file); + return CACHE_MATCH_ERROR; + } + + if (wc_LockMutex(&session_mutex) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + + /* session cache */ + for (i = 0; i < cache_header.rows; ++i) { + ret = (int)XFREAD(SessionCache + i, sizeof(SessionRow), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Session cache member file read failed"); + XMEMSET(SessionCache, 0, sizeof SessionCache); + rc = FREAD_ERROR; + break; + } + } + +#ifndef NO_CLIENT_CACHE + /* client cache */ + for (i = 0; i < cache_header.rows; ++i) { + ret = (int)XFREAD(ClientCache + i, sizeof(ClientRow), 1, file); + if (ret != 1) { + WOLFSSL_MSG("Client cache member file read failed"); + XMEMSET(ClientCache, 0, sizeof ClientCache); + rc = FREAD_ERROR; + break; + } + } + +#endif /* NO_CLIENT_CACHE */ + + wc_UnLockMutex(&session_mutex); + + XFCLOSE(file); + WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc); + + return rc; +} + +#endif /* !NO_FILESYSTEM */ +#endif /* PERSIST_SESSION_CACHE */ +#endif /* NO_SESSION_CACHE */ + + +void wolfSSL_load_error_strings(void) /* compatibility only */ +{} + + +int wolfSSL_library_init(void) +{ + WOLFSSL_ENTER("SSL_library_init"); + if (wolfSSL_Init() == WOLFSSL_SUCCESS) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FATAL_ERROR; +} + + +#ifdef HAVE_SECRET_CALLBACK + +int wolfSSL_set_session_secret_cb(WOLFSSL* ssl, SessionSecretCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_set_session_secret_cb"); + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + ssl->sessionSecretCb = cb; + ssl->sessionSecretCtx = ctx; + /* If using a pre-set key, assume session resumption. */ + ssl->session.sessionIDSz = 0; + ssl->options.resuming = 1; + + return WOLFSSL_SUCCESS; +} + +#endif + + +#ifndef NO_SESSION_CACHE + +/* on by default if built in but allow user to turn off */ +WOLFSSL_ABI +long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode) +{ + WOLFSSL_ENTER("SSL_CTX_set_session_cache_mode"); + if (mode == WOLFSSL_SESS_CACHE_OFF) + ctx->sessionCacheOff = 1; + + if ((mode & WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR) != 0) + ctx->sessionCacheFlushOff = 1; + +#ifdef HAVE_EXT_CACHE + if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE) != 0) + ctx->internalCacheOff = 1; +#endif + + return WOLFSSL_SUCCESS; +} + +#endif /* NO_SESSION_CACHE */ + + +#if !defined(NO_CERTS) +#if defined(PERSIST_CERT_CACHE) + + +#define WOLFSSL_CACHE_CERT_VERSION 1 + +typedef struct { + int version; /* cache cert layout version id */ + int rows; /* hash table rows, CA_TABLE_SIZE */ + int columns[CA_TABLE_SIZE]; /* columns per row on list */ + int signerSz; /* sizeof Signer object */ +} CertCacheHeader; + +/* current cert persistence layout is: + + 1) CertCacheHeader + 2) caTable + + update WOLFSSL_CERT_CACHE_VERSION if change layout for the following + PERSIST_CERT_CACHE functions +*/ + + +/* Return memory needed to persist this signer, have lock */ +static WC_INLINE int GetSignerMemory(Signer* signer) +{ + int sz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) + + sizeof(signer->nameLen) + sizeof(signer->subjectNameHash); + +#if !defined(NO_SKID) + sz += (int)sizeof(signer->subjectKeyIdHash); +#endif + + /* add dynamic bytes needed */ + sz += signer->pubKeySize; + sz += signer->nameLen; + + return sz; +} + + +/* Return memory needed to persist this row, have lock */ +static WC_INLINE int GetCertCacheRowMemory(Signer* row) +{ + int sz = 0; + + while (row) { + sz += GetSignerMemory(row); + row = row->next; + } + + return sz; +} + + +/* get the size of persist cert cache, have lock */ +static WC_INLINE int GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm) +{ + int sz; + int i; + + sz = sizeof(CertCacheHeader); + + for (i = 0; i < CA_TABLE_SIZE; i++) + sz += GetCertCacheRowMemory(cm->caTable[i]); + + return sz; +} + + +/* Store cert cache header columns with number of items per list, have lock */ +static WC_INLINE void SetCertHeaderColumns(WOLFSSL_CERT_MANAGER* cm, int* columns) +{ + int i; + Signer* row; + + for (i = 0; i < CA_TABLE_SIZE; i++) { + int count = 0; + row = cm->caTable[i]; + + while (row) { + ++count; + row = row->next; + } + columns[i] = count; + } +} + + +/* Restore whole cert row from memory, have lock, return bytes consumed, + < 0 on error, have lock */ +static WC_INLINE int RestoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, + int row, int listSz, const byte* end) +{ + int idx = 0; + + if (listSz < 0) { + WOLFSSL_MSG("Row header corrupted, negative value"); + return PARSE_ERROR; + } + + while (listSz) { + Signer* signer; + byte* publicKey; + byte* start = current + idx; /* for end checks on this signer */ + int minSz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) + + sizeof(signer->nameLen) + sizeof(signer->subjectNameHash); + #ifndef NO_SKID + minSz += (int)sizeof(signer->subjectKeyIdHash); + #endif + + if (start + minSz > end) { + WOLFSSL_MSG("Would overread restore buffer"); + return BUFFER_E; + } + signer = MakeSigner(cm->heap); + if (signer == NULL) + return MEMORY_E; + + /* pubKeySize */ + XMEMCPY(&signer->pubKeySize, current + idx, sizeof(signer->pubKeySize)); + idx += (int)sizeof(signer->pubKeySize); + + /* keyOID */ + XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID)); + idx += (int)sizeof(signer->keyOID); + + /* pulicKey */ + if (start + minSz + signer->pubKeySize > end) { + WOLFSSL_MSG("Would overread restore buffer"); + FreeSigner(signer, cm->heap); + return BUFFER_E; + } + publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap, + DYNAMIC_TYPE_KEY); + if (publicKey == NULL) { + FreeSigner(signer, cm->heap); + return MEMORY_E; + } + + XMEMCPY(publicKey, current + idx, signer->pubKeySize); + signer->publicKey = publicKey; + idx += signer->pubKeySize; + + /* nameLen */ + XMEMCPY(&signer->nameLen, current + idx, sizeof(signer->nameLen)); + idx += (int)sizeof(signer->nameLen); + + /* name */ + if (start + minSz + signer->pubKeySize + signer->nameLen > end) { + WOLFSSL_MSG("Would overread restore buffer"); + FreeSigner(signer, cm->heap); + return BUFFER_E; + } + signer->name = (char*)XMALLOC(signer->nameLen, cm->heap, + DYNAMIC_TYPE_SUBJECT_CN); + if (signer->name == NULL) { + FreeSigner(signer, cm->heap); + return MEMORY_E; + } + + XMEMCPY(signer->name, current + idx, signer->nameLen); + idx += signer->nameLen; + + /* subjectNameHash */ + XMEMCPY(signer->subjectNameHash, current + idx, SIGNER_DIGEST_SIZE); + idx += SIGNER_DIGEST_SIZE; + + #ifndef NO_SKID + /* subjectKeyIdHash */ + XMEMCPY(signer->subjectKeyIdHash, current + idx,SIGNER_DIGEST_SIZE); + idx += SIGNER_DIGEST_SIZE; + #endif + + signer->next = cm->caTable[row]; + cm->caTable[row] = signer; + + --listSz; + } + + return idx; +} + + +/* Store whole cert row into memory, have lock, return bytes added */ +static WC_INLINE int StoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, int row) +{ + int added = 0; + Signer* list = cm->caTable[row]; + + while (list) { + XMEMCPY(current + added, &list->pubKeySize, sizeof(list->pubKeySize)); + added += (int)sizeof(list->pubKeySize); + + XMEMCPY(current + added, &list->keyOID, sizeof(list->keyOID)); + added += (int)sizeof(list->keyOID); + + XMEMCPY(current + added, list->publicKey, list->pubKeySize); + added += list->pubKeySize; + + XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen)); + added += (int)sizeof(list->nameLen); + + XMEMCPY(current + added, list->name, list->nameLen); + added += list->nameLen; + + XMEMCPY(current + added, list->subjectNameHash, SIGNER_DIGEST_SIZE); + added += SIGNER_DIGEST_SIZE; + + #ifndef NO_SKID + XMEMCPY(current + added, list->subjectKeyIdHash,SIGNER_DIGEST_SIZE); + added += SIGNER_DIGEST_SIZE; + #endif + + list = list->next; + } + + return added; +} + + +/* Persist cert cache to memory, have lock */ +static WC_INLINE int DoMemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, + void* mem, int sz) +{ + int realSz; + int ret = WOLFSSL_SUCCESS; + int i; + + WOLFSSL_ENTER("DoMemSaveCertCache"); + + realSz = GetCertCacheMemSize(cm); + if (realSz > sz) { + WOLFSSL_MSG("Mem output buffer too small"); + ret = BUFFER_E; + } + else { + byte* current; + CertCacheHeader hdr; + + hdr.version = WOLFSSL_CACHE_CERT_VERSION; + hdr.rows = CA_TABLE_SIZE; + SetCertHeaderColumns(cm, hdr.columns); + hdr.signerSz = (int)sizeof(Signer); + + XMEMCPY(mem, &hdr, sizeof(CertCacheHeader)); + current = (byte*)mem + sizeof(CertCacheHeader); + + for (i = 0; i < CA_TABLE_SIZE; ++i) + current += StoreCertRow(cm, current, i); + } + + return ret; +} + + +#if !defined(NO_FILESYSTEM) + +/* Persist cert cache to file */ +int CM_SaveCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname) +{ + XFILE file; + int rc = WOLFSSL_SUCCESS; + int memSz; + byte* mem; + + WOLFSSL_ENTER("CM_SaveCertCache"); + + file = XFOPEN(fname, "w+b"); + if (file == XBADFILE) { + WOLFSSL_MSG("Couldn't open cert cache save file"); + return WOLFSSL_BAD_FILE; + } + + if (wc_LockMutex(&cm->caLock) != 0) { + WOLFSSL_MSG("wc_LockMutex on caLock failed"); + XFCLOSE(file); + return BAD_MUTEX_E; + } + + memSz = GetCertCacheMemSize(cm); + mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + WOLFSSL_MSG("Alloc for tmp buffer failed"); + rc = MEMORY_E; + } else { + rc = DoMemSaveCertCache(cm, mem, memSz); + if (rc == WOLFSSL_SUCCESS) { + int ret = (int)XFWRITE(mem, memSz, 1, file); + if (ret != 1) { + WOLFSSL_MSG("Cert cache file write failed"); + rc = FWRITE_ERROR; + } + } + XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + wc_UnLockMutex(&cm->caLock); + XFCLOSE(file); + + return rc; +} + + +/* Restore cert cache from file */ +int CM_RestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname) +{ + XFILE file; + int rc = WOLFSSL_SUCCESS; + int ret; + int memSz; + byte* mem; + + WOLFSSL_ENTER("CM_RestoreCertCache"); + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) { + WOLFSSL_MSG("Couldn't open cert cache save file"); + return WOLFSSL_BAD_FILE; + } + + if(XFSEEK(file, 0, XSEEK_END) != 0) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + memSz = (int)XFTELL(file); + XREWIND(file); + + if (memSz > MAX_WOLFSSL_FILE_SIZE || memSz <= 0) { + WOLFSSL_MSG("CM_RestoreCertCache file size error"); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + + mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + WOLFSSL_MSG("Alloc for tmp buffer failed"); + XFCLOSE(file); + return MEMORY_E; + } + + ret = (int)XFREAD(mem, memSz, 1, file); + if (ret != 1) { + WOLFSSL_MSG("Cert file read error"); + rc = FREAD_ERROR; + } else { + rc = CM_MemRestoreCertCache(cm, mem, memSz); + if (rc != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Mem restore cert cache failed"); + } + } + + XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFCLOSE(file); + + return rc; +} + +#endif /* NO_FILESYSTEM */ + + +/* Persist cert cache to memory */ +int CM_MemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz, int* used) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("CM_MemSaveCertCache"); + + if (wc_LockMutex(&cm->caLock) != 0) { + WOLFSSL_MSG("wc_LockMutex on caLock failed"); + return BAD_MUTEX_E; + } + + ret = DoMemSaveCertCache(cm, mem, sz); + if (ret == WOLFSSL_SUCCESS) + *used = GetCertCacheMemSize(cm); + + wc_UnLockMutex(&cm->caLock); + + return ret; +} + + +/* Restore cert cache from memory */ +int CM_MemRestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const void* mem, int sz) +{ + int ret = WOLFSSL_SUCCESS; + int i; + CertCacheHeader* hdr = (CertCacheHeader*)mem; + byte* current = (byte*)mem + sizeof(CertCacheHeader); + byte* end = (byte*)mem + sz; /* don't go over */ + + WOLFSSL_ENTER("CM_MemRestoreCertCache"); + + if (current > end) { + WOLFSSL_MSG("Cert Cache Memory buffer too small"); + return BUFFER_E; + } + + if (hdr->version != WOLFSSL_CACHE_CERT_VERSION || + hdr->rows != CA_TABLE_SIZE || + hdr->signerSz != (int)sizeof(Signer)) { + + WOLFSSL_MSG("Cert Cache Memory header mismatch"); + return CACHE_MATCH_ERROR; + } + + if (wc_LockMutex(&cm->caLock) != 0) { + WOLFSSL_MSG("wc_LockMutex on caLock failed"); + return BAD_MUTEX_E; + } + + FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); + + for (i = 0; i < CA_TABLE_SIZE; ++i) { + int added = RestoreCertRow(cm, current, i, hdr->columns[i], end); + if (added < 0) { + WOLFSSL_MSG("RestoreCertRow error"); + ret = added; + break; + } + current += added; + } + + wc_UnLockMutex(&cm->caLock); + + return ret; +} + + +/* get how big the the cert cache save buffer needs to be */ +int CM_GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm) +{ + int sz; + + WOLFSSL_ENTER("CM_GetCertCacheMemSize"); + + if (wc_LockMutex(&cm->caLock) != 0) { + WOLFSSL_MSG("wc_LockMutex on caLock failed"); + return BAD_MUTEX_E; + } + + sz = GetCertCacheMemSize(cm); + + wc_UnLockMutex(&cm->caLock); + + return sz; +} + +#endif /* PERSIST_CERT_CACHE */ +#endif /* NO_CERTS */ + +#ifdef OPENSSL_EXTRA + + +/* removes all cipher suites from the list that contain "toRemove" + * returns the new list size on success + */ +static int wolfSSL_remove_ciphers(char* list, int sz, const char* toRemove) +{ + int idx = 0; + char* next = (char*)list; + int totalSz = sz; + + if (list == NULL) { + return 0; + } + + do { + char* current = next; + char name[MAX_SUITE_NAME + 1]; + word32 length; + + next = XSTRSTR(next, ":"); + length = min(sizeof(name), !next ? (word32)XSTRLEN(current) /* last */ + : (word32)(next - current)); + + XSTRNCPY(name, current, length); + name[(length == sizeof(name)) ? length - 1 : length] = 0; + + if (XSTRSTR(name, toRemove)) { + XMEMMOVE(list + idx, list + idx + length, totalSz - (idx + length)); + totalSz -= length; + list[totalSz] = '\0'; + next = current; + } + else { + idx += length; + } + } while (next++); /* ++ needed to skip ':' */ + + return totalSz; +} + +/* parse some bulk lists like !eNULL / !aNULL + * + * returns WOLFSSL_SUCCESS on success and sets the cipher suite list + */ +static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, Suites* suites, + const char* list) +{ + int ret = 0; + const int suiteSz = GetCipherNamesSize(); + char* next = (char*)list; + const CipherSuiteInfo* names = GetCipherNames(); + char* localList = NULL; + int sz = 0; + + if (suites == NULL || list == NULL) { + WOLFSSL_MSG("NULL argument"); + return WOLFSSL_FAILURE; + } + + /* does list contain eNULL or aNULL? */ + if (XSTRSTR(list, "aNULL") || XSTRSTR(list, "eNULL")) { + do { + char* current = next; + char name[MAX_SUITE_NAME + 1]; + int i; + word32 length; + + next = XSTRSTR(next, ":"); + length = min(sizeof(name), !next ? (word32)XSTRLEN(current) /*last*/ + : (word32)(next - current)); + + XSTRNCPY(name, current, length); + name[(length == sizeof(name)) ? length - 1 : length] = 0; + + /* check for "not" case */ + if (name[0] == '!' && suiteSz > 0) { + /* populate list with all suites if not already created */ + if (localList == NULL) { + for (i = 0; i < suiteSz; i++) { + sz += (int)XSTRLEN(names[i].name) + 2; + } + localList = (char*)XMALLOC(sz, ctx->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (localList == NULL) { + return WOLFSSL_FAILURE; + } + wolfSSL_get_ciphers(localList, sz); + sz = (int)XSTRLEN(localList); + } + + if (XSTRSTR(name, "eNULL")) { + wolfSSL_remove_ciphers(localList, sz, "-NULL"); + } + } + } + while (next++); /* ++ needed to skip ':' */ + + ret = SetCipherList(ctx, suites, localList); + XFREE(localList, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + return (ret)? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + } + else { + return (SetCipherList(ctx, suites, list)) ? WOLFSSL_SUCCESS : + WOLFSSL_FAILURE; + } +} + +#endif + + +int wolfSSL_CTX_set_cipher_list(WOLFSSL_CTX* ctx, const char* list) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list"); + + if (ctx == NULL) + return WOLFSSL_FAILURE; + + /* alloc/init on demand only */ + if (ctx->suites == NULL) { + ctx->suites = (Suites*)XMALLOC(sizeof(Suites), ctx->heap, + DYNAMIC_TYPE_SUITES); + if (ctx->suites == NULL) { + WOLFSSL_MSG("Memory alloc for Suites failed"); + return WOLFSSL_FAILURE; + } + XMEMSET(ctx->suites, 0, sizeof(Suites)); + } + +#ifdef OPENSSL_EXTRA + return wolfSSL_parse_cipher_list(ctx, ctx->suites, list); +#else + return (SetCipherList(ctx, ctx->suites, list)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +#endif +} + + +int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list) +{ + WOLFSSL_ENTER("wolfSSL_set_cipher_list"); +#ifdef SINGLE_THREADED + if (ssl->ctx->suites == ssl->suites) { + ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, + DYNAMIC_TYPE_SUITES); + if (ssl->suites == NULL) { + WOLFSSL_MSG("Suites Memory error"); + return MEMORY_E; + } + ssl->options.ownSuites = 1; + } +#endif + +#ifdef OPENSSL_EXTRA + return wolfSSL_parse_cipher_list(ssl->ctx, ssl->suites, list); +#else + return (SetCipherList(ssl->ctx, ssl->suites, list)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +#endif +} + + +int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) +{ + int useNb = 0; + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + useNb = ssl->options.dtlsUseNonblock; +#endif + } + else { + WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " + "DEPRECATED for non-DTLS use."); + } + return useNb; +} + + +#ifndef WOLFSSL_LEANPSK + +void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) +{ + (void)nonblock; + + WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); + + if (ssl == NULL) + return; + + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + ssl->options.dtlsUseNonblock = (nonblock != 0); +#endif + } + else { + WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " + "DEPRECATED for non-DTLS use."); + } +} + + +#ifdef WOLFSSL_DTLS + +int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) +{ + int timeout = 0; + if (ssl) + timeout = ssl->dtls_timeout; + + WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout()", timeout); + return timeout; +} + +int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) +{ + if (ssl && timeleft) { + XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); + timeleft->tv_sec = ssl->dtls_timeout; + } + return 0; +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) +{ + WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); + (void)ssl; + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, word32 duration_ms) +{ + WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); + (void)ssl; + (void)duration_ms; +} +#endif + +/* user may need to alter init dtls recv timeout, WOLFSSL_SUCCESS on ok */ +int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) +{ + if (ssl == NULL || timeout < 0) + return BAD_FUNC_ARG; + + if (timeout > ssl->dtls_timeout_max) { + WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout max"); + return BAD_FUNC_ARG; + } + + ssl->dtls_timeout_init = timeout; + ssl->dtls_timeout = timeout; + + return WOLFSSL_SUCCESS; +} + + +/* user may need to alter max dtls recv timeout, WOLFSSL_SUCCESS on ok */ +int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) +{ + if (ssl == NULL || timeout < 0) + return BAD_FUNC_ARG; + + if (timeout < ssl->dtls_timeout_init) { + WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); + return BAD_FUNC_ARG; + } + + ssl->dtls_timeout_max = timeout; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) +{ + int result = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_dtls_got_timeout()"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (!ssl->options.handShakeDone && + (DtlsMsgPoolTimeout(ssl) < 0 || DtlsMsgPoolSend(ssl, 0) < 0)) { + + result = WOLFSSL_FATAL_ERROR; + } + + WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout()", result); + return result; +} + + +/* retransmit all the saves messages, WOLFSSL_SUCCESS on ok */ +int wolfSSL_dtls_retransmit(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_retransmit()"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (!ssl->options.handShakeDone) { + int result = DtlsMsgPoolSend(ssl, 0); + if (result < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + } + + return 0; +} + +#endif /* DTLS */ +#endif /* LEANPSK */ + + +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) + +/* Not an SSL function, return 0 for success, error code otherwise */ +/* Prereq: ssl's RNG needs to be initialized. */ +int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, + const byte* secret, word32 secretSz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); + + if (ssl == NULL) { + WOLFSSL_MSG("need a SSL object"); + return BAD_FUNC_ARG; + } + + if (secret != NULL && secretSz == 0) { + WOLFSSL_MSG("can't have a new secret without a size"); + return BAD_FUNC_ARG; + } + + /* If secretSz is 0, use the default size. */ + if (secretSz == 0) + secretSz = COOKIE_SECRET_SZ; + + if (secretSz != ssl->buffers.dtlsCookieSecret.length) { + byte* newSecret; + + if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { + ForceZero(ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + XFREE(ssl->buffers.dtlsCookieSecret.buffer, + ssl->heap, DYNAMIC_TYPE_NONE); + } + + newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); + if (newSecret == NULL) { + ssl->buffers.dtlsCookieSecret.buffer = NULL; + ssl->buffers.dtlsCookieSecret.length = 0; + WOLFSSL_MSG("couldn't allocate new cookie secret"); + return MEMORY_ERROR; + } + ssl->buffers.dtlsCookieSecret.buffer = newSecret; + ssl->buffers.dtlsCookieSecret.length = secretSz; + } + + /* If the supplied secret is NULL, randomly generate a new secret. */ + if (secret == NULL) { + ret = wc_RNG_GenerateBlock(ssl->rng, + ssl->buffers.dtlsCookieSecret.buffer, secretSz); + } + else + XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); + + WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); + return ret; +} + +#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ + + +/* EITHER SIDE METHODS */ +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) + WOLFSSL_METHOD* wolfSSLv23_method(void) + { + return wolfSSLv23_method_ex(NULL); + } + WOLFSSL_METHOD* wolfSSLv23_method_ex(void* heap) + { + WOLFSSL_METHOD* m = NULL; + WOLFSSL_ENTER("SSLv23_method"); + #if !defined(NO_WOLFSSL_CLIENT) + m = wolfSSLv23_client_method_ex(heap); + #elif !defined(NO_WOLFSSL_SERVER) + m = wolfSSLv23_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + + return m; + } + + #ifdef WOLFSSL_ALLOW_SSLV3 + WOLFSSL_METHOD* wolfSSLv3_method(void) + { + return wolfSSLv3_method_ex(NULL); + } + WOLFSSL_METHOD* wolfSSLv3_method_ex(void* heap) + { + WOLFSSL_METHOD* m = NULL; + WOLFSSL_ENTER("SSLv3_method"); + #if !defined(NO_WOLFSSL_CLIENT) + m = wolfSSLv3_client_method_ex(heap); + #elif !defined(NO_WOLFSSL_SERVER) + m = wolfSSLv3_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + + return m; + } + #endif +#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + +/* client only parts */ +#ifndef NO_WOLFSSL_CLIENT + + #ifdef OPENSSL_EXTRA + WOLFSSL_METHOD* wolfSSLv2_client_method(void) + { + WOLFSSL_STUB("wolfSSLv2_client_method"); + return NULL; + } + #endif + + #ifdef WOLFSSL_ALLOW_SSLV3 + WOLFSSL_METHOD* wolfSSLv3_client_method(void) + { + return wolfSSLv3_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfSSLv3_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("SSLv3_client_method_ex"); + if (method) + InitSSL_Method(method, MakeSSLv3()); + return method; + } + #endif /* WOLFSSL_ALLOW_SSLV3 */ + + + WOLFSSL_METHOD* wolfSSLv23_client_method(void) + { + return wolfSSLv23_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfSSLv23_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("SSLv23_client_method_ex"); + if (method) { + #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) + #if defined(WOLFSSL_TLS13) + InitSSL_Method(method, MakeTLSv1_3()); + #elif !defined(WOLFSSL_NO_TLS12) + InitSSL_Method(method, MakeTLSv1_2()); + #elif !defined(NO_OLD_TLS) + InitSSL_Method(method, MakeTLSv1_1()); + #endif + #else + #ifndef NO_OLD_TLS + InitSSL_Method(method, MakeTLSv1_1()); + #endif + #endif + #if !defined(NO_OLD_TLS) || defined(WOLFSSL_TLS13) + method->downgrade = 1; + #endif + } + return method; + } + + + #if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) || \ + defined(WOLFSSL_ALLOW_SSLV3) + /* If SCTP is not enabled returns the state of the dtls option. + * If SCTP is enabled returns dtls && !sctp. */ + static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl) + { + int result = ssl->options.dtls; + + if (result) { + #ifdef WOLFSSL_SCTP + result = !ssl->options.dtlsSctp; + #endif + } + + return result; + } + #endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */ + + + /* please see note at top of README if you get an error from connect */ + WOLFSSL_ABI + int wolfSSL_connect(WOLFSSL* ssl) + { + #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)) + int neededState; + #endif + + WOLFSSL_ENTER("SSL_connect()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl == NULL) + return BAD_FUNC_ARG; + + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) + if (ssl->options.side == WOLFSSL_NEITHER_END) { + ssl->error = InitSSL_Side(ssl, WOLFSSL_CLIENT_END); + if (ssl->error != WOLFSSL_SUCCESS) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->error = 0; /* expected to be zero here */ + } + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_ST_CONNECT, SSL_SUCCESS); + ssl->cbmode = SSL_CB_WRITE; + } + #endif + #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + + #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) + return wolfSSL_connect_TLSv13(ssl); + #else + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + + if (ssl->options.side != WOLFSSL_CLIENT_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return WOLFSSL_FATAL_ERROR; + } + + #ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + } + #endif + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { + if ( (ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.connectState++; + WOLFSSL_MSG("connect state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("connect state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + switch (ssl->options.connectState) { + + case CONNECT_BEGIN : + /* always send client hello first */ + if ( (ssl->error = SendClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.connectState = CLIENT_HELLO_SENT; + WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + FALL_THROUGH; + + case CLIENT_HELLO_SENT : + neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : + SERVER_HELLODONE_COMPLETE; + #ifdef WOLFSSL_DTLS + /* In DTLS, when resuming, we can go straight to FINISHED, + * or do a cookie exchange and then skip to FINISHED, assume + * we need the cookie exchange first. */ + if (IsDtlsNotSctpMode(ssl)) + neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + #endif + /* get response */ + while (ssl->options.serverState < neededState) { + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + else if (neededState == SERVER_FINISHED_COMPLETE) + if (!ssl->options.resuming) { + if (!IsDtlsNotSctpMode(ssl)) + neededState = SERVER_HELLODONE_COMPLETE; + else + neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + } + } + + ssl->options.connectState = HELLO_AGAIN; + WOLFSSL_MSG("connect state: HELLO_AGAIN"); + FALL_THROUGH; + + case HELLO_AGAIN : + if (ssl->options.certOnly) + return WOLFSSL_SUCCESS; + + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->options.serverState == + SERVER_HELLOVERIFYREQUEST_COMPLETE) { + if (IsDtlsNotSctpMode(ssl)) { + /* re-init hashes, exclude first hello and verify request */ + if ((ssl->error = InitHandshakeHashes(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + if ( (ssl->error = SendClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + #endif + + ssl->options.connectState = HELLO_AGAIN_REPLY; + WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); + FALL_THROUGH; + + case HELLO_AGAIN_REPLY : + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + neededState = ssl->options.resuming ? + SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; + + /* get response */ + while (ssl->options.serverState < neededState) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + if (neededState == SERVER_FINISHED_COMPLETE) { + if (!ssl->options.resuming) + neededState = SERVER_HELLODONE_COMPLETE; + } + } + } + #endif + + ssl->options.connectState = FIRST_REPLY_DONE; + WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); + FALL_THROUGH; + + case FIRST_REPLY_DONE : + #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + if (ssl->options.sendVerify) { + if ( (ssl->error = SendCertificate(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate"); + } + + #endif + ssl->options.connectState = FIRST_REPLY_FIRST; + WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); + FALL_THROUGH; + + case FIRST_REPLY_FIRST : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + if (!ssl->options.resuming) { + if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: client key exchange"); + } + + ssl->options.connectState = FIRST_REPLY_SECOND; + WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); + FALL_THROUGH; + + case FIRST_REPLY_SECOND : + #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) + if (ssl->options.sendVerify) { + if ( (ssl->error = SendCertificateVerify(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate verify"); + } + #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */ + ssl->options.connectState = FIRST_REPLY_THIRD; + WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); + FALL_THROUGH; + + case FIRST_REPLY_THIRD : + if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: change cipher spec"); + ssl->options.connectState = FIRST_REPLY_FOURTH; + WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH"); + FALL_THROUGH; + + case FIRST_REPLY_FOURTH : + if ( (ssl->error = SendFinished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: finished"); + ssl->options.connectState = FINISHED_DONE; + WOLFSSL_MSG("connect state: FINISHED_DONE"); + FALL_THROUGH; + + case FINISHED_DONE : + /* get response */ + while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.connectState = SECOND_REPLY_DONE; + WOLFSSL_MSG("connect state: SECOND_REPLY_DONE"); + FALL_THROUGH; + + case SECOND_REPLY_DONE: +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.dtls) { + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + } +#ifdef WOLFSSL_DTLS + else { + ssl->options.dtlsHsRetain = 1; + } +#endif /* WOLFSSL_DTLS */ + + WOLFSSL_LEAVE("SSL_connect()", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default: + WOLFSSL_MSG("Unknown connect state ERROR"); + return WOLFSSL_FATAL_ERROR; /* unknown connect state */ + } + #endif /* !WOLFSSL_NO_TLS12 */ + } + +#endif /* NO_WOLFSSL_CLIENT */ + + +/* server only parts */ +#ifndef NO_WOLFSSL_SERVER + + #ifdef OPENSSL_EXTRA + WOLFSSL_METHOD* wolfSSLv2_server_method(void) + { + WOLFSSL_STUB("wolfSSLv2_server_method"); + return 0; + } + #endif + + #ifdef WOLFSSL_ALLOW_SSLV3 + WOLFSSL_METHOD* wolfSSLv3_server_method(void) + { + return wolfSSLv3_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfSSLv3_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("SSLv3_server_method_ex"); + if (method) { + InitSSL_Method(method, MakeSSLv3()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } + #endif /* WOLFSSL_ALLOW_SSLV3 */ + + WOLFSSL_METHOD* wolfSSLv23_server_method(void) + { + return wolfSSLv23_server_method_ex(NULL); + } + + WOLFSSL_METHOD* wolfSSLv23_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("SSLv23_server_method_ex"); + if (method) { + #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) + #ifdef WOLFSSL_TLS13 + InitSSL_Method(method, MakeTLSv1_3()); + #elif !defined(WOLFSSL_NO_TLS12) + InitSSL_Method(method, MakeTLSv1_2()); + #elif !defined(NO_OLD_TLS) + InitSSL_Method(method, MakeTLSv1_1()); + #endif + #else + #ifndef NO_OLD_TLS + InitSSL_Method(method, MakeTLSv1_1()); + #else + #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2 + #endif + #endif + #if !defined(NO_OLD_TLS) || defined(WOLFSSL_TLS13) + method->downgrade = 1; + #endif + method->side = WOLFSSL_SERVER_END; + } + return method; + } + + + int wolfSSL_accept(WOLFSSL* ssl) + { +#if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)) + word16 havePSK = 0; + word16 haveAnon = 0; + word16 haveMcast = 0; +#endif + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) + if (ssl->options.side == WOLFSSL_NEITHER_END) { + WOLFSSL_MSG("Setting WOLFSSL_SSL to be server side"); + ssl->error = InitSSL_Side(ssl, WOLFSSL_SERVER_END); + if (ssl->error != WOLFSSL_SUCCESS) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->error = 0; /* expected to be zero here */ + } + #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + +#if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) + return wolfSSL_accept_TLSv13(ssl); +#else + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_accept_TLSv13(ssl); + #endif + WOLFSSL_ENTER("SSL_accept()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + (void)havePSK; + + #ifdef HAVE_ANON + haveAnon = ssl->options.haveAnon; + #endif + (void)haveAnon; + + #ifdef WOLFSSL_MULTICAST + haveMcast = ssl->options.haveMcast; + #endif + (void)haveMcast; + + if (ssl->options.side != WOLFSSL_SERVER_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return WOLFSSL_FATAL_ERROR; + } + + #ifndef NO_CERTS + /* in case used set_accept_state after init */ + /* allow no private key if using PK callbacks and CB is set */ + if (!havePSK && !haveAnon && !haveMcast) { + if (!ssl->buffers.certificate || + !ssl->buffers.certificate->buffer) { + + WOLFSSL_MSG("accept error: server cert required"); + WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY); + return WOLFSSL_FATAL_ERROR; + } + + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + WOLFSSL_MSG("Using PK for server private key"); + } + else + #endif + if (!ssl->buffers.key || !ssl->buffers.key->buffer) { + WOLFSSL_MSG("accept error: server key required"); + WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY); + return WOLFSSL_FATAL_ERROR; + } + } + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + } + #endif + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { + if ( (ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.acceptState++; + WOLFSSL_MSG("accept state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("accept state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + switch (ssl->options.acceptState) { + + case ACCEPT_BEGIN : +#ifdef HAVE_SECURE_RENEGOTIATION + case ACCEPT_BEGIN_RENEG: +#endif + /* get response */ + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } +#ifdef WOLFSSL_TLS13 + ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; + WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + FALL_THROUGH; + + case ACCEPT_CLIENT_HELLO_DONE : + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } +#endif + ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + FALL_THROUGH; + + case ACCEPT_FIRST_REPLY_DONE : + if ( (ssl->error = SendServerHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_SENT; + WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); + FALL_THROUGH; + + case SERVER_HELLO_SENT : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } + #endif + #ifndef NO_CERTS + if (!ssl->options.resuming) + if ( (ssl->error = SendCertificate(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #endif + ssl->options.acceptState = CERT_SENT; + WOLFSSL_MSG("accept state CERT_SENT"); + FALL_THROUGH; + + case CERT_SENT : + #ifndef NO_CERTS + if (!ssl->options.resuming) + if ( (ssl->error = SendCertificateStatus(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #endif + ssl->options.acceptState = CERT_STATUS_SENT; + WOLFSSL_MSG("accept state CERT_STATUS_SENT"); + FALL_THROUGH; + + case CERT_STATUS_SENT : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } + #endif + if (!ssl->options.resuming) + if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = KEY_EXCHANGE_SENT; + WOLFSSL_MSG("accept state KEY_EXCHANGE_SENT"); + FALL_THROUGH; + + case KEY_EXCHANGE_SENT : + #ifndef NO_CERTS + if (!ssl->options.resuming) { + if (ssl->options.verifyPeer) { + if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + #endif + ssl->options.acceptState = CERT_REQ_SENT; + WOLFSSL_MSG("accept state CERT_REQ_SENT"); + FALL_THROUGH; + + case CERT_REQ_SENT : + if (!ssl->options.resuming) + if ( (ssl->error = SendServerHelloDone(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_DONE; + WOLFSSL_MSG("accept state SERVER_HELLO_DONE"); + FALL_THROUGH; + + case SERVER_HELLO_DONE : + if (!ssl->options.resuming) { + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); + FALL_THROUGH; + + case ACCEPT_SECOND_REPLY_DONE : +#ifdef HAVE_SESSION_TICKET + if (ssl->options.createTicket) { + if ( (ssl->error = SendTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + FALL_THROUGH; + + case TICKET_SENT: + if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = CHANGE_CIPHER_SENT; + WOLFSSL_MSG("accept state CHANGE_CIPHER_SENT"); + FALL_THROUGH; + + case CHANGE_CIPHER_SENT : + if ( (ssl->error = SendFinished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_FINISHED_DONE; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); + FALL_THROUGH; + + case ACCEPT_FINISHED_DONE : + if (ssl->options.resuming) + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); + FALL_THROUGH; + + case ACCEPT_THIRD_REPLY_DONE : +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.dtls) { + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + } +#ifdef WOLFSSL_DTLS + else { + ssl->options.dtlsHsRetain = 1; + } +#endif /* WOLFSSL_DTLS */ + +#ifdef WOLFSSL_SESSION_EXPORT + if (ssl->dtls_export) { + if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { + WOLFSSL_MSG("Export DTLS session error"); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + + WOLFSSL_LEAVE("SSL_accept()", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default : + WOLFSSL_MSG("Unknown accept state ERROR"); + return WOLFSSL_FATAL_ERROR; + } +#endif /* !WOLFSSL_NO_TLS12 */ + } + +#endif /* NO_WOLFSSL_SERVER */ + + +#ifndef NO_HANDSHAKE_DONE_CB + +int wolfSSL_SetHsDoneCb(WOLFSSL* ssl, HandShakeDoneCb cb, void* user_ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetHsDoneCb"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->hsDoneCb = cb; + ssl->hsDoneCtx = user_ctx; + + + return WOLFSSL_SUCCESS; +} + +#endif /* NO_HANDSHAKE_DONE_CB */ + +WOLFSSL_ABI +int wolfSSL_Cleanup(void) +{ + int ret = WOLFSSL_SUCCESS; + int release = 0; + + WOLFSSL_ENTER("wolfSSL_Cleanup"); + + if (initRefCount == 0) + return ret; /* possibly no init yet, but not failure either way */ + + if (wc_LockMutex(&count_mutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex count"); + return BAD_MUTEX_E; + } + + release = initRefCount-- == 1; + if (initRefCount < 0) + initRefCount = 0; + + wc_UnLockMutex(&count_mutex); + + if (!release) + return ret; + +#ifdef OPENSSL_EXTRA + if (bn_one) { + wolfSSL_BN_free(bn_one); + bn_one = NULL; + } +#endif + +#ifndef NO_SESSION_CACHE + if (wc_FreeMutex(&session_mutex) != 0) + ret = BAD_MUTEX_E; +#endif + if (wc_FreeMutex(&count_mutex) != 0) + ret = BAD_MUTEX_E; + +#ifdef OPENSSL_EXTRA + wolfSSL_RAND_Cleanup(); +#endif + + if (wolfCrypt_Cleanup() != 0) { + WOLFSSL_MSG("Error with wolfCrypt_Cleanup call"); + ret = WC_CLEANUP_E; + } + + return ret; +} + + +#ifndef NO_SESSION_CACHE + + +/* some session IDs aren't random after all, let's make them random */ +static WC_INLINE word32 HashSession(const byte* sessionID, word32 len, int* error) +{ + byte digest[WC_MAX_DIGEST_SIZE]; + +#ifndef NO_MD5 + *error = wc_Md5Hash(sessionID, len, digest); +#elif !defined(NO_SHA) + *error = wc_ShaHash(sessionID, len, digest); +#elif !defined(NO_SHA256) + *error = wc_Sha256Hash(sessionID, len, digest); +#else + #error "We need a digest to hash the session IDs" +#endif + + return *error == 0 ? MakeWordFromHash(digest) : 0; /* 0 on failure */ +} + + +WOLFSSL_ABI +void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm) +{ + /* static table now, no flushing needed */ + (void)ctx; + (void)tm; +} + + +/* set ssl session timeout in seconds */ +WOLFSSL_ABI +int wolfSSL_set_timeout(WOLFSSL* ssl, unsigned int to) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (to == 0) + to = WOLFSSL_SESSION_TIMEOUT; + ssl->timeout = to; + + return WOLFSSL_SUCCESS; +} + + +/* set ctx session timeout in seconds */ +WOLFSSL_ABI +int wolfSSL_CTX_set_timeout(WOLFSSL_CTX* ctx, unsigned int to) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + if (to == 0) + to = WOLFSSL_SESSION_TIMEOUT; + ctx->timeout = to; + + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_CLIENT_CACHE + +/* Get Session from Client cache based on id/len, return NULL on failure */ +WOLFSSL_SESSION* GetSessionClient(WOLFSSL* ssl, const byte* id, int len) +{ + WOLFSSL_SESSION* ret = NULL; + word32 row; + int idx; + int count; + int error = 0; + + WOLFSSL_ENTER("GetSessionClient"); + + if (ssl->ctx->sessionCacheOff) + return NULL; + + if (ssl->options.side == WOLFSSL_SERVER_END) + return NULL; + + len = min(SERVER_ID_LEN, (word32)len); + +#ifdef HAVE_EXT_CACHE + if (ssl->ctx->get_sess_cb != NULL) { + int copy = 0; + ret = ssl->ctx->get_sess_cb(ssl, (byte*)id, len, ©); + if (ret != NULL) + return ret; + } + + if (ssl->ctx->internalCacheOff) + return NULL; +#endif + + row = HashSession(id, len, &error) % SESSION_ROWS; + if (error != 0) { + WOLFSSL_MSG("Hash session failed"); + return NULL; + } + + if (wc_LockMutex(&session_mutex) != 0) { + WOLFSSL_MSG("Lock session mutex failed"); + return NULL; + } + + /* start from most recently used */ + count = min((word32)ClientCache[row].totalCount, SESSIONS_PER_ROW); + idx = ClientCache[row].nextIdx - 1; + if (idx < 0) + idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ + + for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) { + WOLFSSL_SESSION* current; + ClientSession clSess; + + if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */ + WOLFSSL_MSG("Bad idx"); + break; + } + + clSess = ClientCache[row].Clients[idx]; + + current = &SessionCache[clSess.serverRow].Sessions[clSess.serverIdx]; + if (XMEMCMP(current->serverID, id, len) == 0) { + WOLFSSL_MSG("Found a serverid match for client"); + if (LowResTimer() < (current->bornOn + current->timeout)) { + WOLFSSL_MSG("Session valid"); + ret = current; + break; + } else { + WOLFSSL_MSG("Session timed out"); /* could have more for id */ + } + } else { + WOLFSSL_MSG("ServerID not a match from client table"); + } + } + + wc_UnLockMutex(&session_mutex); + + return ret; +} + +#endif /* NO_CLIENT_CACHE */ + +/* Restore the master secret and session information for certificates. + * + * ssl The SSL/TLS object. + * session The cached session to restore. + * masterSecret The master secret from the cached session. + * restoreSessionCerts Restoring session certificates is required. + */ +static WC_INLINE void RestoreSession(WOLFSSL* ssl, WOLFSSL_SESSION* session, + byte* masterSecret, byte restoreSessionCerts) +{ + (void)ssl; + (void)restoreSessionCerts; + + if (masterSecret) + XMEMCPY(masterSecret, session->masterSecret, SECRET_LEN); +#ifdef SESSION_CERTS + /* If set, we should copy the session certs into the ssl object + * from the session we are returning so we can resume */ + if (restoreSessionCerts) { + ssl->session.chain = session->chain; + ssl->session.version = session->version; + #ifdef NO_RESUME_SUITE_CHECK + ssl->session.cipherSuite0 = session->cipherSuite0; + ssl->session.cipherSuite = session->cipherSuite; + #endif + } +#endif /* SESSION_CERTS */ +#if !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + ssl->session.cipherSuite0 = session->cipherSuite0; + ssl->session.cipherSuite = session->cipherSuite; +#endif +} + +WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret, + byte restoreSessionCerts) +{ + WOLFSSL_SESSION* ret = 0; + const byte* id = NULL; + word32 row; + int idx; + int count; + int error = 0; + + (void) restoreSessionCerts; + + if (ssl->options.sessionCacheOff) + return NULL; + + if (ssl->options.haveSessionId == 0) + return NULL; + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) + return NULL; +#endif + + if (!ssl->options.tls1_3 && ssl->arrays != NULL) + id = ssl->arrays->sessionID; + else + id = ssl->session.sessionID; + +#ifdef HAVE_EXT_CACHE + if (ssl->ctx->get_sess_cb != NULL) { + int copy = 0; + /* Attempt to retrieve the session from the external cache. */ + ret = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, ©); + if (ret != NULL) { + RestoreSession(ssl, ret, masterSecret, restoreSessionCerts); + return ret; + } + } + + if (ssl->ctx->internalCacheOff) + return NULL; +#endif + + row = HashSession(id, ID_LEN, &error) % SESSION_ROWS; + if (error != 0) { + WOLFSSL_MSG("Hash session failed"); + return NULL; + } + + if (wc_LockMutex(&session_mutex) != 0) + return 0; + + /* start from most recently used */ + count = min((word32)SessionCache[row].totalCount, SESSIONS_PER_ROW); + idx = SessionCache[row].nextIdx - 1; + if (idx < 0) + idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ + + for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) { + WOLFSSL_SESSION* current; + + if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */ + WOLFSSL_MSG("Bad idx"); + break; + } + + current = &SessionCache[row].Sessions[idx]; + if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) { + WOLFSSL_MSG("Found a session match"); + if (LowResTimer() < (current->bornOn + current->timeout)) { + WOLFSSL_MSG("Session valid"); + ret = current; + RestoreSession(ssl, ret, masterSecret, restoreSessionCerts); + } else { + WOLFSSL_MSG("Session timed out"); + } + break; /* no more sessionIDs whether valid or not that match */ + } else { + WOLFSSL_MSG("SessionID not a match at this idx"); + } + } + + wc_UnLockMutex(&session_mutex); + + return ret; +} + + +static int GetDeepCopySession(WOLFSSL* ssl, WOLFSSL_SESSION* copyFrom) +{ + WOLFSSL_SESSION* copyInto = &ssl->session; + void* tmpBuff = NULL; + int ticketLen = 0; + int doDynamicCopy = 0; + int ret = WOLFSSL_SUCCESS; + + (void)ticketLen; + (void)doDynamicCopy; + (void)tmpBuff; + + if (!ssl || !copyFrom) + return BAD_FUNC_ARG; + +#ifdef HAVE_SESSION_TICKET + /* Free old dynamic ticket if we had one to avoid leak */ + if (copyInto->isDynamic) { + XFREE(copyInto->ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + copyInto->ticket = copyInto->staticTicket; + copyInto->isDynamic = 0; + } +#endif + + if (wc_LockMutex(&session_mutex) != 0) + return BAD_MUTEX_E; + +#ifdef HAVE_SESSION_TICKET + /* Size of ticket to alloc if needed; Use later for alloc outside lock */ + doDynamicCopy = copyFrom->isDynamic; + ticketLen = copyFrom->ticketLen; +#endif + + *copyInto = *copyFrom; + + /* Default ticket to non dynamic. This will avoid crash if we fail below */ +#ifdef HAVE_SESSION_TICKET + copyInto->ticket = copyInto->staticTicket; + copyInto->isDynamic = 0; +#endif + +#ifndef NO_RESUME_SUITE_CHECK + copyInto->cipherSuite0 = copyFrom->cipherSuite0; + copyInto->cipherSuite = copyFrom->cipherSuite; +#endif + + if (wc_UnLockMutex(&session_mutex) != 0) { + return BAD_MUTEX_E; + } + +#ifdef HAVE_SESSION_TICKET +#ifdef WOLFSSL_TLS13 + if (wc_LockMutex(&session_mutex) != 0) { + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + return BAD_MUTEX_E; + } + +#ifdef NO_RESUME_SUITE_CHECK + copyInto->cipherSuite0 = copyFrom->cipherSuite0; + copyInto->cipherSuite = copyFrom->cipherSuite; +#endif + copyInto->namedGroup = copyFrom->namedGroup; + copyInto->ticketSeen = copyFrom->ticketSeen; + copyInto->ticketAdd = copyFrom->ticketAdd; +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(©Into->ticketNonce, ©From->ticketNonce, + sizeof(TicketNonce)); +#endif +#ifdef WOLFSSL_EARLY_DATA + copyInto->maxEarlyDataSz = copyFrom->maxEarlyDataSz; +#endif + XMEMCPY(copyInto->masterSecret, copyFrom->masterSecret, SECRET_LEN); + + if (wc_UnLockMutex(&session_mutex) != 0) { + if (ret == WOLFSSL_SUCCESS) + ret = BAD_MUTEX_E; + } +#endif + /* If doing dynamic copy, need to alloc outside lock, then inside a lock + * confirm the size still matches and memcpy */ + if (doDynamicCopy) { + tmpBuff = (byte*)XMALLOC(ticketLen, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + if (!tmpBuff) + return MEMORY_ERROR; + + if (wc_LockMutex(&session_mutex) != 0) { + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + return BAD_MUTEX_E; + } + + if ((word16)ticketLen != copyFrom->ticketLen) { + /* Another thread modified the ssl-> session ticket during alloc. + * Treat as error, since ticket different than when copy requested */ + ret = VAR_STATE_CHANGE_E; + } + + if (ret == WOLFSSL_SUCCESS) { + copyInto->ticket = (byte*)tmpBuff; + copyInto->isDynamic = 1; + XMEMCPY(copyInto->ticket, copyFrom->ticket, ticketLen); + } + } else { + /* Need to ensure ticket pointer gets updated to own buffer + * and is not pointing to buff of session copied from */ + copyInto->ticket = copyInto->staticTicket; + } + + if (doDynamicCopy) { + if (wc_UnLockMutex(&session_mutex) != 0) { + if (ret == WOLFSSL_SUCCESS) + ret = BAD_MUTEX_E; + } + } + + if (ret != WOLFSSL_SUCCESS) { + /* cleanup */ + if (tmpBuff) + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + copyInto->ticket = copyInto->staticTicket; + copyInto->isDynamic = 0; + } +#endif /* HAVE_SESSION_TICKET */ + return ret; +} + + +int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) +{ + if (ssl->options.sessionCacheOff) + return WOLFSSL_FAILURE; + +#ifdef OPENSSL_EXTRA + /* check for application context id */ + if (ssl->sessionCtxSz > 0) { + if (XMEMCMP(ssl->sessionCtx, session->sessionCtx, ssl->sessionCtxSz)) { + /* context id did not match! */ + WOLFSSL_MSG("Session context did not match"); + return SSL_FAILURE; + } + } +#endif /* OPENSSL_EXTRA */ + + if (LowResTimer() < (session->bornOn + session->timeout)) { + int ret = GetDeepCopySession(ssl, session); + if (ret == WOLFSSL_SUCCESS) { + ssl->options.resuming = 1; + +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + ssl->version = session->version; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + ssl->options.cipherSuite0 = session->cipherSuite0; + ssl->options.cipherSuite = session->cipherSuite; +#endif + } + + return ret; + } + return WOLFSSL_FAILURE; /* session timed out */ +} + + +#ifdef WOLFSSL_SESSION_STATS +static int get_locked_session_stats(word32* active, word32* total, + word32* peak); +#endif + +int AddSession(WOLFSSL* ssl) +{ + word32 row = 0; + word32 idx = 0; + int error = 0; +#ifdef HAVE_SESSION_TICKET + byte* tmpBuff = NULL; + int ticLen = 0; +#endif + WOLFSSL_SESSION* session; + int i; + int overwrite = 0; + + if (ssl->options.sessionCacheOff) + return 0; + + if (ssl->options.haveSessionId == 0) + return 0; + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) + return 0; +#endif + +#ifdef HAVE_SESSION_TICKET + ticLen = ssl->session.ticketLen; + /* Alloc Memory here so if Malloc fails can exit outside of lock */ + if(ticLen > SESSION_TICKET_LEN) { + tmpBuff = (byte*)XMALLOC(ticLen, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + if(!tmpBuff) + return MEMORY_E; + } +#endif + +#ifdef HAVE_EXT_CACHE + if (ssl->options.internalCacheOff) { + /* Create a new session object to be stored. */ + session = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL, + DYNAMIC_TYPE_OPENSSL); + if (session == NULL) { +#ifdef HAVE_SESSION_TICKET + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif + return MEMORY_E; + } + XMEMSET(session, 0, sizeof(WOLFSSL_SESSION)); + session->isAlloced = 1; + } + else +#endif + { + /* Use the session object in the cache for external cache if required. + */ +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (ssl->options.tls1_3) { + row = HashSession(ssl->session.sessionID, ID_LEN, &error) % + SESSION_ROWS; + } + else +#endif + { + row = HashSession(ssl->arrays->sessionID, ID_LEN, &error) % + SESSION_ROWS; + } + if (error != 0) { + WOLFSSL_MSG("Hash session failed"); +#ifdef HAVE_SESSION_TICKET + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif + return error; + } + + if (wc_LockMutex(&session_mutex) != 0) { +#ifdef HAVE_SESSION_TICKET + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif + return BAD_MUTEX_E; + } + + for (i=0; ioptions.tls1_3) { + if (XMEMCMP(ssl->session.sessionID, SessionCache[row].Sessions[i].sessionID, ID_LEN) == 0) { + WOLFSSL_MSG("Session already exists. Overwriting."); + overwrite = 1; + idx = i; + break; + } + } + else { + if (XMEMCMP(ssl->arrays->sessionID, SessionCache[row].Sessions[i].sessionID, ID_LEN) == 0) { + WOLFSSL_MSG("Session already exists. Overwriting."); + overwrite = 1; + idx = i; + break; + } + } + } + + if (!overwrite) { + idx = SessionCache[row].nextIdx++; + } +#ifdef SESSION_INDEX + ssl->sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx; +#endif + session = &SessionCache[row].Sessions[idx]; + } + + if (!ssl->options.tls1_3) + XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); + else + XMEMCPY(session->masterSecret, ssl->session.masterSecret, SECRET_LEN); + session->haveEMS = ssl->options.haveEMS; +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (ssl->options.tls1_3) { + XMEMCPY(session->sessionID, ssl->session.sessionID, ID_LEN); + session->sessionIDSz = ID_LEN; + } + else +#endif + { + XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); + session->sessionIDSz = ssl->arrays->sessionIDSz; + } + +#ifdef OPENSSL_EXTRA + /* If using compatibility layer then check for and copy over session context + * id. */ + if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { + XMEMCPY(session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); + } +#endif + + session->timeout = ssl->timeout; + session->bornOn = LowResTimer(); + +#ifdef HAVE_SESSION_TICKET + /* Check if another thread modified ticket since alloc */ + if ((word16)ticLen != ssl->session.ticketLen) { + error = VAR_STATE_CHANGE_E; + } + + if (error == 0) { + /* Cleanup cache row's old Dynamic buff if exists */ + if(session->isDynamic) { + XFREE(session->ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + session->ticket = NULL; + } + + /* If too large to store in static buffer, use dyn buffer */ + if (ticLen > SESSION_TICKET_LEN) { + session->ticket = tmpBuff; + session->isDynamic = 1; + } else { + session->ticket = session->staticTicket; + session->isDynamic = 0; + } + + session->ticketLen = (word16)ticLen; + XMEMCPY(session->ticket, ssl->session.ticket, ticLen); + } else { /* cleanup, reset state */ + session->ticket = session->staticTicket; + session->isDynamic = 0; + session->ticketLen = 0; + if (tmpBuff) { + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + tmpBuff = NULL; + } + } +#endif + +#ifdef SESSION_CERTS + if (error == 0) { + if (!overwrite || ssl->session.chain.count > 0) { + /* + * If we are overwriting and no certs present in ssl->session.chain + * then keep the old chain. + */ + session->chain.count = ssl->session.chain.count; + XMEMCPY(session->chain.certs, ssl->session.chain.certs, + sizeof(x509_buffer) * session->chain.count); + } + } +#endif /* SESSION_CERTS */ +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + if (error == 0) { + session->version = ssl->version; + } +#endif /* SESSION_CERTS || (WOLFSSL_TLS13 & HAVE_SESSION_TICKET) */ +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + if (error == 0) { + session->cipherSuite0 = ssl->options.cipherSuite0; + session->cipherSuite = ssl->options.cipherSuite; + } +#endif +#if defined(WOLFSSL_TLS13) + if (error == 0) { + session->namedGroup = ssl->session.namedGroup; + } +#endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (error == 0) { + session->ticketSeen = ssl->session.ticketSeen; + session->ticketAdd = ssl->session.ticketAdd; +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(&session->ticketNonce, &ssl->session.ticketNonce, + sizeof(TicketNonce)); +#endif + #ifdef WOLFSSL_EARLY_DATA + session->maxEarlyDataSz = ssl->session.maxEarlyDataSz; + #endif + } +#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET */ +#ifdef HAVE_EXT_CACHE + if (!ssl->options.internalCacheOff) +#endif + { + if (error == 0) { + SessionCache[row].totalCount++; + if (SessionCache[row].nextIdx == SESSIONS_PER_ROW) + SessionCache[row].nextIdx = 0; + } + } +#ifndef NO_CLIENT_CACHE + if (error == 0) { + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->session.idLen) { + word32 clientRow, clientIdx; + + WOLFSSL_MSG("Adding client cache entry"); + + session->idLen = ssl->session.idLen; + XMEMCPY(session->serverID, ssl->session.serverID, + ssl->session.idLen); + +#ifdef HAVE_EXT_CACHE + if (!ssl->options.internalCacheOff) +#endif + { + clientRow = HashSession(ssl->session.serverID, + ssl->session.idLen, &error) % SESSION_ROWS; + if (error != 0) { + WOLFSSL_MSG("Hash session failed"); + } else { + clientIdx = ClientCache[clientRow].nextIdx++; + + ClientCache[clientRow].Clients[clientIdx].serverRow = + (word16)row; + ClientCache[clientRow].Clients[clientIdx].serverIdx = + (word16)idx; + + ClientCache[clientRow].totalCount++; + if (ClientCache[clientRow].nextIdx == SESSIONS_PER_ROW) + ClientCache[clientRow].nextIdx = 0; + } + } + } + else + session->idLen = 0; + } +#endif /* NO_CLIENT_CACHE */ + +#if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) +#ifdef HAVE_EXT_CACHE + if (!ssl->options.internalCacheOff) +#endif + { + if (error == 0) { + word32 active = 0; + + error = get_locked_session_stats(&active, NULL, NULL); + if (error == WOLFSSL_SUCCESS) { + error = 0; /* back to this function ok */ + + if (active > PeakSessions) + PeakSessions = active; + } + } + } +#endif /* defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) */ + +#ifdef HAVE_EXT_CACHE + if (!ssl->options.internalCacheOff) +#endif + { + if (wc_UnLockMutex(&session_mutex) != 0) + return BAD_MUTEX_E; + } + +#ifdef HAVE_EXT_CACHE + if (error == 0 && ssl->ctx->new_sess_cb != NULL) + ssl->ctx->new_sess_cb(ssl, session); + if (ssl->options.internalCacheOff) + wolfSSL_SESSION_free(session); +#endif + + return error; +} + + +#ifdef SESSION_INDEX + +int wolfSSL_GetSessionIndex(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_GetSessionIndex"); + WOLFSSL_LEAVE("wolfSSL_GetSessionIndex", ssl->sessionIndex); + return ssl->sessionIndex; +} + + +int wolfSSL_GetSessionAtIndex(int idx, WOLFSSL_SESSION* session) +{ + int row, col, result = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_GetSessionAtIndex"); + + row = idx >> SESSIDX_ROW_SHIFT; + col = idx & SESSIDX_IDX_MASK; + + if (wc_LockMutex(&session_mutex) != 0) { + return BAD_MUTEX_E; + } + + if (row < SESSION_ROWS && + col < (int)min(SessionCache[row].totalCount, SESSIONS_PER_ROW)) { + XMEMCPY(session, + &SessionCache[row].Sessions[col], sizeof(WOLFSSL_SESSION)); + result = WOLFSSL_SUCCESS; + } + + if (wc_UnLockMutex(&session_mutex) != 0) + result = BAD_MUTEX_E; + + WOLFSSL_LEAVE("wolfSSL_GetSessionAtIndex", result); + return result; +} + +#endif /* SESSION_INDEX */ + +#if defined(SESSION_CERTS) + +WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session) +{ + WOLFSSL_X509_CHAIN* chain = NULL; + + WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); + if (session) + chain = &session->chain; + + WOLFSSL_LEAVE("wolfSSL_SESSION_get_peer_chain", chain ? 1 : 0); + return chain; +} + + +#ifdef OPENSSL_EXTRA +/* gets the peer certificate associated with the session passed in + * returns null on failure, the caller should not free the returned pointer */ +WOLFSSL_X509* wolfSSL_SESSION_get0_peer(WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); + if (session) { + int count; + + count = wolfSSL_get_chain_count(&session->chain); + if (count < 1 || count >= MAX_CHAIN_DEPTH) { + WOLFSSL_MSG("bad count found"); + return NULL; + } + + if (session->peer == NULL) { + session->peer = wolfSSL_get_chain_X509(&session->chain, 0); + } + return session->peer; + } + WOLFSSL_MSG("No session passed in"); + + return NULL; +} +#endif /* OPENSSL_EXTRA */ +#endif /* SESSION_INDEX && SESSION_CERTS */ + + +#ifdef WOLFSSL_SESSION_STATS + +/* requires session_mutex lock held, WOLFSSL_SUCCESS on ok */ +static int get_locked_session_stats(word32* active, word32* total, word32* peak) +{ + int result = WOLFSSL_SUCCESS; + int i; + int count; + int idx; + word32 now = 0; + word32 seen = 0; + word32 ticks = LowResTimer(); + + (void)peak; + + WOLFSSL_ENTER("get_locked_session_stats"); + + for (i = 0; i < SESSION_ROWS; i++) { + seen += SessionCache[i].totalCount; + + if (active == NULL) + continue; /* no need to calculate what we can't set */ + + count = min((word32)SessionCache[i].totalCount, SESSIONS_PER_ROW); + idx = SessionCache[i].nextIdx - 1; + if (idx < 0) + idx = SESSIONS_PER_ROW - 1; /* if back to front previous was end */ + + for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) { + if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */ + WOLFSSL_MSG("Bad idx"); + break; + } + + /* if not expired then good */ + if (ticks < (SessionCache[i].Sessions[idx].bornOn + + SessionCache[i].Sessions[idx].timeout) ) { + now++; + } + } + } + + if (active) + *active = now; + + if (total) + *total = seen; + +#ifdef WOLFSSL_PEAK_SESSIONS + if (peak) + *peak = PeakSessions; +#endif + + WOLFSSL_LEAVE("get_locked_session_stats", result); + + return result; +} + + +/* return WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak, + word32* maxSessions) +{ + int result = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_get_session_stats"); + + if (maxSessions) { + *maxSessions = SESSIONS_PER_ROW * SESSION_ROWS; + + if (active == NULL && total == NULL && peak == NULL) + return result; /* we're done */ + } + + /* user must provide at least one query value */ + if (active == NULL && total == NULL && peak == NULL) + return BAD_FUNC_ARG; + + if (wc_LockMutex(&session_mutex) != 0) { + return BAD_MUTEX_E; + } + + result = get_locked_session_stats(active, total, peak); + + if (wc_UnLockMutex(&session_mutex) != 0) + result = BAD_MUTEX_E; + + WOLFSSL_LEAVE("wolfSSL_get_session_stats", result); + + return result; +} + +#endif /* WOLFSSL_SESSION_STATS */ + + + #ifdef PRINT_SESSION_STATS + + /* WOLFSSL_SUCCESS on ok */ + int wolfSSL_PrintSessionStats(void) + { + word32 totalSessionsSeen = 0; + word32 totalSessionsNow = 0; + word32 peak = 0; + word32 maxSessions = 0; + int i; + int ret; + double E; /* expected freq */ + double chiSquare = 0; + + ret = wolfSSL_get_session_stats(&totalSessionsNow, &totalSessionsSeen, + &peak, &maxSessions); + if (ret != WOLFSSL_SUCCESS) + return ret; + printf("Total Sessions Seen = %d\n", totalSessionsSeen); + printf("Total Sessions Now = %d\n", totalSessionsNow); +#ifdef WOLFSSL_PEAK_SESSIONS + printf("Peak Sessions = %d\n", peak); +#endif + printf("Max Sessions = %d\n", maxSessions); + + E = (double)totalSessionsSeen / SESSION_ROWS; + + for (i = 0; i < SESSION_ROWS; i++) { + double diff = SessionCache[i].totalCount - E; + diff *= diff; /* square */ + diff /= E; /* normalize */ + + chiSquare += diff; + } + printf(" chi-square = %5.1f, d.f. = %d\n", chiSquare, + SESSION_ROWS - 1); + #if (SESSION_ROWS == 11) + printf(" .05 p value = 18.3, chi-square should be less\n"); + #elif (SESSION_ROWS == 211) + printf(".05 p value = 244.8, chi-square should be less\n"); + #elif (SESSION_ROWS == 5981) + printf(".05 p value = 6161.0, chi-square should be less\n"); + #elif (SESSION_ROWS == 3) + printf(".05 p value = 6.0, chi-square should be less\n"); + #elif (SESSION_ROWS == 2861) + printf(".05 p value = 2985.5, chi-square should be less\n"); + #endif + printf("\n"); + + return ret; + } + + #endif /* SESSION_STATS */ + +#else /* NO_SESSION_CACHE */ + +/* No session cache version */ +WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret, + byte restoreSessionCerts) +{ + (void)ssl; + (void)masterSecret; + (void)restoreSessionCerts; + + return NULL; +} + +#endif /* NO_SESSION_CACHE */ + + +/* call before SSL_connect, if verifying will add name check to + date check and signature check */ +WOLFSSL_ABI +int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn) +{ + WOLFSSL_ENTER("wolfSSL_check_domain_name"); + + if (ssl == NULL || dn == NULL) { + WOLFSSL_MSG("Bad function argument: NULL"); + return WOLFSSL_FAILURE; + } + + if (ssl->buffers.domainName.buffer) + XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); + + ssl->buffers.domainName.length = (word32)XSTRLEN(dn); + ssl->buffers.domainName.buffer = (byte*)XMALLOC( + ssl->buffers.domainName.length + 1, ssl->heap, DYNAMIC_TYPE_DOMAIN); + + if (ssl->buffers.domainName.buffer) { + unsigned char* domainName = ssl->buffers.domainName.buffer; + XMEMCPY(domainName, dn, ssl->buffers.domainName.length); + domainName[ssl->buffers.domainName.length] = '\0'; + return WOLFSSL_SUCCESS; + } + else { + ssl->error = MEMORY_ERROR; + return WOLFSSL_FAILURE; + } +} + + +/* turn on wolfSSL zlib compression + returns WOLFSSL_SUCCESS for success, else error (not built in) +*/ +int wolfSSL_set_compression(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_set_compression"); + (void)ssl; +#ifdef HAVE_LIBZ + ssl->options.usingCompression = 1; + return WOLFSSL_SUCCESS; +#else + return NOT_COMPILED_IN; +#endif +} + + +#ifndef USE_WINDOWS_API + #ifndef NO_WRITEV + + /* simulate writev semantics, doesn't actually do block at a time though + because of SSL_write behavior and because front adds may be small */ + int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov, int iovcnt) + { + #ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ + #else + byte staticBuffer[FILE_BUFFER_SIZE]; + #endif + byte* myBuffer = staticBuffer; + int dynamic = 0; + int sending = 0; + int idx = 0; + int i; + int ret; + + WOLFSSL_ENTER("wolfSSL_writev"); + + for (i = 0; i < iovcnt; i++) + sending += (int)iov[i].iov_len; + + if (sending > (int)sizeof(staticBuffer)) { + myBuffer = (byte*)XMALLOC(sending, ssl->heap, + DYNAMIC_TYPE_WRITEV); + if (!myBuffer) + return MEMORY_ERROR; + + dynamic = 1; + } + + for (i = 0; i < iovcnt; i++) { + XMEMCPY(&myBuffer[idx], iov[i].iov_base, iov[i].iov_len); + idx += (int)iov[i].iov_len; + } + + ret = wolfSSL_write(ssl, myBuffer, sending); + + if (dynamic) + XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV); + + return ret; + } + #endif +#endif + + +#ifdef WOLFSSL_CALLBACKS + + typedef struct itimerval Itimerval; + + /* don't keep calling simple functions while setting up timer and signals + if no inlining these are the next best */ + + #define AddTimes(a, b, c) \ + do { \ + c.tv_sec = a.tv_sec + b.tv_sec; \ + c.tv_usec = a.tv_usec + b.tv_usec; \ + if (c.tv_usec >= 1000000) { \ + c.tv_sec++; \ + c.tv_usec -= 1000000; \ + } \ + } while (0) + + + #define SubtractTimes(a, b, c) \ + do { \ + c.tv_sec = a.tv_sec - b.tv_sec; \ + c.tv_usec = a.tv_usec - b.tv_usec; \ + if (c.tv_usec < 0) { \ + c.tv_sec--; \ + c.tv_usec += 1000000; \ + } \ + } while (0) + + #define CmpTimes(a, b, cmp) \ + ((a.tv_sec == b.tv_sec) ? \ + (a.tv_usec cmp b.tv_usec) : \ + (a.tv_sec cmp b.tv_sec)) \ + + + /* do nothing handler */ + static void myHandler(int signo) + { + (void)signo; + return; + } + + + static int wolfSSL_ex_wrapper(WOLFSSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) + { + int ret = WOLFSSL_FATAL_ERROR; + int oldTimerOn = 0; /* was timer already on */ + WOLFSSL_TIMEVAL startTime; + WOLFSSL_TIMEVAL endTime; + WOLFSSL_TIMEVAL totalTime; + Itimerval myTimeout; + Itimerval oldTimeout; /* if old timer adjust from total time to reset */ + struct sigaction act, oact; + + #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; } + + if (hsCb) { + ssl->hsInfoOn = 1; + InitHandShakeInfo(&ssl->handShakeInfo, ssl); + } + if (toCb) { + ssl->toInfoOn = 1; + InitTimeoutInfo(&ssl->timeoutInfo); + + if (gettimeofday(&startTime, 0) < 0) + ERR_OUT(GETTIME_ERROR); + + /* use setitimer to simulate getitimer, init 0 myTimeout */ + myTimeout.it_interval.tv_sec = 0; + myTimeout.it_interval.tv_usec = 0; + myTimeout.it_value.tv_sec = 0; + myTimeout.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0) + ERR_OUT(SETITIMER_ERROR); + + if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) { + oldTimerOn = 1; + + /* is old timer going to expire before ours */ + if (CmpTimes(oldTimeout.it_value, timeout, <)) { + timeout.tv_sec = oldTimeout.it_value.tv_sec; + timeout.tv_usec = oldTimeout.it_value.tv_usec; + } + } + myTimeout.it_value.tv_sec = timeout.tv_sec; + myTimeout.it_value.tv_usec = timeout.tv_usec; + + /* set up signal handler, don't restart socket send/recv */ + act.sa_handler = myHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_INTERRUPT + act.sa_flags |= SA_INTERRUPT; +#endif + if (sigaction(SIGALRM, &act, &oact) < 0) + ERR_OUT(SIGACT_ERROR); + + if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0) + ERR_OUT(SETITIMER_ERROR); + } + + /* do main work */ +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) + ret = wolfSSL_connect(ssl); +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) + ret = wolfSSL_accept(ssl); +#endif + + /* do callbacks */ + if (toCb) { + if (oldTimerOn) { + gettimeofday(&endTime, 0); + SubtractTimes(endTime, startTime, totalTime); + /* adjust old timer for elapsed time */ + if (CmpTimes(totalTime, oldTimeout.it_value, <)) + SubtractTimes(oldTimeout.it_value, totalTime, + oldTimeout.it_value); + else { + /* reset value to interval, may be off */ + oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec; + oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec; + } + /* keep iter the same whether there or not */ + } + /* restore old handler */ + if (sigaction(SIGALRM, &oact, 0) < 0) + ret = SIGACT_ERROR; /* more pressing error, stomp */ + else + /* use old settings which may turn off (expired or not there) */ + if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0) + ret = SETITIMER_ERROR; + + /* if we had a timeout call callback */ + if (ssl->timeoutInfo.timeoutName[0]) { + ssl->timeoutInfo.timeoutValue.tv_sec = timeout.tv_sec; + ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec; + (toCb)(&ssl->timeoutInfo); + } + /* clean up */ + FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap); + ssl->toInfoOn = 0; + } + if (hsCb) { + FinishHandShakeInfo(&ssl->handShakeInfo); + (hsCb)(&ssl->handShakeInfo); + ssl->hsInfoOn = 0; + } + return ret; + } + + +#ifndef NO_WOLFSSL_CLIENT + + int wolfSSL_connect_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) + { + WOLFSSL_ENTER("wolfSSL_connect_ex"); + return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); + } + +#endif + + +#ifndef NO_WOLFSSL_SERVER + + int wolfSSL_accept_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) + { + WOLFSSL_ENTER("wolfSSL_accept_ex"); + return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); + } + +#endif + +#endif /* WOLFSSL_CALLBACKS */ + + +#ifndef NO_PSK + + void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX* ctx, + wc_psk_client_callback cb) + { + WOLFSSL_ENTER("SSL_CTX_set_psk_client_callback"); + + if (ctx == NULL) + return; + + ctx->havePSK = 1; + ctx->client_psk_cb = cb; + } + + + void wolfSSL_set_psk_client_callback(WOLFSSL* ssl,wc_psk_client_callback cb) + { + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_client_callback"); + + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.client_psk_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + + + void wolfSSL_CTX_set_psk_server_callback(WOLFSSL_CTX* ctx, + wc_psk_server_callback cb) + { + WOLFSSL_ENTER("SSL_CTX_set_psk_server_callback"); + if (ctx == NULL) + return; + ctx->havePSK = 1; + ctx->server_psk_cb = cb; + } + + + void wolfSSL_set_psk_server_callback(WOLFSSL* ssl,wc_psk_server_callback cb) + { + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_server_callback"); + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.server_psk_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + } + + + const char* wolfSSL_get_psk_identity_hint(const WOLFSSL* ssl) + { + WOLFSSL_ENTER("SSL_get_psk_identity_hint"); + + if (ssl == NULL || ssl->arrays == NULL) + return NULL; + + return ssl->arrays->server_hint; + } + + + const char* wolfSSL_get_psk_identity(const WOLFSSL* ssl) + { + WOLFSSL_ENTER("SSL_get_psk_identity"); + + if (ssl == NULL || ssl->arrays == NULL) + return NULL; + + return ssl->arrays->client_identity; + } + + + int wolfSSL_CTX_use_psk_identity_hint(WOLFSSL_CTX* ctx, const char* hint) + { + WOLFSSL_ENTER("SSL_CTX_use_psk_identity_hint"); + if (hint == 0) + ctx->server_hint[0] = '\0'; + else { + /* Qt does not call CTX_set_*_psk_callbacks where havePSK is set */ + #ifdef WOLFSSL_QT + ctx->havePSK=1; + #endif + XSTRNCPY(ctx->server_hint, hint, MAX_PSK_ID_LEN); + ctx->server_hint[MAX_PSK_ID_LEN] = '\0'; /* null term */ + } + return WOLFSSL_SUCCESS; + } + + + int wolfSSL_use_psk_identity_hint(WOLFSSL* ssl, const char* hint) + { + WOLFSSL_ENTER("SSL_use_psk_identity_hint"); + + if (ssl == NULL || ssl->arrays == NULL) + return WOLFSSL_FAILURE; + + if (hint == 0) + ssl->arrays->server_hint[0] = 0; + else { + XSTRNCPY(ssl->arrays->server_hint, hint, + sizeof(ssl->arrays->server_hint)-1); + ssl->arrays->server_hint[sizeof(ssl->arrays->server_hint)-1] = '\0'; + } + return WOLFSSL_SUCCESS; + } + +#endif /* NO_PSK */ + + +#ifdef HAVE_ANON + + int wolfSSL_CTX_allow_anon_cipher(WOLFSSL_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_CTX_allow_anon_cipher"); + + if (ctx == NULL) + return WOLFSSL_FAILURE; + + ctx->haveAnon = 1; + + return WOLFSSL_SUCCESS; + } + +#endif /* HAVE_ANON */ + + +#ifndef NO_CERTS +/* used to be defined on NO_FILESYSTEM only, but are generally useful */ + + int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, + const unsigned char* in, + long sz, int format, int userChain, + word32 flags) + { + int verify; + + WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex"); + + verify = GET_VERIFY_SETTING_CTX(ctx); + if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) + verify = VERIFY_SKIP_DATE; + + if (format == WOLFSSL_FILETYPE_PEM) + return ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL, + verify); + else + return ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL, + userChain, verify); + } + + /* wolfSSL extension allows DER files to be loaded from buffers as well */ + int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, + long sz, int format) + { + return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 0, + WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); + } + + int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx, + const unsigned char* in, + long sz, int format) + { + return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 1, + WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); + } + + +#ifdef WOLFSSL_TRUST_PEER_CERT + int wolfSSL_CTX_trust_peer_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, + long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_buffer"); + + /* sanity check on arguments */ + if (sz < 0 || in == NULL || ctx == NULL) { + return BAD_FUNC_ARG; + } + + if (format == WOLFSSL_FILETYPE_PEM) + return ProcessChainBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, + NULL, GET_VERIFY_SETTING_CTX(ctx)); + else + return ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL, + NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); + } +#endif /* WOLFSSL_TRUST_PEER_CERT */ + + + int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer"); + return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0, + GET_VERIFY_SETTING_CTX(ctx)); + } + + + int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer"); + return ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, NULL, + 0, GET_VERIFY_SETTING_CTX(ctx)); + } + +#ifdef HAVE_PKCS11 + int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, + long sz, int devId, long keySz) + { + int ret = WOLFSSL_FAILURE; + + FreeDer(&ctx->privateKey); + if (AllocDer(&ctx->privateKey, (word32)sz, PRIVATEKEY_TYPE, + ctx->heap) == 0) { + XMEMCPY(ctx->privateKey->buffer, id, sz); + ctx->privateKeyId = 1; + ctx->privateKeySz = (word32)keySz; + if (devId != INVALID_DEVID) + ctx->privateKeyDevId = devId; + else + ctx->privateKeyDevId = ctx->devId; + + ret = WOLFSSL_SUCCESS; + } + + return ret; + } +#endif + + int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer_format"); + return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 1, + GET_VERIFY_SETTING_CTX(ctx)); + } + + int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz) + { + return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz, + WOLFSSL_FILETYPE_PEM); + } + + +#ifndef NO_DH + + /* server wrapper for ctx or ssl Diffie-Hellman parameters */ + static int wolfSSL_SetTmpDH_buffer_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + const unsigned char* buf, + long sz, int format) + { + DerBuffer* der = NULL; + int ret = 0; + word32 pSz = MAX_DH_SIZE; + word32 gSz = MAX_DH_SIZE; + #ifdef WOLFSSL_SMALL_STACK + byte* p = NULL; + byte* g = NULL; + #else + byte p[MAX_DH_SIZE]; + byte g[MAX_DH_SIZE]; + #endif + + if (ctx == NULL || buf == NULL) + return BAD_FUNC_ARG; + + ret = AllocDer(&der, 0, DH_PARAM_TYPE, ctx->heap); + if (ret != 0) { + return ret; + } + der->buffer = (byte*)buf; + der->length = (word32)sz; + + #ifdef WOLFSSL_SMALL_STACK + p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + + if (p == NULL || g == NULL) { + XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + return MEMORY_E; + } + #endif + + if (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM) + ret = WOLFSSL_BAD_FILETYPE; + else { + if (format == WOLFSSL_FILETYPE_PEM) { +#ifdef WOLFSSL_PEM_TO_DER + FreeDer(&der); + ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, ctx->heap, + NULL, NULL); + #ifdef WOLFSSL_WPAS + #ifndef NO_DSA + if (ret < 0) { + ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, ctx->heap, + NULL, NULL); + } + #endif + #endif /* WOLFSSL_WPAS */ +#else + ret = NOT_COMPILED_IN; +#endif /* WOLFSSL_PEM_TO_DER */ + } + + if (ret == 0) { + if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) + ret = WOLFSSL_BAD_FILETYPE; + else if (ssl) + ret = wolfSSL_SetTmpDH(ssl, p, pSz, g, gSz); + else + ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz); + } + } + + FreeDer(&der); + + #ifdef WOLFSSL_SMALL_STACK + XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + #endif + + return ret; + } + + + /* server Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ + int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz, + int format) + { + if (ssl == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_SetTmpDH_buffer_wrapper(ssl->ctx, ssl, buf, sz, format); + } + + + /* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ + int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf, + long sz, int format) + { + return wolfSSL_SetTmpDH_buffer_wrapper(ctx, NULL, buf, sz, format); + } + +#endif /* NO_DH */ + + + int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, + const unsigned char* in, long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_use_certificate_buffer"); + if (ssl == NULL) + return BAD_FUNC_ARG; + + return ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 0, + GET_VERIFY_SETTING_SSL(ssl)); + } + + + int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, + const unsigned char* in, long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer"); + if (ssl == NULL) + return BAD_FUNC_ARG; + + return ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, + ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); + } + +#ifdef HAVE_PKCS11 + int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id, + long sz, int devId, long keySz) + { + int ret = WOLFSSL_FAILURE; + + if (ssl->buffers.weOwnKey) + FreeDer(&ssl->buffers.key); + if (AllocDer(&ssl->buffers.key, (word32)sz, PRIVATEKEY_TYPE, + ssl->heap) == 0) { + XMEMCPY(ssl->buffers.key->buffer, id, sz); + ssl->buffers.weOwnKey = 1; + ssl->buffers.keyId = 1; + ssl->buffers.keySz = (word32)keySz; + if (devId != INVALID_DEVID) + ssl->buffers.keyDevId = devId; + else + ssl->buffers.keyDevId = ssl->devId; + + ret = WOLFSSL_SUCCESS; + } + + return ret; + } +#endif + + int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl, + const unsigned char* in, long sz, int format) + { + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); + if (ssl == NULL) + return BAD_FUNC_ARG; + + return ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, + ssl, NULL, 1, GET_VERIFY_SETTING_SSL(ssl)); + } + + int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, + const unsigned char* in, long sz) + { + return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz, + WOLFSSL_FILETYPE_PEM); + } + + + /* unload any certs or keys that SSL owns, leave CTX as is + WOLFSSL_SUCCESS on ok */ + int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) + { + if (ssl == NULL) { + WOLFSSL_MSG("Null function arg"); + return BAD_FUNC_ARG; + } + + if (ssl->buffers.weOwnCert && !ssl->keepCert) { + WOLFSSL_MSG("Unloading cert"); + FreeDer(&ssl->buffers.certificate); + #ifdef KEEP_OUR_CERT + FreeX509(ssl->ourCert); + if (ssl->ourCert) { + XFREE(ssl->ourCert, ssl->heap, DYNAMIC_TYPE_X509); + ssl->ourCert = NULL; + } + #endif + ssl->buffers.weOwnCert = 0; + } + + if (ssl->buffers.weOwnCertChain) { + WOLFSSL_MSG("Unloading cert chain"); + FreeDer(&ssl->buffers.certChain); + ssl->buffers.weOwnCertChain = 0; + } + + if (ssl->buffers.weOwnKey) { + WOLFSSL_MSG("Unloading key"); + FreeDer(&ssl->buffers.key); + ssl->buffers.weOwnKey = 0; + } + + return WOLFSSL_SUCCESS; + } + + + int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_CertManagerUnloadCAs(ctx->cm); + } + + +#ifdef WOLFSSL_TRUST_PEER_CERT + int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_CertManagerUnload_trust_peers(ctx->cm); + } +#endif /* WOLFSSL_TRUST_PEER_CERT */ +/* old NO_FILESYSTEM end */ +#endif /* !NO_CERTS */ + + +#ifdef OPENSSL_EXTRA + + int wolfSSL_add_all_algorithms(void) + { + WOLFSSL_ENTER("wolfSSL_add_all_algorithms"); + if (wolfSSL_Init() == WOLFSSL_SUCCESS) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FATAL_ERROR; + } + + int wolfSSL_OpenSSL_add_all_algorithms_noconf(void) + { + WOLFSSL_ENTER("wolfSSL_OpenSSL_add_all_algorithms_noconf"); + + if (wolfSSL_add_all_algorithms() == WOLFSSL_FATAL_ERROR) + return WOLFSSL_FATAL_ERROR; + + return WOLFSSL_SUCCESS; + } + + int wolfSSL_OpenSSL_add_all_algorithms_conf(void) + { + WOLFSSL_ENTER("wolfSSL_OpenSSL_add_all_algorithms_conf"); + /* This function is currently the same as + wolfSSL_OpenSSL_add_all_algorithms_noconf since we do not employ + the use of a wolfssl.cnf type configuration file and is only used for + OpenSSL compatability. */ + + if (wolfSSL_add_all_algorithms() == WOLFSSL_FATAL_ERROR) { + return WOLFSSL_FATAL_ERROR; + } + return WOLFSSL_SUCCESS; + } + + /* returns previous set cache size which stays constant */ + long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX* ctx, long sz) + { + /* cache size fixed at compile time in wolfSSL */ + (void)ctx; + (void)sz; + WOLFSSL_MSG("session cache is set at compile time"); + #ifndef NO_SESSION_CACHE + return (long)(SESSIONS_PER_ROW * SESSION_ROWS); + #else + return 0; + #endif + } + +#endif + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) + void wolfSSL_CTX_set_quiet_shutdown(WOLFSSL_CTX* ctx, int mode) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_quiet_shutdown"); + if (mode) + ctx->quietShutdown = 1; + } + + + void wolfSSL_set_quiet_shutdown(WOLFSSL* ssl, int mode) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_quiet_shutdown"); + if (mode) + ssl->options.quietShutdown = 1; + } +#endif + +#ifdef OPENSSL_EXTRA + void wolfSSL_set_bio(WOLFSSL* ssl, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr) + { + WOLFSSL_ENTER("wolfSSL_set_bio"); + + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument, ssl was NULL"); + return; + } + + /* if WOLFSSL_BIO is socket type then set WOLFSSL socket to use */ + if (rd != NULL && rd->type == WOLFSSL_BIO_SOCKET) { + wolfSSL_set_rfd(ssl, rd->num); + } + if (wr != NULL && wr->type == WOLFSSL_BIO_SOCKET) { + wolfSSL_set_wfd(ssl, wr->num); + } + + /* free any existing WOLFSSL_BIOs in use */ + if (ssl->biord != NULL) { + if (ssl->biord != ssl->biowr) { + if (ssl->biowr != NULL) { + wolfSSL_BIO_free(ssl->biowr); + ssl->biowr = NULL; + } + } + wolfSSL_BIO_free(ssl->biord); + ssl->biord = NULL; + } + + + ssl->biord = rd; + ssl->biowr = wr; + + /* set SSL to use BIO callbacks instead */ + if (((ssl->cbioFlag & WOLFSSL_CBIO_RECV) == 0) && + (rd != NULL && rd->type != WOLFSSL_BIO_SOCKET)) { + ssl->CBIORecv = BioReceive; + } + if (((ssl->cbioFlag & WOLFSSL_CBIO_SEND) == 0) && + (wr != NULL && wr->type != WOLFSSL_BIO_SOCKET)) { + ssl->CBIOSend = BioSend; + } + + /* User programs should always retry reading from these BIOs */ + if (rd) { + /* User writes to rd */ + BIO_set_retry_write(rd); + } + if (wr) { + /* User reads from wr */ + BIO_set_retry_read(wr); + } + } +#endif + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(HAVE_WEBSERVER) + void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_client_CA_list"); + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) + if (ctx != NULL) + ctx->ca_names = names; + #else + (void)ctx; + (void)names; + #endif + } + + + /* returns the CA's set on server side or the CA's sent from server when + * on client side */ +#if defined(SESSION_CERTS) && defined(OPENSSL_ALL) + WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get_client_CA_list( + const WOLFSSL* ssl) + { + WOLFSSL_ENTER("wolfSSL_get_client_CA_list"); + + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get_client_CA_list"); + return NULL; + } + + /* return list of CAs sent from the server */ + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLF_STACK_OF(WOLFSSL_X509)* sk; + + sk = wolfSSL_get_peer_cert_chain(ssl); + if (sk != NULL) { + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + WOLFSSL_X509* x509; + + ret = wolfSSL_sk_X509_NAME_new(NULL); + do { + x509 = wolfSSL_sk_X509_pop(sk); + if (x509 != NULL) { + if (wolfSSL_X509_get_isCA(x509)) { + if (wolfSSL_sk_X509_NAME_push(ret, + wolfSSL_X509_get_subject_name(x509)) != 0) { + WOLFSSL_MSG("Error pushing X509 name to stack"); + /* continue on to try other certificates and + * do not fail out here */ + } + } + wolfSSL_X509_free(x509); + } + } while (x509 != NULL); + wolfSSL_sk_X509_free(sk); + return ret; + } + return NULL; + } + else { + /* currently only can be set in the CTX */ + return ssl->ctx->ca_names; + } + } +#endif /* SESSION_CERTS */ + + + #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \ + defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY) + /* registers client cert callback, called during handshake if server + requests client auth but user has not loaded client cert/key */ + void wolfSSL_CTX_set_client_cert_cb(WOLFSSL_CTX *ctx, client_cert_cb cb) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_client_cert_cb"); + + if (ctx != NULL) { + ctx->CBClientCert = cb; + } + } + #endif /* OPENSSL_ALL || OPENSSL_EXTRA || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || HAVE_WEBSERVER */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) + WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get_client_CA_list( + const WOLFSSL_CTX *s) + { + WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); + + if (s == NULL) + return NULL; + + return s->ca_names; + } +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + #if !defined(NO_RSA) && !defined(NO_CERTS) + WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname) + { + /* The webserver build is using this to load a CA into the server + * for client authentication as an option. Have this return NULL in + * that case. If OPENSSL_EXTRA is enabled, go ahead and include + * the function. */ + #ifdef OPENSSL_EXTRA + WOLFSSL_STACK *list = NULL; + WOLFSSL_STACK *node; + WOLFSSL_BIO* bio; + WOLFSSL_X509 *cert = NULL; + WOLFSSL_X509_NAME *subjectName = NULL; + unsigned long err; + + WOLFSSL_ENTER("wolfSSL_load_client_CA_file"); + + bio = wolfSSL_BIO_new_file(fname, "r"); + if (bio == NULL) + return NULL; + + /* Read each certificate in the chain out of the file. */ + while (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { + subjectName = wolfSSL_X509_get_subject_name(cert); + if (subjectName == NULL) + break; + + node = wolfSSL_sk_new_node(NULL); + if (node == NULL) + break; + node->type = STACK_TYPE_X509_NAME; + + /* Need a persistent copy of the subject name. */ + node->data.name = wolfSSL_X509_NAME_dup(subjectName); + /* + * Original cert will be freed so make sure not to try to access + * it in the future. + */ + node->data.name->x509 = NULL; + + /* Put node on the front of the list. */ + node->num = (list == NULL) ? 1 : list->num + 1; + node->next = list; + list = node; + + wolfSSL_X509_free(cert); + cert = NULL; + } + + err = wolfSSL_ERR_peek_last_error(); + + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + /* + * wolfSSL_PEM_read_bio_X509 pushes an ASN_NO_PEM_HEADER error + * to the error queue on file end. This should not be left + * for the caller to find so we clear the last error. + */ + wc_RemoveErrorNode(-1); + } + + wolfSSL_X509_free(cert); + wolfSSL_BIO_free(bio); + return list; + #else + (void)fname; + return NULL; + #endif + } + #endif +#endif + +#ifdef OPENSSL_EXTRA + #if !defined(NO_RSA) && !defined(NO_CERTS) + int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) + { + WOLFSSL_STACK *node = NULL; + WOLFSSL_X509_NAME *subjectName = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA"); + + if (ctx == NULL || x509 == NULL){ + WOLFSSL_MSG("Bad argument"); + return SSL_FAILURE; + } + + subjectName = wolfSSL_X509_get_subject_name(x509); + if (subjectName == NULL){ + WOLFSSL_MSG("invalid x509 data"); + return SSL_FAILURE; + } + + /* Alloc stack struct */ + node = (WOLF_STACK_OF(WOLFSSL_X509_NAME)*)XMALLOC( + sizeof(WOLF_STACK_OF(WOLFSSL_X509_NAME)), + NULL, DYNAMIC_TYPE_OPENSSL); + if (node == NULL){ + WOLFSSL_MSG("memory allocation error"); + return SSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509_NAME))); + + /* Alloc and copy WOLFSSL_X509_NAME */ + node->data.name = (WOLFSSL_X509_NAME*)XMALLOC( + sizeof(WOLFSSL_X509_NAME), + NULL, DYNAMIC_TYPE_OPENSSL); + if (node->data.name == NULL) { + XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); + WOLFSSL_MSG("memory allocation error"); + return SSL_FAILURE; + } + XMEMCPY(node->data.name, subjectName, sizeof(WOLFSSL_X509_NAME)); + XMEMSET(subjectName, 0, sizeof(WOLFSSL_X509_NAME)); + + /* push new node onto head of stack */ + node->num = (ctx->ca_names == NULL) ? 1 : ctx->ca_names->num + 1; + node->next = ctx->ca_names; + ctx->ca_names = node; + return SSL_SUCCESS; + } + #endif + + #ifndef NO_WOLFSSL_STUB + int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx) + { + /* TODO:, not needed in goahead */ + (void)ctx; + WOLFSSL_STUB("SSL_CTX_set_default_verify_paths"); + return SSL_NOT_IMPLEMENTED; + } + #endif + + #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ + && !defined(WC_NO_RNG) + static const byte srp_N[] = { + 0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, 0x9C, 0x33, 0xF8, + 0x0A, 0xFA, 0x8F, 0xC5, 0xE8, 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, + 0x3C, 0x0B, 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76, 0xD6, + 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, 0x38, 0x3B, 0x48, 0x13, + 0xD6, 0x92, 0xC6, 0xE0, 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, + 0xE4, 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1, 0x5D, 0xC7, + 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, 0xCE, 0x8E, 0xF4, 0xAD, 0x69, + 0xB1, 0x5D, 0x49, 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85, + 0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC, 0x68, 0xED, 0xBC, + 0x3C, 0x05, 0x72, 0x6C, 0xC0, 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E, + 0xAA, 0x9A, 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, 0x9F, + 0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3 + }; + static const byte srp_g[] = { + 0x02 + }; + + int wolfSSL_CTX_set_srp_username(WOLFSSL_CTX* ctx, char* username) + { + int r = 0; + SrpSide srp_side = SRP_CLIENT_SIDE; + WC_RNG rng; + byte salt[SRP_SALT_SIZE]; + + WOLFSSL_ENTER("wolfSSL_CTX_set_srp_username"); + if (ctx == NULL || ctx->srp == NULL || username==NULL) + return SSL_FAILURE; + + if (ctx->method->side == WOLFSSL_SERVER_END){ + srp_side = SRP_SERVER_SIDE; + } else if (ctx->method->side == WOLFSSL_CLIENT_END){ + srp_side = SRP_CLIENT_SIDE; + } else { + WOLFSSL_MSG("Init CTX failed"); + return SSL_FAILURE; + } + + if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0){ + WOLFSSL_MSG("Init CTX failed"); + XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP); + wolfSSL_CTX_free(ctx); + return SSL_FAILURE; + } + r = wc_SrpSetUsername(ctx->srp, (const byte*)username, + (word32)XSTRLEN(username)); + if (r < 0) { + WOLFSSL_MSG("fail to set srp username."); + return SSL_FAILURE; + } + + /* if wolfSSL_CTX_set_srp_password has already been called, */ + /* execute wc_SrpSetPassword here */ + if (ctx->srp_password != NULL){ + if (wc_InitRng(&rng) < 0){ + WOLFSSL_MSG("wc_InitRng failed"); + return SSL_FAILURE; + } + XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0])); + if (wc_RNG_GenerateBlock(&rng, salt, + sizeof(salt)/sizeof(salt[0])) < 0){ + WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); + wc_FreeRng(&rng); + return SSL_FAILURE; + } + if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]), + srp_g, sizeof(srp_g)/sizeof(srp_g[0]), + salt, sizeof(salt)/sizeof(salt[0])) < 0){ + WOLFSSL_MSG("wc_SrpSetParam failed"); + wc_FreeRng(&rng); + return SSL_FAILURE; + } + r = wc_SrpSetPassword(ctx->srp, + (const byte*)ctx->srp_password, + (word32)XSTRLEN((char *)ctx->srp_password)); + if (r < 0) { + WOLFSSL_MSG("fail to set srp password."); + return SSL_FAILURE; + } + wc_FreeRng(&rng); + XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP); + ctx->srp_password = NULL; + } + + return SSL_SUCCESS; + } + + int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password) + { + int r; + WC_RNG rng; + byte salt[SRP_SALT_SIZE]; + + WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password"); + if (ctx == NULL || ctx->srp == NULL || password == NULL) + return SSL_FAILURE; + + if (ctx->srp->user != NULL){ + if (wc_InitRng(&rng) < 0){ + WOLFSSL_MSG("wc_InitRng failed"); + return SSL_FAILURE; + } + XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0])); + if (wc_RNG_GenerateBlock(&rng, salt, + sizeof(salt)/sizeof(salt[0])) < 0){ + WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); + wc_FreeRng(&rng); + return SSL_FAILURE; + } + if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]), + srp_g, sizeof(srp_g)/sizeof(srp_g[0]), + salt, sizeof(salt)/sizeof(salt[0])) < 0){ + WOLFSSL_MSG("wc_SrpSetParam failed"); + wc_FreeRng(&rng); + return SSL_FAILURE; + } + r = wc_SrpSetPassword(ctx->srp, (const byte*)password, + (word32)XSTRLEN(password)); + if (r < 0) { + WOLFSSL_MSG("wc_SrpSetPassword failed."); + wc_FreeRng(&rng); + return SSL_FAILURE; + } + if (ctx->srp_password != NULL){ + XFREE(ctx->srp_password,NULL, + DYNAMIC_TYPE_SRP); + ctx->srp_password = NULL; + } + wc_FreeRng(&rng); + } else { + /* save password for wolfSSL_set_srp_username */ + if (ctx->srp_password != NULL) + XFREE(ctx->srp_password,ctx->heap, DYNAMIC_TYPE_SRP); + + ctx->srp_password = (byte*)XMALLOC(XSTRLEN(password) + 1, ctx->heap, + DYNAMIC_TYPE_SRP); + if (ctx->srp_password == NULL){ + WOLFSSL_MSG("memory allocation error"); + return SSL_FAILURE; + } + XMEMCPY(ctx->srp_password, password, XSTRLEN(password) + 1); + } + return SSL_SUCCESS; + } + #endif /* WOLFCRYPT_HAVE_SRP && !NO_SHA256 && !WC_NO_RNG */ + + /* keyblock size in bytes or -1 */ + int wolfSSL_get_keyblock_size(WOLFSSL* ssl) + { + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + return 2 * (ssl->specs.key_size + ssl->specs.iv_size + + ssl->specs.hash_size); + } + + + /* store keys returns WOLFSSL_SUCCESS or -1 on error */ + int wolfSSL_get_keys(WOLFSSL* ssl, unsigned char** ms, unsigned int* msLen, + unsigned char** sr, unsigned int* srLen, + unsigned char** cr, unsigned int* crLen) + { + if (ssl == NULL || ssl->arrays == NULL) + return WOLFSSL_FATAL_ERROR; + + *ms = ssl->arrays->masterSecret; + *sr = ssl->arrays->serverRandom; + *cr = ssl->arrays->clientRandom; + + *msLen = SECRET_LEN; + *srLen = RAN_LEN; + *crLen = RAN_LEN; + + return WOLFSSL_SUCCESS; + } + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) + void wolfSSL_set_accept_state(WOLFSSL* ssl) + { + WOLFSSL_ENTER("wolfSSL_set_accept_state"); + if (ssl->options.side == WOLFSSL_CLIENT_END) { + #ifdef HAVE_ECC + ecc_key key; + word32 idx = 0; + + if (ssl->options.haveStaticECC && ssl->buffers.key != NULL) { + if (wc_ecc_init(&key) >= 0) { + if (wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, &key, + ssl->buffers.key->length) != 0) { + ssl->options.haveECDSAsig = 0; + ssl->options.haveECC = 0; + ssl->options.haveStaticECC = 0; + } + wc_ecc_free(&key); + } + } + #endif + + #ifndef NO_DH + if (!ssl->options.haveDH && ssl->ctx->haveDH) { + ssl->buffers.serverDH_P = ssl->ctx->serverDH_P; + ssl->buffers.serverDH_G = ssl->ctx->serverDH_G; + ssl->options.haveDH = 1; + } + #endif + } + + if (InitSSL_Side(ssl, WOLFSSL_SERVER_END) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error initializing server side"); + } + } + +#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */ + + /* return true if connection established */ + int wolfSSL_is_init_finished(WOLFSSL* ssl) + { + if (ssl == NULL) + return 0; + + if (ssl->options.handShakeState == HANDSHAKE_DONE) + return 1; + + return 0; + } + +#ifdef OPENSSL_EXTRA + + void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX* ctx, + WOLFSSL_RSA*(*f)(WOLFSSL*, int, int)) + { + /* wolfSSL verifies all these internally */ + (void)ctx; + (void)f; + } + + + void wolfSSL_set_shutdown(WOLFSSL* ssl, int opt) + { + WOLFSSL_ENTER("wolfSSL_set_shutdown"); + if(ssl==NULL) { + WOLFSSL_MSG("Shutdown not set. ssl is null"); + return; + } + + ssl->options.sentNotify = (opt&WOLFSSL_SENT_SHUTDOWN) > 0; + ssl->options.closeNotify = (opt&WOLFSSL_RECEIVED_SHUTDOWN) > 0; + } + + + long wolfSSL_CTX_get_options(WOLFSSL_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_CTX_get_options"); + WOLFSSL_MSG("wolfSSL options are set through API calls and macros"); + if(ctx == NULL) + return BAD_FUNC_ARG; + return ctx->mask; + } + +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + + static long wolf_set_options(long old_op, long op); + long wolfSSL_CTX_set_options(WOLFSSL_CTX* ctx, long opt) + { + WOLFSSL_ENTER("SSL_CTX_set_options"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->mask = wolf_set_options(ctx->mask, opt); + + return ctx->mask; + } + +#endif + +#ifdef OPENSSL_EXTRA + + long wolfSSL_CTX_clear_options(WOLFSSL_CTX* ctx, long opt) + { + WOLFSSL_ENTER("SSL_CTX_clear_options"); + if(ctx == NULL) + return BAD_FUNC_ARG; + ctx->mask &= ~opt; + return ctx->mask; + } + + int wolfSSL_set_rfd(WOLFSSL* ssl, int rfd) + { + WOLFSSL_ENTER("SSL_set_rfd"); + ssl->rfd = rfd; /* not used directly to allow IO callbacks */ + + ssl->IOCB_ReadCtx = &ssl->rfd; + + return WOLFSSL_SUCCESS; + } + + + int wolfSSL_set_wfd(WOLFSSL* ssl, int wfd) + { + WOLFSSL_ENTER("SSL_set_wfd"); + ssl->wfd = wfd; /* not used directly to allow IO callbacks */ + + ssl->IOCB_WriteCtx = &ssl->wfd; + + return WOLFSSL_SUCCESS; + } + +#ifndef NO_CERTS + + WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(WOLFSSL_CTX* ctx) + { + if (ctx == NULL) { + return NULL; + } + + return &ctx->x509_store; + } + + void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) + { + if (ctx == NULL || str == NULL) { + return; + } + + /* free cert manager if have one */ + if (ctx->cm != NULL) { + wolfSSL_CertManagerFree(ctx->cm); + } + ctx->cm = str->cm; + + /* free existing store if it exists */ + if (ctx->x509_store_pt != NULL) { + /* cert manager was free'd a little earlier in this function */ + ctx->x509_store_pt->cm = NULL; + } + wolfSSL_X509_STORE_free(ctx->x509_store_pt); + ctx->x509_store.cache = str->cache; + ctx->x509_store_pt = str; /* take ownership of store and free it + with CTX free */ + } + + + WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get_current_cert( + WOLFSSL_X509_STORE_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_current_cert"); + if (ctx) + return ctx->current_cert; + return NULL; + } + + + int wolfSSL_X509_STORE_CTX_get_error(WOLFSSL_X509_STORE_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_error"); + if (ctx != NULL) + return ctx->error; + return 0; + } + + + int wolfSSL_X509_STORE_CTX_get_error_depth(WOLFSSL_X509_STORE_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_error_depth"); + if(ctx) + return ctx->error_depth; + return WOLFSSL_FATAL_ERROR; + } + + void wolfSSL_X509_STORE_CTX_set_verify_cb(WOLFSSL_X509_STORE_CTX *ctx, + WOLFSSL_X509_STORE_CTX_verify_cb verify_cb) + { + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_verify_cb"); + if(ctx == NULL) + return; + ctx->verify_cb = verify_cb; + } + +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + void wolfSSL_X509_STORE_set_verify_cb(WOLFSSL_X509_STORE *st, + WOLFSSL_X509_STORE_CTX_verify_cb verify_cb) + { + WOLFSSL_ENTER("WOLFSSL_X509_STORE_set_verify_cb"); + if (st != NULL) { + st->verify_cb = verify_cb; + } + } +#endif + + +#endif /* !NO_CERTS */ + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_md(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_f_md"); + meth.type = WOLFSSL_BIO_MD; + + return &meth; + } + + /* return the context and initialize the BIO state */ + int wolfSSL_BIO_get_md_ctx(WOLFSSL_BIO *bio, WOLFSSL_EVP_MD_CTX **mdcp) + { + int ret = WOLFSSL_FAILURE; + + if ((bio != NULL) && (mdcp != NULL)) { + *mdcp = (WOLFSSL_EVP_MD_CTX*)bio->ptr; + ret = WOLFSSL_SUCCESS; + } + + return ret; + } + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_buffer(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("BIO_f_buffer"); + meth.type = WOLFSSL_BIO_BUFFER; + + return &meth; + } + + #ifndef NO_WOLFSSL_STUB + long wolfSSL_BIO_set_write_buffer_size(WOLFSSL_BIO* bio, long size) + { + /* wolfSSL has internal buffer, compatibility only */ + WOLFSSL_ENTER("BIO_set_write_buffer_size"); + WOLFSSL_STUB("BIO_set_write_buffer_size"); + (void)bio; + return size; + } + #endif + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_bio(void) + { + static WOLFSSL_BIO_METHOD bio_meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_bio"); + bio_meth.type = WOLFSSL_BIO_BIO; + + return &bio_meth; + } + + +#ifndef NO_FILESYSTEM + WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_file(void) + { + static WOLFSSL_BIO_METHOD file_meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_file"); + file_meth.type = WOLFSSL_BIO_FILE; + + return &file_meth; + } +#endif + + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_ssl(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_f_ssl"); + meth.type = WOLFSSL_BIO_SSL; + + return &meth; + } + + + WOLFSSL_BIO_METHOD *wolfSSL_BIO_s_socket(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_socket"); + meth.type = WOLFSSL_BIO_SOCKET; + + return &meth; + } + + + WOLFSSL_BIO* wolfSSL_BIO_new_socket(int sfd, int closeF) + { + WOLFSSL_BIO* bio = wolfSSL_BIO_new(wolfSSL_BIO_s_socket()); + + WOLFSSL_ENTER("BIO_new_socket"); + if (bio) { + bio->type = WOLFSSL_BIO_SOCKET; + bio->shutdown = (byte)closeF; + bio->num = sfd; + } + return bio; + } + + + int wolfSSL_BIO_eof(WOLFSSL_BIO* b) + { + WOLFSSL_ENTER("BIO_eof"); + if ((b != NULL) && (b->eof)) + return 1; + + return 0; + } + + + long wolfSSL_BIO_set_ssl(WOLFSSL_BIO* b, WOLFSSL* ssl, int closeF) + { + WOLFSSL_ENTER("wolfSSL_BIO_set_ssl"); + + if (b != NULL) { + b->ptr = ssl; + b->shutdown = (byte)closeF; + /* add to ssl for bio free if SSL_free called before/instead of free_all? */ + } + + return 0; + } + +#ifndef NO_FILESYSTEM + long wolfSSL_BIO_set_fd(WOLFSSL_BIO* b, int fd, int closeF) + { + WOLFSSL_ENTER("wolfSSL_BIO_set_fd"); + + if (b != NULL) { + b->num = fd; + b->shutdown = (byte)closeF; + } + + return WOLFSSL_SUCCESS; + } +#endif + + /* Sets the close flag */ + int wolfSSL_BIO_set_close(WOLFSSL_BIO *b, long flag) + { + WOLFSSL_ENTER("wolfSSL_BIO_set_close"); + if (b != NULL) { + b->shutdown = (byte)flag; + } + + return WOLFSSL_SUCCESS; + } + + + WOLFSSL_BIO* wolfSSL_BIO_new(WOLFSSL_BIO_METHOD* method) + { + WOLFSSL_BIO* bio; + + WOLFSSL_ENTER("wolfSSL_BIO_new"); + if (method == NULL) { + WOLFSSL_MSG("Bad method pointer passed in"); + return NULL; + } + + bio = (WOLFSSL_BIO*) XMALLOC(sizeof(WOLFSSL_BIO), 0, + DYNAMIC_TYPE_OPENSSL); + if (bio) { + XMEMSET(bio, 0, sizeof(WOLFSSL_BIO)); + bio->type = (byte)method->type; + bio->method = method; + bio->shutdown = BIO_CLOSE; /* default to close things */ + bio->init = 1; + if (method->type != WOLFSSL_BIO_FILE && + method->type != WOLFSSL_BIO_SOCKET && + method->type != WOLFSSL_BIO_MD) { + bio->mem_buf =(WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), + 0, DYNAMIC_TYPE_OPENSSL); + if (bio->mem_buf == NULL) { + WOLFSSL_MSG("Memory error"); + wolfSSL_BIO_free(bio); + return NULL; + } + bio->mem_buf->data = (char*)bio->ptr; + } + + if (method->type == WOLFSSL_BIO_MD) { + bio->ptr = wolfSSL_EVP_MD_CTX_new(); + if (bio->ptr == NULL) { + WOLFSSL_MSG("Memory error"); + wolfSSL_BIO_free(bio); + return NULL; + } + } + + /* check if is custom method */ + if (method->createCb) { + method->createCb(bio); + } + } + return bio; + } + + WOLFSSL_BIO* wolfSSL_BIO_new_mem_buf(const void* buf, int len) + { + WOLFSSL_BIO* bio = NULL; + + if (buf == NULL || len < 0) { + return bio; + } + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); + if (bio == NULL) { + return bio; + } + + bio->num = bio->wrSz = len; + bio->ptr = (byte*)XMALLOC(len, 0, DYNAMIC_TYPE_OPENSSL); + if (bio->ptr == NULL) { + wolfSSL_BIO_free(bio); + return NULL; + } + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + + XMEMCPY(bio->ptr, buf, len); + + return bio; + } + + /* + * Note : If the flag BIO_NOCLOSE is set then freeing memory buffers is up + * to the application. + * Returns 1 on success, 0 on failure + */ + int wolfSSL_BIO_free(WOLFSSL_BIO* bio) + { + int ret; + + /* unchain?, doesn't matter in goahead since from free all */ + WOLFSSL_ENTER("wolfSSL_BIO_free"); + if (bio) { + + if (bio->infoCb) { + /* info callback is called before free */ + ret = (int)bio->infoCb(bio, WOLFSSL_BIO_CB_FREE, NULL, 0, 0, 1); + if (ret <= 0) { + return ret; + } + } + + /* call custom set free callback */ + if (bio->method && bio->method->freeCb) { + bio->method->freeCb(bio); + } + + /* remove from pair by setting the paired bios pair to NULL */ + if (bio->pair != NULL) { + bio->pair->pair = NULL; + } + + if (bio->shutdown) { + if (bio->type == WOLFSSL_BIO_SSL && bio->ptr) + wolfSSL_free((WOLFSSL*)bio->ptr); + #ifdef CloseSocket + if (bio->type == WOLFSSL_BIO_SOCKET && bio->num) + CloseSocket(bio->num); + #endif + } + + #ifndef NO_FILESYSTEM + if (bio->type == WOLFSSL_BIO_FILE && bio->shutdown == BIO_CLOSE) { + if (bio->ptr) { + XFCLOSE((XFILE)bio->ptr); + } + } + #endif + + if (bio->shutdown != BIO_NOCLOSE) { + if (bio->type == WOLFSSL_BIO_MEMORY && bio->ptr != NULL) { + if (bio->mem_buf != NULL) { + if (bio->mem_buf->data != (char*)bio->ptr) { + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = NULL; + } + } + else { + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = NULL; + } + } + if (bio->mem_buf != NULL) { + wolfSSL_BUF_MEM_free(bio->mem_buf); + bio->mem_buf = NULL; + } + } + + if (bio->type == WOLFSSL_BIO_MD) { + wolfSSL_EVP_MD_CTX_free((WOLFSSL_EVP_MD_CTX*)bio->ptr); + } + + XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL); + } + return 1; + } + + /* like BIO_free, but no return value */ + void wolfSSL_BIO_vfree(WOLFSSL_BIO* bio) + { + wolfSSL_BIO_free(bio); + } + + + int wolfSSL_BIO_free_all(WOLFSSL_BIO* bio) + { + WOLFSSL_ENTER("BIO_free_all"); + while (bio) { + WOLFSSL_BIO* next = bio->next; + wolfSSL_BIO_free(bio); + bio = next; + } + return 0; + } + + + WOLFSSL_BIO* wolfSSL_BIO_push(WOLFSSL_BIO* top, WOLFSSL_BIO* append) + { + WOLFSSL_ENTER("BIO_push"); + top->next = append; + append->prev = top; + + return top; + } +#endif /* OPENSSL_EXTRA */ + +#ifdef WOLFSSL_ENCRYPTED_KEYS + + void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx, + void* userdata) + { + WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb_userdata"); + if (ctx) + ctx->passwd_userdata = userdata; + } + + + void wolfSSL_CTX_set_default_passwd_cb(WOLFSSL_CTX* ctx,pem_password_cb* cb) + { + WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb"); + if (ctx) + ctx->passwd_cb = cb; + } + + pem_password_cb* wolfSSL_CTX_get_default_passwd_cb(WOLFSSL_CTX *ctx) + { + if (ctx == NULL || ctx->passwd_cb == NULL) { + return NULL; + } + + return ctx->passwd_cb; + } + + + void* wolfSSL_CTX_get_default_passwd_cb_userdata(WOLFSSL_CTX *ctx) + { + if (ctx == NULL) { + return NULL; + } + + return ctx->passwd_userdata; + } + +#endif /* WOLFSSL_ENCRYPTED_KEYS */ + + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + int wolfSSL_num_locks(void) + { + return 0; + } + + void wolfSSL_set_locking_callback(void (*f)(int, int, const char*, int)) + { + WOLFSSL_ENTER("wolfSSL_set_locking_callback"); + + if (wc_SetMutexCb(f) != 0) { + WOLFSSL_MSG("Error when setting mutex call back"); + } + } + + + typedef unsigned long (idCb)(void); + static idCb* inner_idCb = NULL; + + unsigned long wolfSSL_thread_id(void) + { + if (inner_idCb != NULL) { + return inner_idCb(); + } + else { + return 0; + } + } + + + void wolfSSL_set_id_callback(unsigned long (*f)(void)) + { + inner_idCb = f; + } + + unsigned long wolfSSL_ERR_get_error(void) + { + WOLFSSL_ENTER("wolfSSL_ERR_get_error"); + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + { + unsigned long ret = wolfSSL_ERR_peek_error_line_data(NULL, NULL, + NULL, NULL); + wc_RemoveErrorNode(-1); + return ret; + } +#elif (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) + { + int ret = wc_PullErrorNode(NULL, NULL, NULL); + + if (ret < 0) { + if (ret == BAD_STATE_E) return 0; /* no errors in queue */ + WOLFSSL_MSG("Error with pulling error node!"); + WOLFSSL_LEAVE("wolfSSL_ERR_get_error", ret); + ret = 0 - ret; /* return absolute value of error */ + + /* panic and try to clear out nodes */ + wc_ClearErrorNodes(); + } + + return (unsigned long)ret; + } +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif + } + +#if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) + /* print out and clear all errors */ + void wolfSSL_ERR_print_errors(WOLFSSL_BIO* bio) + { + const char* file = NULL; + const char* reason = NULL; + int ret; + int line = 0; + char buf[WOLFSSL_MAX_ERROR_SZ * 2]; + + WOLFSSL_ENTER("wolfSSL_ERR_print_errors"); + + if (bio == NULL) { + WOLFSSL_MSG("BIO passed in was null"); + return; + } + + do { + ret = wc_PeekErrorNode(0, &file, &reason, &line); + if (ret >= 0) { + const char* r = wolfSSL_ERR_reason_error_string(0 - ret); + XSNPRINTF(buf, sizeof(buf), "error:%d:wolfSSL library:%s:%s:%d\n", + ret, r, file, line); + wolfSSL_BIO_write(bio, buf, (int)XSTRLEN(buf)); + wc_RemoveErrorNode(0); + } + } while (ret >= 0); + } +#endif /* OPENSSL_EXTRA || DEBUG_WOLFSSL_VERBOSE */ + +#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ + +#ifdef OPENSSL_EXTRA + +#if !defined(NO_WOLFSSL_SERVER) +size_t wolfSSL_get_server_random(const WOLFSSL *ssl, unsigned char *out, + size_t outSz) +{ + size_t size; + + /* return max size of buffer */ + if (outSz == 0) { + return RAN_LEN; + } + + if (ssl == NULL || out == NULL) { + return 0; + } + + if (ssl->options.saveArrays == 0 || ssl->arrays == NULL) { + WOLFSSL_MSG("Arrays struct not saved after handshake"); + return 0; + } + + if (outSz > RAN_LEN) { + size = RAN_LEN; + } + else { + size = outSz; + } + + XMEMCPY(out, ssl->arrays->serverRandom, size); + return size; +} + + +/* Used to get the peer ephemeral public key sent during the connection + * NOTE: currently wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) must be called + * before the ephemeral key is stored. + * return WOLFSSL_SUCCESS on success */ +int wolfSSL_get_server_tmp_key(const WOLFSSL* ssl, WOLFSSL_EVP_PKEY** pkey) +{ + WOLFSSL_EVP_PKEY* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_get_server_tmp_key"); + + if (ssl == NULL || pkey == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return WOLFSSL_FAILURE; + } + +#ifdef HAVE_ECC + if (ssl->peerEccKey != NULL) { + unsigned char* der; + const unsigned char* pt; + unsigned int derSz = 0; + int sz; + + if (wc_ecc_export_x963(ssl->peerEccKey, NULL, &derSz) != + LENGTH_ONLY_E) { + WOLFSSL_MSG("get ecc der size failed"); + return WOLFSSL_FAILURE; + } + + derSz += MAX_SEQ_SZ + (2 * MAX_ALGO_SZ) + MAX_SEQ_SZ + TRAILING_ZERO; + der = (unsigned char*)XMALLOC(derSz, ssl->heap, DYNAMIC_TYPE_KEY); + if (der == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + + if ((sz = wc_EccPublicKeyToDer(ssl->peerEccKey, der, derSz, 1)) <= 0) { + WOLFSSL_MSG("get ecc der failed"); + XFREE(der, ssl->heap, DYNAMIC_TYPE_KEY); + return WOLFSSL_FAILURE; + } + pt = der; /* in case pointer gets advanced */ + ret = wolfSSL_d2i_PUBKEY(NULL, &pt, sz); + XFREE(der, ssl->heap, DYNAMIC_TYPE_KEY); + } +#endif + + *pkey = ret; + if (ret == NULL) + return WOLFSSL_FAILURE; + else + return WOLFSSL_SUCCESS; +} + +#endif /* !NO_WOLFSSL_SERVER */ + +int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version"); + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case SSL3_VERSION: + ctx->minDowngrade = SSLv3_MINOR; + break; +#endif +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case TLS1_VERSION: + ctx->minDowngrade = TLSv1_MINOR; + break; + #endif + case TLS1_1_VERSION: + ctx->minDowngrade = TLSv1_1_MINOR; + break; + #endif + #ifndef WOLFSSL_NO_TLS12 + case TLS1_2_VERSION: + ctx->minDowngrade = TLSv1_2_MINOR; + break; + #endif + #ifdef WOLFSSL_TLS13 + case TLS1_3_VERSION: + ctx->minDowngrade = TLSv1_3_MINOR; + break; + #endif +#endif +#ifdef WOLFSSL_DTLS + #ifndef NO_OLD_TLS + case DTLS1_VERSION: + ctx->minDowngrade = DTLS_MINOR; + break; + #endif + case DTLS1_2_VERSION: + ctx->minDowngrade = DTLSv1_2_MINOR; + break; +#endif + default: + return BAD_FUNC_ARG; + } + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int ver) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version"); + + /* supported only at compile-time only */ + (void)ctx; + (void)ver; + return WOLFSSL_SUCCESS; +} + + +#if !defined(NO_WOLFSSL_CLIENT) +/* Return the amount of random bytes copied over or error case. + * ssl : ssl struct after handshake + * out : buffer to hold random bytes + * outSz : either 0 (return max buffer sz) or size of out buffer + * + * NOTE: wolfSSL_KeepArrays(ssl) must be called to retain handshake information. + */ +size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, + size_t outSz) +{ + size_t size; + + /* return max size of buffer */ + if (outSz == 0) { + return RAN_LEN; + } + + if (ssl == NULL || out == NULL) { + return 0; + } + + if (ssl->options.saveArrays == 0 || ssl->arrays == NULL) { + WOLFSSL_MSG("Arrays struct not saved after handshake"); + return 0; + } + + if (outSz > RAN_LEN) { + size = RAN_LEN; + } + else { + size = outSz; + } + + XMEMCPY(out, ssl->arrays->clientRandom, size); + return size; +} +#endif /* !NO_WOLFSSL_CLIENT */ + + + unsigned long wolfSSLeay(void) + { + return SSLEAY_VERSION_NUMBER; + } + + unsigned long wolfSSL_OpenSSL_version_num(void) + { + return OPENSSL_VERSION_NUMBER; + } + + const char* wolfSSLeay_version(int type) + { + static const char* version = "SSLeay wolfSSL compatibility"; + (void)type; + return version; + } + + +#ifndef NO_MD5 + int wolfSSL_MD5_Init(WOLFSSL_MD5_CTX* md5) + { + int ret; + typedef char md5_test[sizeof(MD5_CTX) >= sizeof(wc_Md5) ? 1 : -1]; + (void)sizeof(md5_test); + + WOLFSSL_ENTER("MD5_Init"); + ret = wc_InitMd5((wc_Md5*)md5); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_MD5_Update(WOLFSSL_MD5_CTX* md5, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("wolfSSL_MD5_Update"); + ret = wc_Md5Update((wc_Md5*)md5, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_MD5_Final(byte* input, WOLFSSL_MD5_CTX* md5) + { + int ret; + + WOLFSSL_ENTER("MD5_Final"); + ret = wc_Md5Final((wc_Md5*)md5, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } +#endif /* !NO_MD5 */ + + +#ifndef NO_SHA + int wolfSSL_SHA_Init(WOLFSSL_SHA_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA_CTX) >= sizeof(wc_Sha) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA_Init"); + ret = wc_InitSha((wc_Sha*)sha); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA_Update(WOLFSSL_SHA_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA_Update"); + ret = wc_ShaUpdate((wc_Sha*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA_Final(byte* input, WOLFSSL_SHA_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA_Final"); + ret = wc_ShaFinal((wc_Sha*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA1_Init(WOLFSSL_SHA_CTX* sha) + { + WOLFSSL_ENTER("SHA1_Init"); + return SHA_Init(sha); + } + + + int wolfSSL_SHA1_Update(WOLFSSL_SHA_CTX* sha, const void* input, + unsigned long sz) + { + WOLFSSL_ENTER("SHA1_Update"); + return SHA_Update(sha, input, sz); + } + + + int wolfSSL_SHA1_Final(byte* input, WOLFSSL_SHA_CTX* sha) + { + WOLFSSL_ENTER("SHA1_Final"); + return SHA_Final(input, sha); + } +#endif /* !NO_SHA */ + +#ifdef WOLFSSL_SHA224 + + int wolfSSL_SHA224_Init(WOLFSSL_SHA224_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA224_CTX) >= sizeof(wc_Sha224) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA224_Init"); + ret = wc_InitSha224((wc_Sha224*)sha); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA224_Update(WOLFSSL_SHA224_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA224_Update"); + ret = wc_Sha224Update((wc_Sha224*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA224_Final(byte* input, WOLFSSL_SHA224_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA224_Final"); + ret = wc_Sha224Final((wc_Sha224*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + +#endif /* WOLFSSL_SHA224 */ + + + int wolfSSL_SHA256_Init(WOLFSSL_SHA256_CTX* sha256) + { + int ret; + + typedef char sha_test[sizeof(SHA256_CTX) >= sizeof(wc_Sha256) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA256_Init"); + ret = wc_InitSha256((wc_Sha256*)sha256); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA256_Update(WOLFSSL_SHA256_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA256_Update"); + ret = wc_Sha256Update((wc_Sha256*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA256_Final(byte* input, WOLFSSL_SHA256_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA256_Final"); + ret = wc_Sha256Final((wc_Sha256*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + +#ifdef WOLFSSL_SHA384 + + int wolfSSL_SHA384_Init(WOLFSSL_SHA384_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA384_CTX) >= sizeof(wc_Sha384) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA384_Init"); + ret = wc_InitSha384((wc_Sha384*)sha); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA384_Update(WOLFSSL_SHA384_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA384_Update"); + ret = wc_Sha384Update((wc_Sha384*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA384_Final(byte* input, WOLFSSL_SHA384_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA384_Final"); + ret = wc_Sha384Final((wc_Sha384*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + +#endif /* WOLFSSL_SHA384 */ + + +#ifdef WOLFSSL_SHA512 + + int wolfSSL_SHA512_Init(WOLFSSL_SHA512_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA512_CTX) >= sizeof(wc_Sha512) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA512_Init"); + ret = wc_InitSha512((wc_Sha512*)sha); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA512_Update(WOLFSSL_SHA512_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA512_Update"); + ret = wc_Sha512Update((wc_Sha512*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA512_Final(byte* input, WOLFSSL_SHA512_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA512_Final"); + ret = wc_Sha512Final((wc_Sha512*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + +#endif /* WOLFSSL_SHA512 */ + +#ifdef WOLFSSL_SHA3 +#ifndef WOLFSSL_NOSHA3_224 + + int wolfSSL_SHA3_224_Init(WOLFSSL_SHA3_224_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA3_224_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA3_224_Init"); + ret = wc_InitSha3_224((wc_Sha3*)sha, NULL, 0); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_224_Update(WOLFSSL_SHA3_224_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA3_224_Update"); + ret = wc_Sha3_224_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_224_Final(byte* input, WOLFSSL_SHA3_224_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA3_224_Final"); + ret = wc_Sha3_224_Final((wc_Sha3*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + +#endif /* WOLFSSL_NOSHA3_224 */ + + +#ifndef WOLFSSL_NOSHA3_256 + int wolfSSL_SHA3_256_Init(WOLFSSL_SHA3_256_CTX* sha3_256) + { + int ret; + + typedef char sha_test[sizeof(SHA3_256_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA3_256_Init"); + ret = wc_InitSha3_256((wc_Sha3*)sha3_256, NULL, 0); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_256_Update(WOLFSSL_SHA3_256_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA3_256_Update"); + ret = wc_Sha3_256_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_256_Final(byte* input, WOLFSSL_SHA3_256_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA3_256_Final"); + ret = wc_Sha3_256_Final((wc_Sha3*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } +#endif /* WOLFSSL_NOSHA3_256 */ + + + int wolfSSL_SHA3_384_Init(WOLFSSL_SHA3_384_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA3_384_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA3_384_Init"); + ret = wc_InitSha3_384((wc_Sha3*)sha, NULL, 0); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_384_Update(WOLFSSL_SHA3_384_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA3_384_Update"); + ret = wc_Sha3_384_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_384_Final(byte* input, WOLFSSL_SHA3_384_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA3_384_Final"); + ret = wc_Sha3_384_Final((wc_Sha3*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + +#ifndef WOLFSSL_NOSHA3_512 + + int wolfSSL_SHA3_512_Init(WOLFSSL_SHA3_512_CTX* sha) + { + int ret; + + typedef char sha_test[sizeof(SHA3_512_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; + (void)sizeof(sha_test); + + WOLFSSL_ENTER("SHA3_512_Init"); + ret = wc_InitSha3_512((wc_Sha3*)sha, NULL, 0); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_512_Update(WOLFSSL_SHA3_512_CTX* sha, const void* input, + unsigned long sz) + { + int ret; + + WOLFSSL_ENTER("SHA3_512_Update"); + ret = wc_Sha3_512_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + + + int wolfSSL_SHA3_512_Final(byte* input, WOLFSSL_SHA3_512_CTX* sha) + { + int ret; + + WOLFSSL_ENTER("SHA3_512_Final"); + ret = wc_Sha3_512_Final((wc_Sha3*)sha, input); + + /* return 1 on success, 0 otherwise */ + if (ret == 0) + return 1; + + return 0; + } + +#endif /* WOLFSSL_NOSHA3_512 */ +#endif /* WOLFSSL_SHA3 */ + + /* store for external read of iv, WOLFSSL_SUCCESS on success */ + int wolfSSL_StoreExternalIV(WOLFSSL_EVP_CIPHER_CTX* ctx) + { + WOLFSSL_ENTER("wolfSSL_StoreExternalIV"); + + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); + return WOLFSSL_FATAL_ERROR; + } + + switch (ctx->cipherType) { + +#ifndef NO_AES +#ifdef HAVE_AES_CBC + case AES_128_CBC_TYPE : + case AES_192_CBC_TYPE : + case AES_256_CBC_TYPE : + WOLFSSL_MSG("AES CBC"); + XMEMCPY(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); + break; +#endif +#ifdef HAVE_AESGCM + case AES_128_GCM_TYPE : + case AES_192_GCM_TYPE : + case AES_256_GCM_TYPE : + WOLFSSL_MSG("AES GCM"); + XMEMCPY(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); + break; +#endif /* HAVE_AESGCM */ +#ifdef HAVE_AES_ECB + case AES_128_ECB_TYPE : + case AES_192_ECB_TYPE : + case AES_256_ECB_TYPE : + WOLFSSL_MSG("AES ECB"); + break; +#endif +#ifdef WOLFSSL_AES_COUNTER + case AES_128_CTR_TYPE : + case AES_192_CTR_TYPE : + case AES_256_CTR_TYPE : + WOLFSSL_MSG("AES CTR"); + XMEMCPY(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); + break; +#endif /* WOLFSSL_AES_COUNTER */ +#ifdef WOLFSSL_AES_CFB +#if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) + case AES_128_CFB1_TYPE: + case AES_192_CFB1_TYPE: + case AES_256_CFB1_TYPE: + WOLFSSL_MSG("AES CFB1"); + break; + case AES_128_CFB8_TYPE: + case AES_192_CFB8_TYPE: + case AES_256_CFB8_TYPE: + WOLFSSL_MSG("AES CFB8"); + break; +#endif /* !HAVE_SELFTEST && !HAVE_FIPS */ + case AES_128_CFB128_TYPE: + case AES_192_CFB128_TYPE: + case AES_256_CFB128_TYPE: + WOLFSSL_MSG("AES CFB128"); + break; +#endif /* WOLFSSL_AES_CFB */ +#if defined(WOLFSSL_AES_OFB) + case AES_128_OFB_TYPE: + case AES_192_OFB_TYPE: + case AES_256_OFB_TYPE: + WOLFSSL_MSG("AES OFB"); + break; +#endif /* WOLFSSL_AES_OFB */ +#ifdef WOLFSSL_AES_XTS + case AES_128_XTS_TYPE: + case AES_256_XTS_TYPE: + WOLFSSL_MSG("AES XTS"); + break; +#endif /* WOLFSSL_AES_XTS */ +#endif /* NO_AES */ + +#ifndef NO_DES3 + case DES_CBC_TYPE : + WOLFSSL_MSG("DES CBC"); + XMEMCPY(ctx->iv, &ctx->cipher.des.reg, DES_BLOCK_SIZE); + break; + + case DES_EDE3_CBC_TYPE : + WOLFSSL_MSG("DES EDE3 CBC"); + XMEMCPY(ctx->iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE); + break; +#endif +#ifdef WOLFSSL_DES_ECB + case DES_ECB_TYPE : + WOLFSSL_MSG("DES ECB"); + break; + case DES_EDE3_ECB_TYPE : + WOLFSSL_MSG("DES3 ECB"); + break; +#endif + +#ifdef HAVE_IDEA + case IDEA_CBC_TYPE : + WOLFSSL_MSG("IDEA CBC"); + XMEMCPY(ctx->iv, &ctx->cipher.idea.reg, IDEA_BLOCK_SIZE); + break; +#endif + case ARC4_TYPE : + WOLFSSL_MSG("ARC4"); + break; + + case NULL_CIPHER_TYPE : + WOLFSSL_MSG("NULL"); + break; + + default: { + WOLFSSL_MSG("bad type"); + return WOLFSSL_FATAL_ERROR; + } + } + return WOLFSSL_SUCCESS; + } + + /* set internal IV from external, WOLFSSL_SUCCESS on success */ + int wolfSSL_SetInternalIV(WOLFSSL_EVP_CIPHER_CTX* ctx) + { + + WOLFSSL_ENTER("wolfSSL_SetInternalIV"); + + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); + return WOLFSSL_FATAL_ERROR; + } + + switch (ctx->cipherType) { + +#ifndef NO_AES +#ifdef HAVE_AES_CBC + case AES_128_CBC_TYPE : + case AES_192_CBC_TYPE : + case AES_256_CBC_TYPE : + WOLFSSL_MSG("AES CBC"); + XMEMCPY(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE); + break; +#endif +#ifdef HAVE_AESGCM + case AES_128_GCM_TYPE : + case AES_192_GCM_TYPE : + case AES_256_GCM_TYPE : + WOLFSSL_MSG("AES GCM"); + XMEMCPY(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE); + break; +#endif +#ifdef HAVE_AES_ECB + case AES_128_ECB_TYPE : + case AES_192_ECB_TYPE : + case AES_256_ECB_TYPE : + WOLFSSL_MSG("AES ECB"); + break; +#endif +#ifdef WOLFSSL_AES_COUNTER + case AES_128_CTR_TYPE : + case AES_192_CTR_TYPE : + case AES_256_CTR_TYPE : + WOLFSSL_MSG("AES CTR"); + XMEMCPY(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE); + break; +#endif + +#endif /* NO_AES */ + +#ifndef NO_DES3 + case DES_CBC_TYPE : + WOLFSSL_MSG("DES CBC"); + XMEMCPY(&ctx->cipher.des.reg, ctx->iv, DES_BLOCK_SIZE); + break; + + case DES_EDE3_CBC_TYPE : + WOLFSSL_MSG("DES EDE3 CBC"); + XMEMCPY(&ctx->cipher.des3.reg, ctx->iv, DES_BLOCK_SIZE); + break; +#endif +#ifdef WOLFSSL_DES_ECB + case DES_ECB_TYPE : + WOLFSSL_MSG("DES ECB"); + break; + case DES_EDE3_ECB_TYPE : + WOLFSSL_MSG("DES3 ECB"); + break; +#endif + +#ifdef HAVE_IDEA + case IDEA_CBC_TYPE : + WOLFSSL_MSG("IDEA CBC"); + XMEMCPY(&ctx->cipher.idea.reg, ctx->iv, IDEA_BLOCK_SIZE); + break; +#endif + case ARC4_TYPE : + WOLFSSL_MSG("ARC4"); + break; + + case NULL_CIPHER_TYPE : + WOLFSSL_MSG("NULL"); + break; + + default: { + WOLFSSL_MSG("bad type"); + return WOLFSSL_FATAL_ERROR; + } + } + return WOLFSSL_SUCCESS; + } + + unsigned char* wolfSSL_HMAC(const WOLFSSL_EVP_MD* evp_md, const void* key, + int key_len, const unsigned char* d, int n, + unsigned char* md, unsigned int* md_len) + { + int type; + int mdlen; + unsigned char* ret = NULL; +#ifdef WOLFSSL_SMALL_STACK + Hmac* hmac = NULL; +#else + Hmac hmac[1]; +#endif + void* heap = NULL; + + WOLFSSL_ENTER("wolfSSL_HMAC"); + if (!md) { + WOLFSSL_MSG("Static buffer not supported, pass in md buffer"); + return NULL; /* no static buffer support */ + } + +#ifndef NO_MD5 + if (XSTRNCMP(evp_md, "MD5", 3) == 0) { + type = WC_MD5; + mdlen = WC_MD5_DIGEST_SIZE; + } else +#endif +#ifdef WOLFSSL_SHA224 + if (XSTRNCMP(evp_md, "SHA224", 6) == 0) { + type = WC_SHA224; + mdlen = WC_SHA224_DIGEST_SIZE; + } else +#endif +#ifndef NO_SHA256 + if (XSTRNCMP(evp_md, "SHA256", 6) == 0) { + type = WC_SHA256; + mdlen = WC_SHA256_DIGEST_SIZE; + } else +#endif +#ifdef WOLFSSL_SHA384 + if (XSTRNCMP(evp_md, "SHA384", 6) == 0) { + type = WC_SHA384; + mdlen = WC_SHA384_DIGEST_SIZE; + } else +#endif +#ifdef WOLFSSL_SHA512 + if (XSTRNCMP(evp_md, "SHA512", 6) == 0) { + type = WC_SHA512; + mdlen = WC_SHA512_DIGEST_SIZE; + } else +#endif +#ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_224 + if (XSTRNCMP(evp_md, "SHA3_224", 8) == 0) { + type = WC_SHA3_224; + mdlen = WC_SHA3_224_DIGEST_SIZE; + } else + #endif + #ifndef WOLFSSL_NOSHA3_256 + if (XSTRNCMP(evp_md, "SHA3_256", 8) == 0) { + type = WC_SHA3_256; + mdlen = WC_SHA3_256_DIGEST_SIZE; + } else + #endif + if (XSTRNCMP(evp_md, "SHA3_384", 8) == 0) { + type = WC_SHA3_384; + mdlen = WC_SHA3_384_DIGEST_SIZE; + } else + #ifndef WOLFSSL_NOSHA3_512 + if (XSTRNCMP(evp_md, "SHA3_512", 8) == 0) { + type = WC_SHA3_512; + mdlen = WC_SHA3_512_DIGEST_SIZE; + } else + #endif +#endif +#ifndef NO_SHA + if (XSTRNCMP(evp_md, "SHA", 3) == 0) { + type = WC_SHA; + mdlen = WC_SHA_DIGEST_SIZE; + } else +#endif + { + return NULL; + } + + #ifdef WOLFSSL_SMALL_STACK + hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, DYNAMIC_TYPE_HMAC); + if (hmac == NULL) + return NULL; + #endif + + if (wc_HmacInit(hmac, heap, INVALID_DEVID) == 0) { + if (wc_HmacSetKey(hmac, type, (const byte*)key, key_len) == 0) { + if (wc_HmacUpdate(hmac, d, n) == 0) { + if (wc_HmacFinal(hmac, md) == 0) { + if (md_len) + *md_len = mdlen; + ret = md; + } + } + } + wc_HmacFree(hmac); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); + #endif + + (void)evp_md; + return ret; + } + + void wolfSSL_ERR_clear_error(void) + { + WOLFSSL_ENTER("wolfSSL_ERR_clear_error"); + +#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_NGINX) || \ + defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) + wc_ClearErrorNodes(); +#endif + } + + + int wolfSSL_RAND_status(void) + { + return WOLFSSL_SUCCESS; /* wolfCrypt provides enough seed internally */ + } + + + #ifndef NO_WOLFSSL_STUB + void wolfSSL_RAND_add(const void* add, int len, double entropy) + { + (void)add; + (void)len; + (void)entropy; + WOLFSSL_STUB("RAND_add"); + /* wolfSSL seeds/adds internally, use explicit RNG if you want + to take control */ + } + #endif + +#ifndef NO_DES3 + /* 0 on ok */ + int wolfSSL_DES_key_sched(WOLFSSL_const_DES_cblock* key, + WOLFSSL_DES_key_schedule* schedule) + { + WOLFSSL_ENTER("wolfSSL_DES_key_sched"); + + if (key == NULL || schedule == NULL) { + WOLFSSL_MSG("Null argument passed in"); + } + else { + XMEMCPY(schedule, key, sizeof(WOLFSSL_const_DES_cblock)); + } + + return 0; + } + + + /* intended to behave similar to Kerberos mit_des_cbc_cksum + * return the last 4 bytes of cipher text */ + WOLFSSL_DES_LONG wolfSSL_DES_cbc_cksum(const unsigned char* in, + WOLFSSL_DES_cblock* out, long length, WOLFSSL_DES_key_schedule* sc, + WOLFSSL_const_DES_cblock* iv) + { + WOLFSSL_DES_LONG ret; + unsigned char* tmp; + unsigned char* data = (unsigned char*)in; + long dataSz = length; + byte dynamicFlag = 0; /* when padding the buffer created needs free'd */ + + WOLFSSL_ENTER("wolfSSL_DES_cbc_cksum"); + + if (in == NULL || out == NULL || sc == NULL || iv == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return 0; + } + + /* if input length is not a multiple of DES_BLOCK_SIZE pad with 0s */ + if (dataSz % DES_BLOCK_SIZE) { + dataSz += DES_BLOCK_SIZE - (dataSz % DES_BLOCK_SIZE); + data = (unsigned char*)XMALLOC(dataSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (data == NULL) { + WOLFSSL_MSG("Issue creating temporary buffer"); + return 0; + } + dynamicFlag = 1; /* set to free buffer at end */ + XMEMCPY(data, in, length); + XMEMSET(data + length, 0, dataSz - length); /* padding */ + } + + tmp = (unsigned char*)XMALLOC(dataSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + WOLFSSL_MSG("Issue creating temporary buffer"); + if (dynamicFlag == 1) { + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + return 0; + } + + wolfSSL_DES_cbc_encrypt(data, tmp, dataSz, sc, + (WOLFSSL_DES_cblock*)iv, 1); + XMEMCPY((unsigned char*)out, tmp + (dataSz - DES_BLOCK_SIZE), + DES_BLOCK_SIZE); + + ret = (((*((unsigned char*)out + 4) & 0xFF) << 24)| + ((*((unsigned char*)out + 5) & 0xFF) << 16)| + ((*((unsigned char*)out + 6) & 0xFF) << 8) | + (*((unsigned char*)out + 7) & 0xFF)); + + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (dynamicFlag == 1) { + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + return ret; + } + + + void wolfSSL_DES_cbc_encrypt(const unsigned char* input, + unsigned char* output, long length, + WOLFSSL_DES_key_schedule* schedule, + WOLFSSL_DES_cblock* ivec, int enc) + { + Des myDes; + byte lastblock[DES_BLOCK_SIZE]; + int lb_sz; + long blk; + + WOLFSSL_ENTER("DES_cbc_encrypt"); + + /* OpenSSL compat, no ret */ + wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc); + lb_sz = length%DES_BLOCK_SIZE; + blk = length/DES_BLOCK_SIZE; + + if (enc){ + wc_Des_CbcEncrypt(&myDes, output, input, (word32)blk*DES_BLOCK_SIZE); + if(lb_sz){ + XMEMSET(lastblock, 0, DES_BLOCK_SIZE); + XMEMCPY(lastblock, input+length-lb_sz, lb_sz); + wc_Des_CbcEncrypt(&myDes, output+blk*DES_BLOCK_SIZE, + lastblock, (word32)DES_BLOCK_SIZE); + } + } + else { + wc_Des_CbcDecrypt(&myDes, output, input, (word32)blk*DES_BLOCK_SIZE); + if(lb_sz){ + wc_Des_CbcDecrypt(&myDes, lastblock, input+length-lb_sz, (word32)DES_BLOCK_SIZE); + XMEMCPY(output+length-lb_sz, lastblock, lb_sz); + } + } + } + + + /* WOLFSSL_DES_key_schedule is a unsigned char array of size 8 */ + void wolfSSL_DES_ede3_cbc_encrypt(const unsigned char* input, + unsigned char* output, long sz, + WOLFSSL_DES_key_schedule* ks1, + WOLFSSL_DES_key_schedule* ks2, + WOLFSSL_DES_key_schedule* ks3, + WOLFSSL_DES_cblock* ivec, int enc) + { + int ret; + Des3 des; + byte key[24];/* EDE uses 24 size key */ + byte lastblock[DES_BLOCK_SIZE]; + int lb_sz; + long blk; + + WOLFSSL_ENTER("wolfSSL_DES_ede3_cbc_encrypt"); + + XMEMSET(key, 0, sizeof(key)); + XMEMCPY(key, *ks1, DES_BLOCK_SIZE); + XMEMCPY(&key[DES_BLOCK_SIZE], *ks2, DES_BLOCK_SIZE); + XMEMCPY(&key[DES_BLOCK_SIZE * 2], *ks3, DES_BLOCK_SIZE); + lb_sz = sz%DES_BLOCK_SIZE; + blk = sz/DES_BLOCK_SIZE; + + /* OpenSSL compat, no ret */ + (void)wc_Des3Init(&des, NULL, INVALID_DEVID); + + if (enc) { + wc_Des3_SetKey(&des, key, (const byte*)ivec, DES_ENCRYPTION); + ret = wc_Des3_CbcEncrypt(&des, output, input, (word32)blk*DES_BLOCK_SIZE); + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); + #endif + (void)ret; /* ignore return codes for processing */ + if(lb_sz){ + XMEMSET(lastblock, 0, DES_BLOCK_SIZE); + XMEMCPY(lastblock, input+sz-lb_sz, lb_sz); + ret = wc_Des3_CbcEncrypt(&des, output+blk*DES_BLOCK_SIZE, + lastblock, (word32)DES_BLOCK_SIZE); + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); + #endif + (void)ret; /* ignore return codes for processing */ + } + } + else { + wc_Des3_SetKey(&des, key, (const byte*)ivec, DES_DECRYPTION); + ret = wc_Des3_CbcDecrypt(&des, output, input, (word32)blk*DES_BLOCK_SIZE); + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); + #endif + (void)ret; /* ignore return codes for processing */ + if(lb_sz){ + ret = wc_Des3_CbcDecrypt(&des, lastblock, input+sz-lb_sz, (word32)DES_BLOCK_SIZE); + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); + #endif + (void)ret; /* ignore return codes for processing */ + XMEMCPY(output+sz-lb_sz, lastblock, lb_sz); + } + } + wc_Des3Free(&des); + } + + + /* correctly sets ivec for next call */ + void wolfSSL_DES_ncbc_encrypt(const unsigned char* input, + unsigned char* output, long length, + WOLFSSL_DES_key_schedule* schedule, WOLFSSL_DES_cblock* ivec, + int enc) + { + Des myDes; + byte lastblock[DES_BLOCK_SIZE]; + int lb_sz; + long idx = length; + long blk; + + WOLFSSL_ENTER("DES_ncbc_encrypt"); + + /* OpenSSL compat, no ret */ + wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc); + lb_sz = length%DES_BLOCK_SIZE; + blk = length/DES_BLOCK_SIZE; + idx -= sizeof(DES_cblock); + if (lb_sz) { + idx += DES_BLOCK_SIZE - lb_sz; + } + if (enc){ + wc_Des_CbcEncrypt(&myDes, output, input, + (word32)blk * DES_BLOCK_SIZE); + if (lb_sz){ + XMEMSET(lastblock, 0, DES_BLOCK_SIZE); + XMEMCPY(lastblock, input+length-lb_sz, lb_sz); + wc_Des_CbcEncrypt(&myDes, output + blk * DES_BLOCK_SIZE, + lastblock, (word32)DES_BLOCK_SIZE); + } + XMEMCPY(ivec, output + idx, sizeof(DES_cblock)); + } else { + WOLFSSL_DES_cblock tmp; + XMEMCPY(tmp, input + idx, sizeof(DES_cblock)); + wc_Des_CbcDecrypt(&myDes, output, input, + (word32)blk * DES_BLOCK_SIZE); + if (lb_sz){ + wc_Des_CbcDecrypt(&myDes, lastblock, input + length - lb_sz, + (word32)DES_BLOCK_SIZE); + XMEMCPY(output+length-lb_sz, lastblock, lb_sz); + } + XMEMCPY(ivec, tmp, sizeof(WOLFSSL_DES_cblock)); + } + + } + +#endif /* NO_DES3 */ + + void wolfSSL_ERR_free_strings(void) + { + /* handled internally */ + } + + void wolfSSL_cleanup_all_ex_data(void) + { + /* nothing to do here */ + } + + int wolfSSL_clear(WOLFSSL* ssl) + { + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + + ssl->options.isClosed = 0; + ssl->options.connReset = 0; + ssl->options.sentNotify = 0; + ssl->options.sendVerify = 0; + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN; + ssl->options.handShakeState = NULL_STATE; + ssl->options.handShakeDone = 0; + /* ssl->options.processReply = doProcessInit; */ + + ssl->keys.encryptionOn = 0; + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + + if (ssl->hsHashes != NULL) { +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + if (wc_InitMd5_ex(&ssl->hsHashes->hashMd5, ssl->heap, + ssl->devId) != 0) { + return WOLFSSL_FAILURE; + } + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Md5SetFlags(&ssl->hsHashes->hashMd5, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#ifndef NO_SHA + if (wc_InitSha_ex(&ssl->hsHashes->hashSha, ssl->heap, + ssl->devId) != 0) { + return WOLFSSL_FAILURE; + } + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_ShaSetFlags(&ssl->hsHashes->hashSha, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#endif +#ifndef NO_SHA256 + if (wc_InitSha256_ex(&ssl->hsHashes->hashSha256, ssl->heap, + ssl->devId) != 0) { + return WOLFSSL_FAILURE; + } + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Sha256SetFlags(&ssl->hsHashes->hashSha256, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#ifdef WOLFSSL_SHA384 + if (wc_InitSha384_ex(&ssl->hsHashes->hashSha384, ssl->heap, + ssl->devId) != 0) { + return WOLFSSL_FAILURE; + } + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Sha384SetFlags(&ssl->hsHashes->hashSha384, WC_HASH_FLAG_WILLCOPY); + #endif +#endif +#ifdef WOLFSSL_SHA512 + if (wc_InitSha512_ex(&ssl->hsHashes->hashSha512, ssl->heap, + ssl->devId) != 0) { + return WOLFSSL_FAILURE; + } + #if defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB) + wc_Sha512SetFlags(&ssl->hsHashes->hashSha512, WC_HASH_FLAG_WILLCOPY); + #endif +#endif + } +#ifdef SESSION_CERTS + ssl->session.chain.count = 0; +#endif +#ifdef KEEP_PEER_CERT + FreeX509(&ssl->peerCert); + InitX509(&ssl->peerCert, 0, ssl->heap); +#endif + + return WOLFSSL_SUCCESS; + } + + long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t) + { + word32 tmptime; + if (!ses || t < 0) + return BAD_FUNC_ARG; + + tmptime = t & 0xFFFFFFFF; + + ses->timeout = tmptime; + + return WOLFSSL_SUCCESS; + } + +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + long wolfSSL_CTX_set_mode(WOLFSSL_CTX* ctx, long mode) + { + /* WOLFSSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is wolfSSL default mode */ + + WOLFSSL_ENTER("SSL_CTX_set_mode"); + switch(mode) { + case SSL_MODE_ENABLE_PARTIAL_WRITE: + ctx->partialWrite = 1; + break; + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + case SSL_MODE_RELEASE_BUFFERS: + WOLFSSL_MSG("SSL_MODE_RELEASE_BUFFERS not implemented."); + break; + #endif + default: + WOLFSSL_MSG("Mode Not Implemented"); + } + + /* SSL_MODE_AUTO_RETRY + * Should not return -1 with renegotiation on read/write */ + + return mode; + } +#endif + +#ifdef OPENSSL_EXTRA + + #ifndef NO_WOLFSSL_STUB + long wolfSSL_SSL_get_mode(WOLFSSL* ssl) + { + /* TODO: */ + (void)ssl; + WOLFSSL_STUB("SSL_get_mode"); + return 0; + } + #endif + + #ifndef NO_WOLFSSL_STUB + long wolfSSL_CTX_get_mode(WOLFSSL_CTX* ctx) + { + /* TODO: */ + (void)ctx; + WOLFSSL_STUB("SSL_CTX_get_mode"); + return 0; + } + #endif + + #ifndef NO_WOLFSSL_STUB + void wolfSSL_CTX_set_default_read_ahead(WOLFSSL_CTX* ctx, int m) + { + /* TODO: maybe? */ + (void)ctx; + (void)m; + WOLFSSL_STUB("SSL_CTX_set_default_read_ahead"); + } + #endif + + + /* Storing app session context id, this value is inherited by WOLFSSL + * objects created from WOLFSSL_CTX. Any session that is imported with a + * different session context id will be rejected. + * + * ctx structure to set context in + * sid_ctx value of context to set + * sid_ctx_len length of sid_ctx buffer + * + * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing + */ + int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx, + const unsigned char* sid_ctx, + unsigned int sid_ctx_len) + { + WOLFSSL_ENTER("SSL_CTX_set_session_id_context"); + + /* No application specific context needed for wolfSSL */ + if (sid_ctx_len > ID_LEN || ctx == NULL || sid_ctx == NULL) { + return SSL_FAILURE; + } + XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len); + ctx->sessionCtxSz = (byte)sid_ctx_len; + + return SSL_SUCCESS; + } + + + + /* Storing app session context id. Any session that is imported with a + * different session context id will be rejected. + * + * ssl structure to set context in + * id value of context to set + * len length of sid_ctx buffer + * + * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing + */ + int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id, + unsigned int len) + { + WOLFSSL_ENTER("wolfSSL_set_session_id_context"); + + if (len > ID_LEN || ssl == NULL || id == NULL) { + return SSL_FAILURE; + } + XMEMCPY(ssl->sessionCtx, id, len); + ssl->sessionCtxSz = (byte)len; + + return SSL_SUCCESS; + } + + + long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX* ctx) + { + (void)ctx; + #ifndef NO_SESSION_CACHE + return (long)(SESSIONS_PER_ROW * SESSION_ROWS); + #else + return 0; + #endif + } + + + /* returns the unsigned error value and increments the pointer into the + * error queue. + * + * file pointer to file name + * line gets set to line number of error when not NULL + */ + unsigned long wolfSSL_ERR_get_error_line(const char** file, int* line) + { + #ifdef DEBUG_WOLFSSL + int ret = wc_PullErrorNode(file, NULL, line); + if (ret < 0) { + if (ret == BAD_STATE_E) return 0; /* no errors in queue */ + WOLFSSL_MSG("Issue getting error node"); + WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line", ret); + ret = 0 - ret; /* return absolute value of error */ + + /* panic and try to clear out nodes */ + wc_ClearErrorNodes(); + } + return (unsigned long)ret; + #else + (void)file; + (void)line; + + return 0; + #endif + } + + +#if (defined(DEBUG_WOLFSSL) || defined(OPENSSL_EXTRA)) && \ + (!defined(_WIN32) && !defined(NO_ERROR_QUEUE)) + static const char WOLFSSL_SYS_ACCEPT_T[] = "accept"; + static const char WOLFSSL_SYS_BIND_T[] = "bind"; + static const char WOLFSSL_SYS_CONNECT_T[] = "connect"; + static const char WOLFSSL_SYS_FOPEN_T[] = "fopen"; + static const char WOLFSSL_SYS_FREAD_T[] = "fread"; + static const char WOLFSSL_SYS_GETADDRINFO_T[] = "getaddrinfo"; + static const char WOLFSSL_SYS_GETSOCKOPT_T[] = "getsockopt"; + static const char WOLFSSL_SYS_GETSOCKNAME_T[] = "getsockname"; + static const char WOLFSSL_SYS_GETHOSTBYNAME_T[] = "gethostbyname"; + static const char WOLFSSL_SYS_GETNAMEINFO_T[] = "getnameinfo"; + static const char WOLFSSL_SYS_GETSERVBYNAME_T[] = "getservbyname"; + static const char WOLFSSL_SYS_IOCTLSOCKET_T[] = "ioctlsocket"; + static const char WOLFSSL_SYS_LISTEN_T[] = "listen"; + static const char WOLFSSL_SYS_OPENDIR_T[] = "opendir"; + static const char WOLFSSL_SYS_SETSOCKOPT_T[] = "setsockopt"; + static const char WOLFSSL_SYS_SOCKET_T[] = "socket"; + + /* switch with int mapped to function name for compatibility */ + static const char* wolfSSL_ERR_sys_func(int fun) + { + switch (fun) { + case WOLFSSL_SYS_ACCEPT: return WOLFSSL_SYS_ACCEPT_T; + case WOLFSSL_SYS_BIND: return WOLFSSL_SYS_BIND_T; + case WOLFSSL_SYS_CONNECT: return WOLFSSL_SYS_CONNECT_T; + case WOLFSSL_SYS_FOPEN: return WOLFSSL_SYS_FOPEN_T; + case WOLFSSL_SYS_FREAD: return WOLFSSL_SYS_FREAD_T; + case WOLFSSL_SYS_GETADDRINFO: return WOLFSSL_SYS_GETADDRINFO_T; + case WOLFSSL_SYS_GETSOCKOPT: return WOLFSSL_SYS_GETSOCKOPT_T; + case WOLFSSL_SYS_GETSOCKNAME: return WOLFSSL_SYS_GETSOCKNAME_T; + case WOLFSSL_SYS_GETHOSTBYNAME: return WOLFSSL_SYS_GETHOSTBYNAME_T; + case WOLFSSL_SYS_GETNAMEINFO: return WOLFSSL_SYS_GETNAMEINFO_T; + case WOLFSSL_SYS_GETSERVBYNAME: return WOLFSSL_SYS_GETSERVBYNAME_T; + case WOLFSSL_SYS_IOCTLSOCKET: return WOLFSSL_SYS_IOCTLSOCKET_T; + case WOLFSSL_SYS_LISTEN: return WOLFSSL_SYS_LISTEN_T; + case WOLFSSL_SYS_OPENDIR: return WOLFSSL_SYS_OPENDIR_T; + case WOLFSSL_SYS_SETSOCKOPT: return WOLFSSL_SYS_SETSOCKOPT_T; + case WOLFSSL_SYS_SOCKET: return WOLFSSL_SYS_SOCKET_T; + default: + return "NULL"; + } + } +#endif /* DEBUG_WOLFSSL */ + + + /* @TODO when having an error queue this needs to push to the queue */ + void wolfSSL_ERR_put_error(int lib, int fun, int err, const char* file, + int line) + { + WOLFSSL_ENTER("wolfSSL_ERR_put_error"); + + #if !defined(DEBUG_WOLFSSL) && !defined(OPENSSL_EXTRA) + (void)fun; + (void)err; + (void)file; + (void)line; + WOLFSSL_MSG("Not compiled in debug mode"); + #elif defined(OPENSSL_EXTRA) && \ + (defined(_WIN32) || defined(NO_ERROR_QUEUE)) + (void)fun; + (void)file; + (void)line; + WOLFSSL_ERROR(err); + #else + WOLFSSL_ERROR_LINE(err, wolfSSL_ERR_sys_func(fun), (unsigned int)line, + file, NULL); + #endif + (void)lib; + } + + + /* Similar to wolfSSL_ERR_get_error_line but takes in a flags argument for + * more flexibility. + * + * file output pointer to file where error happened + * line output to line number of error + * data output data. Is a string if ERR_TXT_STRING flag is used + * flags bit flag to adjust data output + * + * Returns the error value or 0 if no errors are in the queue + */ + unsigned long wolfSSL_ERR_get_error_line_data(const char** file, int* line, + const char** data, int *flags) + { + int ret; + + WOLFSSL_STUB("wolfSSL_ERR_get_error_line_data"); + + if (flags != NULL) { + if ((*flags & ERR_TXT_STRING) == ERR_TXT_STRING) { + ret = wc_PullErrorNode(file, data, line); + if (ret < 0) { + if (ret == BAD_STATE_E) return 0; /* no errors in queue */ + WOLFSSL_MSG("Error with pulling error node!"); + WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret); + ret = 0 - ret; /* return absolute value of error */ + + /* panic and try to clear out nodes */ + wc_ClearErrorNodes(); + } + + return (unsigned long)ret; + } + } + + ret = wc_PullErrorNode(file, NULL, line); + if (ret < 0) { + if (ret == BAD_STATE_E) return 0; /* no errors in queue */ + WOLFSSL_MSG("Error with pulling error node!"); + WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret); + ret = 0 - ret; /* return absolute value of error */ + + /* panic and try to clear out nodes */ + wc_ClearErrorNodes(); + } + + return (unsigned long)ret; + } + +#endif /* OPENSSL_EXTRA */ + + +#if (defined(KEEP_PEER_CERT) && defined(SESSION_CERTS)) || \ + (defined(OPENSSL_ALL) && defined(HAVE_PKCS7)) + /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object. + * + * x509 WOLFSSL_X509 object to decode into. + * in X509 DER data. + * len Length of the X509 DER data. + * returns the new certificate on success, otherwise NULL. + */ + static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len) + { + int ret; + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + if (x509 == NULL || in == NULL || len <= 0) + return BAD_FUNC_ARG; + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return MEMORY_E; + #endif + + /* Create a DecodedCert object and copy fields into WOLFSSL_X509 object. + */ + InitDecodedCert(cert, (byte*)in, len, NULL); + if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL)) == 0) { + /* Check if x509 was not previously initialized by wolfSSL_X509_new() */ + if (x509->dynamicMemory != TRUE) + InitX509(x509, 0, NULL); + ret = CopyDecodedToX509(x509, cert); + FreeDecodedCert(cert); + } + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + #endif + + return ret; + } +#endif /* (KEEP_PEER_CERT && SESSION_CERTS) || (OPENSSL_ALL && HAVE_PKCS7) */ + + +#ifdef KEEP_PEER_CERT + WOLFSSL_ABI + WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl) + { + WOLFSSL_ENTER("SSL_get_peer_certificate"); + if (ssl == NULL) + return NULL; + + if (ssl->peerCert.issuer.sz) + return &ssl->peerCert; +#ifdef SESSION_CERTS + else if (ssl->session.chain.count > 0) { + if (DecodeToX509(&ssl->peerCert, ssl->session.chain.certs[0].buffer, + ssl->session.chain.certs[0].length) == 0) { + return &ssl->peerCert; + } + } +#endif + return 0; + } + +#endif /* KEEP_PEER_CERT */ + +#if defined(SESSION_CERTS) +/* Return stack of peer certs. + * If Qt or OPENSSL_ALL is defined then return ssl->peerCertChain. + * All other cases return &ssl->session.chain + * ssl->peerCertChain is type WOLFSSL_STACK* + * ssl->session.chain is type WOLFSSL_X509_CHAIN + * Caller does not need to free return. The stack is Free'd when WOLFSSL* ssl is. + */ +WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl) +{ + WOLFSSL_STACK* sk; + WOLFSSL_ENTER("wolfSSL_get_peer_cert_chain"); + + if (ssl == NULL) + return NULL; + + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + if (ssl->peerCertChain == NULL) + wolfSSL_set_peer_cert_chain((WOLFSSL*) ssl); + sk = ssl->peerCertChain; + #else + sk = (WOLF_STACK_OF(WOLFSSL_X509)* )&ssl->session.chain; + #endif + + if (sk == NULL) { + WOLFSSL_MSG("Error: Null Peer Cert Chain"); + } + return sk; +} + +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +/* Builds up and creates a stack of peer certificates for ssl->peerCertChain + based off of the ssl session chain. Returns stack of WOLFSSL_X509 certs or + NULL on failure */ +WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_set_peer_cert_chain(WOLFSSL* ssl) +{ + WOLFSSL_STACK* sk; + WOLFSSL_X509* x509; + int i = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_set_peer_cert_chain"); + if ((ssl == NULL) || (ssl->session.chain.count == 0)) + return NULL; + + sk = wolfSSL_sk_X509_new(); + i = ssl->session.chain.count-1; + for (; i >= 0; i--) { + /* For servers, the peer certificate chain does not include the peer + certificate, so do not add it to the stack */ + if (ssl->options.side == WOLFSSL_SERVER_END && i == 0) + continue; + x509 = wolfSSL_X509_new(); + if (x509 == NULL) { + WOLFSSL_MSG("Error Creating X509"); + return NULL; + } + ret = DecodeToX509(x509, ssl->session.chain.certs[i].buffer, + ssl->session.chain.certs[i].length); + + if (ret != 0 || wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error decoding cert"); + wolfSSL_X509_free(x509); + wolfSSL_sk_X509_free(sk); + return NULL; + } + } + + if (sk == NULL) { + WOLFSSL_MSG("Null session chain"); + } + /* This is Free'd when ssl is Free'd */ + ssl->peerCertChain = sk; + return sk; +} +#endif /* OPENSSL_ALL || WOLFSSL_QT */ +#endif /* SESSION_CERTS */ + +#ifndef NO_CERTS +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + +/* user externally called free X509, if dynamic go ahead with free, otherwise + * don't */ +static void ExternalFreeX509(WOLFSSL_X509* x509) +{ + int doFree = 0; + + WOLFSSL_ENTER("ExternalFreeX509"); + if (x509) { + if (x509->dynamicMemory) { + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + if (wc_LockMutex(&x509->refMutex) != 0) { + WOLFSSL_MSG("Couldn't lock x509 mutex"); + } + /* only free if all references to it are done */ + x509->refCount--; + if (x509->refCount == 0) + doFree = 1; + wc_UnLockMutex(&x509->refMutex); + #else + doFree = 1; + #endif /* OPENSSL_EXTRA */ + + if (doFree) { + FreeX509(x509); + XFREE(x509, x509->heap, DYNAMIC_TYPE_X509); + } + } else { + WOLFSSL_MSG("free called on non dynamic object, not freeing"); + } + } +} + +/* Frees an external WOLFSSL_X509 structure */ +WOLFSSL_ABI +void wolfSSL_X509_free(WOLFSSL_X509* x509) +{ + WOLFSSL_ENTER("wolfSSL_FreeX509"); + ExternalFreeX509(x509); +} + + +/* copy name into in buffer, at most sz bytes, if buffer is null will + malloc buffer, call responsible for freeing */ +WOLFSSL_ABI +char* wolfSSL_X509_NAME_oneline(WOLFSSL_X509_NAME* name, char* in, int sz) +{ + int copySz; + + if (name == NULL) { + WOLFSSL_MSG("WOLFSSL_X509_NAME pointer was NULL"); + return NULL; + } + + copySz = min(sz, name->sz); + + WOLFSSL_ENTER("wolfSSL_X509_NAME_oneline"); + if (!name->sz) return in; + + if (!in) { + #ifdef WOLFSSL_STATIC_MEMORY + WOLFSSL_MSG("Using static memory -- please pass in a buffer"); + return NULL; + #else + in = (char*)XMALLOC(name->sz, NULL, DYNAMIC_TYPE_OPENSSL); + if (!in ) return in; + copySz = name->sz; + #endif + } + + if (copySz <= 0) + return in; + + XMEMCPY(in, name->name, copySz - 1); + in[copySz - 1] = 0; + + return in; +} + +#if defined(OPENSSL_EXTRA) && defined(XSNPRINTF) +/* Copies X509 subject name into a buffer, with comma-separated name entries + * (matching OpenSSL v1.0.0 format) + * Example Output for Issuer: + * + * C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, + * CN=www.wolfssl.com, emailAddress=info@wolfssl.com + */ +char* wolfSSL_X509_get_name_oneline(WOLFSSL_X509_NAME* name, char* in, int sz) +{ + WOLFSSL_X509_NAME_ENTRY* entry; + int nameSz, strSz, count, i, idx = 0; + int totalSz = 0; + char *str; + char tmpBuf[256]; + char buf[80]; + const char* sn; + WOLFSSL_ENTER("wolfSSL_X509_get_name_oneline"); + + if (name == NULL) { + WOLFSSL_MSG("wolfSSL_X509_get_subject_name failed"); + return NULL; + } + #ifdef WOLFSSL_STATIC_MEMORY + if (!in) { + WOLFSSL_MSG("Using static memory -- please pass in a buffer"); + return NULL; + } + #endif + + tmpBuf[0] = '\0'; /* Make sure tmpBuf is NULL terminated */ + /* Loop through X509 name entries and copy new format to buffer */ + count = wolfSSL_X509_NAME_entry_count(name); + for (i = 0; i < count; i++) { + + /* Get name entry and size */ + entry = wolfSSL_X509_NAME_get_entry(name, i); + if (entry == NULL) { + WOLFSSL_MSG("X509_NAME_get_entry failed"); + return NULL; + } + nameSz = wolfSSL_X509_NAME_get_text_by_NID(name, entry->nid, buf, + sizeof(buf)); + if (nameSz < 0) { + WOLFSSL_MSG("X509_NAME_get_text_by_NID failed"); + return NULL; + } + + /* Get short name */ + sn = wolfSSL_OBJ_nid2sn(entry->nid); + if (sn == NULL) { + WOLFSSL_MSG("OBJ_nid2sn failed"); + return NULL; + } + + /* Copy sn and name text to buffer + * Add extra strSz for '=', ',', ' ' and '\0' characters in XSNPRINTF. + */ + if (i != count - 1) { + strSz = (int)XSTRLEN(sn) + nameSz + 4; + totalSz+= strSz; + str = (char*)XMALLOC(strSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) { + WOLFSSL_MSG("Memory error"); + return NULL; + } + XSNPRINTF(str, strSz, "%s=%s, ", sn, buf); + } + else { + /* Copy last name entry + * Add extra strSz for '=' and '\0' characters in XSNPRINTF. + */ + strSz = (int)XSTRLEN(sn) + nameSz + 2; + totalSz+= strSz; + str = (char*)XMALLOC(strSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) { + WOLFSSL_MSG("Memory error"); + return NULL; + } + XSNPRINTF(str, strSz, "%s=%s", sn, buf); + } + /* Copy string to tmpBuf */ + XSTRNCAT(tmpBuf, str, strSz); + idx += strSz; + XFREE(str, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* Allocate space based on total string size if no buffer was provided */ + if (!in) { + in = (char*)XMALLOC(totalSz+1, NULL, DYNAMIC_TYPE_OPENSSL); + if (in == NULL) { + WOLFSSL_MSG("Memory error"); + return in; + } + } + else { + if (totalSz > sz) { + WOLFSSL_MSG("Memory error"); + return NULL; + } + } + + XMEMCPY(in, tmpBuf, totalSz); + in[totalSz] = '\0'; + + return in; +} +#endif + + +/* Wraps wolfSSL_X509_d2i + * + * returns a WOLFSSL_X509 structure pointer on success and NULL on fail + */ +WOLFSSL_X509* wolfSSL_d2i_X509(WOLFSSL_X509** x509, const unsigned char** in, + int len) +{ + WOLFSSL_X509* newX509 = NULL; + + newX509 = wolfSSL_X509_d2i(x509, *in, len); + if (newX509 != NULL) { + *in += newX509->derCert->length; + } + return newX509; +} + + +WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len) +{ + WOLFSSL_X509 *newX509 = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_d2i"); + + if (in != NULL && len != 0) { + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return NULL; + #endif + + InitDecodedCert(cert, (byte*)in, len, NULL); + if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) { + newX509 = wolfSSL_X509_new(); + if (newX509 != NULL) { + if (CopyDecodedToX509(newX509, cert) != 0) { + wolfSSL_X509_free(newX509); + newX509 = NULL; + } + } + } + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + #endif + } + + if (x509 != NULL) + *x509 = newX509; + + return newX509; +} +#endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA || + OPENSSL_EXTRA_X509_SMALL */ + + + +#if defined(OPENSSL_ALL) || defined(KEEP_OUR_CERT) || defined(KEEP_PEER_CERT) || \ + defined(SESSION_CERTS) + /* return the next, if any, altname from the peer cert */ + WOLFSSL_ABI + char* wolfSSL_X509_get_next_altname(WOLFSSL_X509* cert) + { + char* ret = NULL; + WOLFSSL_ENTER("wolfSSL_X509_get_next_altname"); + + /* don't have any to work with */ + if (cert == NULL || cert->altNames == NULL) + return NULL; + + /* already went through them */ + if (cert->altNamesNext == NULL) + return NULL; + + ret = cert->altNamesNext->name; + cert->altNamesNext = cert->altNamesNext->next; + + return ret; + } + + int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509) + { + int isCA = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_isCA"); + + if (x509 != NULL) + isCA = x509->isCa; + + WOLFSSL_LEAVE("wolfSSL_X509_get_isCA", isCA); + + return isCA; + } + + int wolfSSL_X509_get_signature(WOLFSSL_X509* x509, + unsigned char* buf, int* bufSz) + { + WOLFSSL_ENTER("wolfSSL_X509_get_signature"); + if (x509 == NULL || bufSz == NULL || (*bufSz < (int)x509->sig.length && + buf != NULL)) + return WOLFSSL_FATAL_ERROR; + + if (buf != NULL) + XMEMCPY(buf, x509->sig.buffer, x509->sig.length); + *bufSz = x509->sig.length; + + return WOLFSSL_SUCCESS; + } + + + /* Getter function that copies over the DER public key buffer to "buf" and + * sets the size in bufSz. If "buf" is NULL then just bufSz is set to needed + * buffer size. "bufSz" passed in should initially be set by the user to be + * the size of "buf". This gets checked to make sure the buffer is large + * enough to hold the public key. + * + * Note: this is the X.509 form of key with "header" info. + * return WOLFSSL_SUCCESS on success + */ + int wolfSSL_X509_get_pubkey_buffer(WOLFSSL_X509* x509, + unsigned char* buf, int* bufSz) + { + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + word32 idx; + const byte* der; + int length = 0; + int ret, derSz = 0; + int badDate = 0; + const byte* pubKeyX509 = NULL; + int pubKeyX509Sz = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_pubkey_buffer"); + if (x509 == NULL || bufSz == NULL) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BAD_FUNC_ARG); + return WOLFSSL_FATAL_ERROR; + } + + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), + x509->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (cert == NULL) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", MEMORY_E); + return WOLFSSL_FATAL_ERROR; + } + #endif + + der = wolfSSL_X509_get_der(x509, &derSz); + InitDecodedCert(cert, der, derSz, NULL); + ret = wc_GetPubX509(cert, 0, &badDate); + if (ret >= 0) { + idx = cert->srcIdx; + pubKeyX509 = cert->source + cert->srcIdx; + ret = GetSequence(cert->source, &cert->srcIdx, &length, + cert->maxIdx); + pubKeyX509Sz = length + (cert->srcIdx - idx); + } + + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, x509->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + + if (ret < 0) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", ret); + return WOLFSSL_FATAL_ERROR; + } + + if (buf != NULL) { + if (pubKeyX509Sz > *bufSz) { + WOLFSSL_LEAVE("wolfSSL_X509_get_pubkey_buffer", BUFFER_E); + return WOLFSSL_FATAL_ERROR; + } + XMEMCPY(buf, pubKeyX509, pubKeyX509Sz); + } + *bufSz = pubKeyX509Sz; + + return WOLFSSL_SUCCESS; + } + + + /* Getter function for the public key OID value + * return public key OID stored in WOLFSSL_X509 structure */ + int wolfSSL_X509_get_pubkey_type(WOLFSSL_X509* x509) + { + if (x509 == NULL) + return WOLFSSL_FAILURE; + return x509->pubKeyOID; + } + + /* write X509 serial number in unsigned binary to buffer + buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases + return WOLFSSL_SUCCESS on success */ + int wolfSSL_X509_get_serial_number(WOLFSSL_X509* x509, + byte* in, int* inOutSz) + { + WOLFSSL_ENTER("wolfSSL_X509_get_serial_number"); + if (x509 == NULL || in == NULL || + inOutSz == NULL || *inOutSz < x509->serialSz) + return BAD_FUNC_ARG; + + XMEMCPY(in, x509->serial, x509->serialSz); + *inOutSz = x509->serialSz; + + return WOLFSSL_SUCCESS; + } + + /* not an openssl compatibility function - getting for derCert */ + const byte* wolfSSL_X509_get_der(WOLFSSL_X509* x509, int* outSz) + { + WOLFSSL_ENTER("wolfSSL_X509_get_der"); + + if (x509 == NULL || x509->derCert == NULL || outSz == NULL) + return NULL; + + *outSz = (int)x509->derCert->length; + return x509->derCert->buffer; + } + + /* used by JSSE (not a standard compatibility function) */ + /* this is not thread safe */ + WOLFSSL_ABI + const byte* wolfSSL_X509_notBefore(WOLFSSL_X509* x509) + { + static byte notBeforeData[CTC_DATE_SIZE]; /* temp buffer for date */ + WOLFSSL_ENTER("wolfSSL_X509_notBefore"); + + if (x509 == NULL) + return NULL; + + XMEMSET(notBeforeData, 0, sizeof(notBeforeData)); + notBeforeData[0] = (byte)x509->notBefore.type; + notBeforeData[1] = (byte)x509->notBefore.length; + XMEMCPY(¬BeforeData[2], x509->notBefore.data, x509->notBefore.length); + + return notBeforeData; + } + /* used by JSSE (not a standard compatibility function) */ + /* this is not thread safe */ + WOLFSSL_ABI + const byte* wolfSSL_X509_notAfter(WOLFSSL_X509* x509) + { + static byte notAfterData[CTC_DATE_SIZE]; /* temp buffer for date */ + WOLFSSL_ENTER("wolfSSL_X509_notAfter"); + + if (x509 == NULL) + return NULL; + + XMEMSET(notAfterData, 0, sizeof(notAfterData)); + notAfterData[0] = (byte)x509->notAfter.type; + notAfterData[1] = (byte)x509->notAfter.length; + XMEMCPY(¬AfterData[2], x509->notAfter.data, x509->notAfter.length); + + return notAfterData; + } + + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) && !defined(NO_WOLFSSL_STUB) + WOLFSSL_ASN1_TIME* wolfSSL_X509_gmtime_adj(WOLFSSL_ASN1_TIME *s, long adj) + { + (void) s; + (void) adj; + WOLFSSL_STUB("wolfSSL_X509_gmtime_adj"); + return NULL; + } + #endif + + /* get the buffer to be signed (tbs) from the WOLFSSL_X509 certificate + * + * outSz : gets set to the size of the buffer + * returns a pointer to the internal buffer at the location of TBS on + * on success and NULL on failure. + */ + const unsigned char* wolfSSL_X509_get_tbs(WOLFSSL_X509* x509, int* outSz) + { + int sz = 0, len; + unsigned int idx = 0, tmpIdx; + const unsigned char* der = NULL; + const unsigned char* tbs = NULL; + + if (x509 == NULL || outSz == NULL) { + return NULL; + } + + der = wolfSSL_X509_get_der(x509, &sz); + if (der == NULL) { + return NULL; + } + + if (GetSequence(der, &idx, &len, sz) < 0) { + return NULL; + } + tbs = der + idx; + tmpIdx = idx; + if (GetSequence(der, &idx, &len, sz) < 0) { + return NULL; + } + *outSz = len + (idx - tmpIdx); + return tbs; + } + + int wolfSSL_X509_version(WOLFSSL_X509* x509) + { + WOLFSSL_ENTER("wolfSSL_X509_version"); + + if (x509 == NULL) + return 0; + + return x509->version; + } + +#ifdef WOLFSSL_SEP + +/* copy oid into in buffer, at most *inOutSz bytes, if buffer is null will + malloc buffer, call responsible for freeing. Actual size returned in + *inOutSz. Requires inOutSz be non-null */ +byte* wolfSSL_X509_get_device_type(WOLFSSL_X509* x509, byte* in, int *inOutSz) +{ + int copySz; + + WOLFSSL_ENTER("wolfSSL_X509_get_dev_type"); + if (inOutSz == NULL) return NULL; + if (!x509->deviceTypeSz) return in; + + copySz = min(*inOutSz, x509->deviceTypeSz); + + if (!in) { + #ifdef WOLFSSL_STATIC_MEMORY + WOLFSSL_MSG("Using static memory -- please pass in a buffer"); + return NULL; + #else + in = (byte*)XMALLOC(x509->deviceTypeSz, 0, DYNAMIC_TYPE_OPENSSL); + if (!in) return in; + copySz = x509->deviceTypeSz; + #endif + } + + XMEMCPY(in, x509->deviceType, copySz); + *inOutSz = copySz; + + return in; +} + + +byte* wolfSSL_X509_get_hw_type(WOLFSSL_X509* x509, byte* in, int* inOutSz) +{ + int copySz; + + WOLFSSL_ENTER("wolfSSL_X509_get_hw_type"); + if (inOutSz == NULL) return NULL; + if (!x509->hwTypeSz) return in; + + copySz = min(*inOutSz, x509->hwTypeSz); + + if (!in) { + #ifdef WOLFSSL_STATIC_MEMORY + WOLFSSL_MSG("Using static memory -- please pass in a buffer"); + return NULL; + #else + in = (byte*)XMALLOC(x509->hwTypeSz, 0, DYNAMIC_TYPE_OPENSSL); + if (!in) return in; + copySz = x509->hwTypeSz; + #endif + } + + XMEMCPY(in, x509->hwType, copySz); + *inOutSz = copySz; + + return in; +} + + +byte* wolfSSL_X509_get_hw_serial_number(WOLFSSL_X509* x509,byte* in, + int* inOutSz) +{ + int copySz; + + WOLFSSL_ENTER("wolfSSL_X509_get_hw_serial_number"); + if (inOutSz == NULL) return NULL; + if (!x509->hwTypeSz) return in; + + copySz = min(*inOutSz, x509->hwSerialNumSz); + + if (!in) { + #ifdef WOLFSSL_STATIC_MEMORY + WOLFSSL_MSG("Using static memory -- please pass in a buffer"); + return NULL; + #else + in = (byte*)XMALLOC(x509->hwSerialNumSz, 0, DYNAMIC_TYPE_OPENSSL); + if (!in) return in; + copySz = x509->hwSerialNumSz; + #endif + } + + XMEMCPY(in, x509->hwSerialNum, copySz); + *inOutSz = copySz; + + return in; +} + +#endif /* WOLFSSL_SEP */ + +/* require OPENSSL_EXTRA since wolfSSL_X509_free is wrapped by OPENSSL_EXTRA */ +#if !defined(NO_CERTS) && defined(OPENSSL_EXTRA) + +WOLFSSL_ASN1_TIME* wolfSSL_X509_get_notBefore(const WOLFSSL_X509* x509) +{ + WOLFSSL_ENTER("wolfSSL_X509_get_notBefore"); + + if (x509 == NULL) + return NULL; + + return (WOLFSSL_ASN1_TIME*)&x509->notBefore; +} + + +WOLFSSL_ASN1_TIME* wolfSSL_X509_get_notAfter(const WOLFSSL_X509* x509) +{ + WOLFSSL_ENTER("wolfSSL_X509_get_notAfter"); + + if (x509 == NULL) + return NULL; + + return (WOLFSSL_ASN1_TIME*)&x509->notAfter; +} + + +/* return 1 on success 0 on fail */ +int wolfSSL_sk_X509_push(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, WOLFSSL_X509* x509) +{ + WOLFSSL_STACK* node; + WOLFSSL_ENTER("wolfSSL_sk_X509_push"); + + if (sk == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.x509 == NULL) { + sk->data.x509 = x509; + sk->num += 1; + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_X509); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new x509 onto head of stack */ + node->data.x509 = sk->data.x509; + node->next = sk->next; + node->type = sk->type; + sk->next = node; + sk->data.x509 = x509; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} + + +WOLFSSL_X509* wolfSSL_sk_X509_pop(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk) { + WOLFSSL_STACK* node; + WOLFSSL_X509* x509; + + if (sk == NULL) { + return NULL; + } + + node = sk->next; + x509 = sk->data.x509; + + if (node != NULL) { /* update sk and remove node from stack */ + sk->data.x509 = node->data.x509; + sk->next = node->next; + XFREE(node, NULL, DYNAMIC_TYPE_X509); + } + else { /* last x509 in stack */ + sk->data.x509 = NULL; + } + + if (sk->num > 0) { + sk->num -= 1; + } + + return x509; +} + +/* Getter function for WOLFSSL_X509 pointer + * + * sk is the stack to retrieve pointer from + * i is the index value in stack + * + * returns a pointer to a WOLFSSL_X509 structure on success and NULL on + * fail + */ +WOLFSSL_X509* wolfSSL_sk_X509_value(STACK_OF(WOLFSSL_X509)* sk, int i) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_value"); + + for (; sk != NULL && i > 0; i--) + sk = sk->next; + + if (i != 0 || sk == NULL) + return NULL; + return sk->data.x509; +} + +WOLFSSL_X509* wolfSSL_sk_X509_shift(WOLF_STACK_OF(WOLFSSL_X509)* sk) +{ + return wolfSSL_sk_X509_pop(sk); +} + +#ifndef NO_WOLFSSL_STUB +void* wolfSSL_sk_X509_OBJECT_value(WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* sk, int x) +{ + (void) sk; + (void) x; + return NULL; +} +#endif + + +/* Free's all nodes in X509 stack. This is different then wolfSSL_sk_X509_free + * in that it allows for choosing the function to use when freeing an X509s. + * + * sk stack to free nodes in + * f X509 free function + */ +void wolfSSL_sk_X509_pop_free(STACK_OF(WOLFSSL_X509)* sk, + void (*f) (WOLFSSL_X509*)) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_X509_pop_free"); + + if (sk == NULL) { + return; + } + + /* parse through stack freeing each node */ + node = sk->next; + while (node && sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + if (f) + f(tmp->data.x509); + else + wolfSSL_X509_free(tmp->data.x509); + tmp->data.x509 = NULL; + XFREE(tmp, NULL, DYNAMIC_TYPE_X509); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + if (f) + f(sk->data.x509); + else + wolfSSL_X509_free(sk->data.x509); + sk->data.x509 = NULL; + } + XFREE(sk, NULL, DYNAMIC_TYPE_X509); +} + + +/* free structure for x509 stack */ +void wolfSSL_sk_X509_free(WOLF_STACK_OF(WOLFSSL_X509)* sk) +{ + wolfSSL_sk_X509_pop_free(sk, NULL); +} + +#endif /* NO_CERTS && OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined (WOLFSSL_QT) +/* return 1 on success 0 on fail */ +int wolfSSL_sk_ACCESS_DESCRIPTION_push(WOLF_STACK_OF(ACCESS_DESCRIPTION)* sk, + WOLFSSL_ACCESS_DESCRIPTION* access) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_ACCESS_DESCRIPTION_push"); + + if (sk == NULL || access == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.access == NULL) { + sk->data.access = access; + sk->num += 1; + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_ASN1); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new obj onto head of stack */ + node->data.access = sk->data.access; + node->next = sk->next; + node->type = sk->type; + sk->next = node; + sk->data.access = access; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} + +/* Frees all nodes in ACCESS_DESCRIPTION stack +* +* sk stack of nodes to free +* f free function to use, not called with wolfSSL +*/ +void wolfSSL_sk_ACCESS_DESCRIPTION_pop_free(WOLFSSL_STACK* sk, + void (*f) (WOLFSSL_ACCESS_DESCRIPTION*)) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_ACCESS_DESCRIPTION_pop_free"); + + if (sk == NULL) { + return; + } + + /* parse through stack freeing each node */ + node = sk->next; + while (node && sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + if (f) + f(tmp->data.access); + else + wolfSSL_ACCESS_DESCRIPTION_free(tmp->data.access); + tmp->data.access = NULL; + XFREE(tmp, NULL, DYNAMIC_TYPE_ASN1); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + if (f) + f(sk->data.access); + else { + if(sk->data.access->method) { + + wolfSSL_ASN1_OBJECT_free(sk->data.access->method); + } + if(sk->data.access->location) { + wolfSSL_GENERAL_NAME_free(sk->data.access->location); + } + } + sk->data.access = NULL; + } + XFREE(sk, NULL, DYNAMIC_TYPE_ASN1); +} + +void wolfSSL_sk_ACCESS_DESCRIPTION_free(WOLFSSL_STACK* sk) +{ + wolfSSL_sk_ACCESS_DESCRIPTION_pop_free(sk, NULL); +} + +void wolfSSL_ACCESS_DESCRIPTION_free(WOLFSSL_ACCESS_DESCRIPTION* access) +{ + WOLFSSL_ENTER("wolfSSL_ACCESS_DESCRIPTION_free"); + if (access == NULL) + return; + + if (access->method) + wolfSSL_ASN1_OBJECT_free(access->method); + if (access->location) + wolfSSL_GENERAL_NAME_free(access->location); + + /* access = NULL, don't try to access or double free it */ +} +#endif + +#ifdef OPENSSL_EXTRA + +/* create a generic wolfSSL stack node + * returns a new WOLFSSL_STACK structure on success */ +WOLFSSL_STACK* wolfSSL_sk_new_node(void* heap) +{ + WOLFSSL_STACK* sk; + WOLFSSL_ENTER("wolfSSL_sk_new_node"); + + sk = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), heap, + DYNAMIC_TYPE_OPENSSL); + if (sk != NULL) { + XMEMSET(sk, 0, sizeof(*sk)); + sk->heap = heap; + } + + return sk; +} + +/* free's node but does not free internal data such as in->data.x509 */ +void wolfSSL_sk_free_node(WOLFSSL_STACK* in) +{ + if (in != NULL) { + XFREE(in, in->heap, DYNAMIC_TYPE_OPENSSL); + } +} + +/* pushes node "in" onto "stack" and returns pointer to the new stack on success + * also handles internal "num" for number of nodes on stack + * return WOLFSSL_SUCCESS on success + */ +int wolfSSL_sk_push_node(WOLFSSL_STACK** stack, WOLFSSL_STACK* in) +{ + if (stack == NULL || in == NULL) { + return WOLFSSL_FAILURE; + } + + if (*stack == NULL) { + in->num = 1; + *stack = in; + return WOLFSSL_SUCCESS; + } + + in->num = (*stack)->num + 1; + in->next = *stack; + *stack = in; + return WOLFSSL_SUCCESS; +} + +/* return 1 on success 0 on fail */ +int wolfSSL_sk_push(WOLFSSL_STACK* sk, const void *data) +{ + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_sk_push"); + + switch (sk->type) { + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + case STACK_TYPE_X509: + ret = wolfSSL_sk_X509_push(sk, (WOLFSSL_X509*) data); + break; + #ifndef NO_WOLFSSL_STUB + case STACK_TYPE_CIPHER: + ret = wolfSSL_sk_CIPHER_push(sk, (WOLFSSL_CIPHER*) data); + break; + #endif + case STACK_TYPE_GEN_NAME: + ret = wolfSSL_sk_ASN1_OBJECT_push(sk, (WOLFSSL_ASN1_OBJECT*) data); + break; + case STACK_TYPE_ACCESS_DESCRIPTION: + ret = wolfSSL_sk_ACCESS_DESCRIPTION_push(sk, + (WOLFSSL_ACCESS_DESCRIPTION*) data); + break; + case STACK_TYPE_NULL: + ret = wolfSSL_sk_GENERIC_push(sk, (void*) data); + break; + case STACK_TYPE_OBJ: + ret = wolfSSL_sk_ASN1_OBJECT_push(sk, (WOLFSSL_ASN1_OBJECT*) data); + break; + #endif + default: + ret = wolfSSL_sk_ASN1_OBJECT_push(sk, (WOLFSSL_ASN1_OBJECT*) data); + break; + } + + return ret; +} + +/* Creates and returns new GENERAL_NAME structure */ +WOLFSSL_GENERAL_NAME* wolfSSL_GENERAL_NAME_new(void) +{ + WOLFSSL_GENERAL_NAME* gn; + WOLFSSL_ENTER("GENERAL_NAME_new"); + + gn = (WOLFSSL_GENERAL_NAME*)XMALLOC(sizeof(WOLFSSL_GENERAL_NAME), NULL, + DYNAMIC_TYPE_ASN1); + if (gn == NULL) { + return NULL; + } + XMEMSET(gn, 0, sizeof(WOLFSSL_GENERAL_NAME)); + + gn->d.ia5 = wolfSSL_ASN1_STRING_new(); + if (gn->d.ia5 == NULL) { + WOLFSSL_MSG("Issue creating ASN1_STRING struct"); + wolfSSL_GENERAL_NAME_free(gn); + return NULL; + } + return gn; +} + +/* return 1 on success 0 on fail */ +int wolfSSL_sk_GENERAL_NAME_push(WOLF_STACK_OF(WOLFSSL_GENERAL_NAME)* sk, + WOLFSSL_GENERAL_NAME* gn) +{ + WOLFSSL_STACK* node; + WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_push"); + + if (sk == NULL || gn == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.gn == NULL) { + sk->data.gn = gn; + sk->num += 1; + + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_ASN1); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new obj onto head of stack */ + node->data.gn = sk->data.gn; + node->next = sk->next; + sk->next = node; + sk->data.gn = gn; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} + +/* Returns the general name at index i from the stack + * + * sk stack to get general name from + * idx index to get + * + * return a pointer to the internal node of the stack + */ +WOLFSSL_GENERAL_NAME* wolfSSL_sk_GENERAL_NAME_value(WOLFSSL_STACK* sk, int idx) +{ + WOLFSSL_STACK* ret; + + if (sk == NULL) { + return NULL; + } + + ret = wolfSSL_sk_get_node(sk, idx); + if (ret != NULL) { + return ret->data.gn; + } + return NULL; +} + +/* Gets the number of nodes in the stack + * + * sk stack to get the number of nodes from + * + * returns the number of nodes, -1 if no nodes + */ +int wolfSSL_sk_GENERAL_NAME_num(WOLFSSL_STACK* sk) +{ + WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_num"); + + if (sk == NULL) { + return -1; + } + + return (int)sk->num; +} + +/* Frees all nodes in a GENERAL NAME stack + * + * sk stack of nodes to free + * f free function to use, not called with wolfSSL + */ +void wolfSSL_sk_GENERAL_NAME_pop_free(WOLFSSL_STACK* sk, + void (*f) (WOLFSSL_GENERAL_NAME*)) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_pop_free"); + + if (sk == NULL) { + return; + } + + /* parse through stack freeing each node */ + node = sk->next; + while (node && sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + if (f) + f(tmp->data.gn); + else + wolfSSL_GENERAL_NAME_free(tmp->data.gn); + XFREE(tmp, NULL, DYNAMIC_TYPE_ASN1); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + if (f) + f(sk->data.gn); + else + wolfSSL_GENERAL_NAME_free(sk->data.gn); + } + XFREE(sk, NULL, DYNAMIC_TYPE_ASN1); +} + +void wolfSSL_sk_GENERAL_NAME_free(WOLFSSL_STACK* sk) +{ + WOLFSSL_ENTER("sk_GENERAL_NAME_free"); + wolfSSL_sk_GENERAL_NAME_pop_free(sk, NULL); +} + + +/* returns the number of nodes in stack on success and WOLFSSL_FATAL_ERROR + * on fail */ +int wolfSSL_sk_ACCESS_DESCRIPTION_num(WOLFSSL_STACK* sk) +{ + if (sk == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + return (int)sk->num; +} + +#ifndef NO_WOLFSSL_STUB +/* similar to call to sk_ACCESS_DESCRIPTION_pop_free */ +void wolfSSL_AUTHORITY_INFO_ACCESS_free( + WOLF_STACK_OF(WOLFSSL_ACCESS_DESCRIPTION)* sk) +{ + WOLFSSL_STUB("wolfSSL_AUTHORITY_INFO_ACCESS_free"); + (void)sk; +} +#endif + +/* returns the node at index "idx", NULL if not found */ +WOLFSSL_STACK* wolfSSL_sk_get_node(WOLFSSL_STACK* sk, int idx) +{ + int i; + WOLFSSL_STACK* ret = NULL; + WOLFSSL_STACK* current; + + current = sk; + for (i = 0; i <= idx && current != NULL; i++) { + if (i == idx) { + ret = current; + break; + } + current = current->next; + } + return ret; +} + +/* returns NULL on fail and pointer to internal data on success */ +WOLFSSL_ACCESS_DESCRIPTION* wolfSSL_sk_ACCESS_DESCRIPTION_value( + WOLFSSL_STACK* sk, int idx) +{ + WOLFSSL_STACK* ret; + + if (sk == NULL) { + return NULL; + } + + ret = wolfSSL_sk_get_node(sk, idx); + if (ret != NULL) { + return ret->data.access; + } + return NULL; +} + +/* Frees GENERAL_NAME objects. +*/ +void wolfSSL_GENERAL_NAME_free(WOLFSSL_GENERAL_NAME* name) +{ + WOLFSSL_ENTER("wolfSSL_GENERAL_NAME_Free"); + if(name != NULL) { + if (name->d.dNSName != NULL) { + wolfSSL_ASN1_STRING_free(name->d.dNSName); + name->d.dNSName = NULL; + } + if (name->d.uniformResourceIdentifier != NULL) { + wolfSSL_ASN1_STRING_free(name->d.uniformResourceIdentifier); + name->d.uniformResourceIdentifier = NULL; + } + if (name->d.iPAddress != NULL) { + wolfSSL_ASN1_STRING_free(name->d.iPAddress); + name->d.iPAddress = NULL; + } + if (name->d.registeredID != NULL) { + wolfSSL_ASN1_OBJECT_free(name->d.registeredID); + name->d.registeredID = NULL; + } + if (name->d.ia5 != NULL) { + wolfSSL_ASN1_STRING_free(name->d.ia5); + name->d.ia5 = NULL; + } + XFREE(name, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +void wolfSSL_GENERAL_NAMES_free(WOLFSSL_GENERAL_NAMES *gens) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_GENERAL_NAMES_free"); + + if (gens == NULL) { + return; + } + + /* parse through stack freeing each node */ + node = gens->next; + while (gens->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + wolfSSL_ASN1_OBJECT_free(tmp->data.obj); + XFREE(tmp, NULL, DYNAMIC_TYPE_ASN1); + gens->num -= 1; + } + + /* free head of stack */ + if (gens->num == 1) { + wolfSSL_ASN1_OBJECT_free(gens->data.obj); + } + XFREE(gens, NULL, DYNAMIC_TYPE_ASN1); +} + +#if defined(OPENSSL_ALL) +WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* wolfSSL_sk_X509_EXTENSION_new_null(void) +{ + WOLFSSL_STACK* sk = wolfSSL_sk_new_node(NULL); + if (sk) { + sk->type = STACK_TYPE_X509_EXT; + } + + return (WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)*)sk;; +} + +/* returns the number of nodes on the stack */ +int wolfSSL_sk_X509_EXTENSION_num(WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* sk) +{ + if (sk != NULL) { + return (int)sk->num; + } + return WOLFSSL_FATAL_ERROR; +} + + +/* returns null on failure and pointer to internal value on success */ +WOLFSSL_X509_EXTENSION* wolfSSL_sk_X509_EXTENSION_value( + WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* sk, int idx) +{ + WOLFSSL_STACK* ret; + + if (sk == NULL) { + return NULL; + } + + ret = wolfSSL_sk_get_node(sk, idx); + if (ret != NULL) { + return ret->data.ext; + } + return NULL; +} + +/* frees all of the nodes and the values in stack */ +void wolfSSL_sk_X509_EXTENSION_pop_free( + WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* sk, + void (*f) (WOLFSSL_X509_EXTENSION*)) +{ + WOLFSSL_STACK* current; + + if (sk == NULL) { + return; + } + + current = sk; + while (current != NULL) { + WOLFSSL_STACK* toFree = current; + current = current->next; + + if (f) + f(toFree->data.ext); + wolfSSL_sk_free_node(toFree); + } +} + +#if defined(HAVE_ECC) +/* Copies ecc_key into new WOLFSSL_EC_KEY object + * + * src : EC_KEY to duplicate. If EC_KEY is not null, create new EC_KEY and copy + * internal ecc_key from src to dup. + * + * Returns pointer to duplicate EC_KEY. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src) +{ + WOLFSSL_EC_KEY *dup; + ecc_key *key, *srcKey; + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_dup"); + + if (src == NULL || src->internal == NULL || src->group == NULL || \ + src->pub_key == NULL || src->priv_key == NULL) { + + WOLFSSL_MSG("src NULL error"); + return NULL; + } + + dup = wolfSSL_EC_KEY_new(); + if (dup == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); + return NULL; + } + + key = (ecc_key*)dup->internal; + if (key == NULL) { + WOLFSSL_MSG("ecc_key NULL error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + srcKey = (ecc_key*)src->internal; + + /* ecc_key */ + /* copy pubkey */ + ret = wc_ecc_copy_point(&srcKey->pubkey, &key->pubkey); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + /* copy private key k */ + ret = mp_copy(&srcKey->k, &key->k); + if (ret != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + /* copy domain parameters */ + if (srcKey->dp) { + ret = wc_ecc_set_curve(key, 0, srcKey->dp->id); + if (ret != 0) { + WOLFSSL_MSG("wc_ecc_set_curve error"); + return NULL; + } + } + + key->type = srcKey->type; + key->idx = srcKey->idx; + key->state = srcKey->state; + key->flags = srcKey->flags; + + /* Copy group */ + if (dup->group == NULL) { + WOLFSSL_MSG("EC_GROUP_new_by_curve_name error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + dup->group->curve_idx = src->group->curve_idx; + dup->group->curve_nid = src->group->curve_nid; + dup->group->curve_oid = src->group->curve_oid; + + /* Copy public key */ + if (src->pub_key->internal == NULL || dup->pub_key->internal == NULL) { + WOLFSSL_MSG("NULL pub_key error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + /* Copy public key internal */ + ret = wc_ecc_copy_point((ecc_point*)src->pub_key->internal, \ + (ecc_point*)dup->pub_key->internal); + if (ret != MP_OKAY) { + WOLFSSL_MSG("ecc_copy_point error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + /* Copy X, Y, Z */ + dup->pub_key->X = wolfSSL_BN_dup(src->pub_key->X); + if (!dup->pub_key->X && src->pub_key->X) { + WOLFSSL_MSG("Error copying EC_POINT"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + dup->pub_key->Y = wolfSSL_BN_dup(src->pub_key->Y); + if (!dup->pub_key->Y && src->pub_key->Y) { + WOLFSSL_MSG("Error copying EC_POINT"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + dup->pub_key->Z = wolfSSL_BN_dup(src->pub_key->Z); + if (!dup->pub_key->Z && src->pub_key->Z) { + WOLFSSL_MSG("Error copying EC_POINT"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + dup->pub_key->inSet = src->pub_key->inSet; + dup->pub_key->exSet = src->pub_key->exSet; + + /* Copy private key */ + if (src->priv_key->internal == NULL || dup->priv_key->internal == NULL) { + WOLFSSL_MSG("NULL priv_key error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + /* Free priv_key before call to dup function */ + wolfSSL_BN_free(dup->priv_key); + dup->priv_key = wolfSSL_BN_dup(src->priv_key); + if (dup->priv_key == NULL) { + WOLFSSL_MSG("BN_dup error"); + wolfSSL_EC_KEY_free(dup); + return NULL; + } + + return dup; + +} +#endif /* HAVE_ECC */ + +#if !defined(NO_DH) +int wolfSSL_DH_check(const WOLFSSL_DH *dh, int *codes) +{ + int isPrime = MP_NO, codeTmp = 0; + WC_RNG rng; + + WOLFSSL_ENTER("wolfSSL_DH_check"); + if (dh == NULL){ + return WOLFSSL_FAILURE; + } + + if (dh->g == NULL || dh->g->internal == NULL){ + codeTmp = DH_NOT_SUITABLE_GENERATOR; + } + + if (dh->p == NULL || dh->p->internal == NULL){ + codeTmp = DH_CHECK_P_NOT_PRIME; + } + else + { + /* test if dh->p has prime */ + if (wc_InitRng(&rng) == 0){ + mp_prime_is_prime_ex((mp_int*)dh->p->internal,8,&isPrime,&rng); + } + else { + WOLFSSL_MSG("Error initializing rng\n"); + return WOLFSSL_FAILURE; + } + wc_FreeRng(&rng); + if (isPrime != MP_YES){ + codeTmp = DH_CHECK_P_NOT_PRIME; + } + } + /* User may choose to enter NULL for codes if they don't want to check it*/ + if (codes != NULL){ + *codes = codeTmp; + } + + /* if codeTmp was set,some check was flagged invalid */ + if (codeTmp){ + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* Converts DER encoded DH parameters to a WOLFSSL_DH structure. + * + * dh : structure to copy DH parameters into. + * pp : DER encoded DH parameters + * length : length to copy + * + * Returns pointer to WOLFSSL_DH structure on success, or NULL on failure + */ +WOLFSSL_DH *wolfSSL_d2i_DHparams(WOLFSSL_DH **dh, const unsigned char **pp, + long length) +{ + WOLFSSL_DH *newDH = NULL; + int ret; + word32 idx = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_DHparams"); + + if (pp == NULL || length <= 0) { + WOLFSSL_MSG("bad argument"); + return NULL; + } + + if ((newDH = wolfSSL_DH_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_DH_new() failed"); + return NULL; + } + + ret = wc_DhKeyDecode(*pp, &idx, (DhKey*)newDH->internal, (word32)length); + if (ret != 0) { + WOLFSSL_MSG("DhKeyDecode() failed"); + wolfSSL_DH_free(newDH); + return NULL; + } + newDH->inSet = 1; + + if (SetDhExternal(newDH) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDhExternal failed"); + wolfSSL_DH_free(newDH); + return NULL; + } + + *pp += length; + if (dh != NULL){ + *dh = newDH; + } + + return newDH; +} + +/* Converts internal WOLFSSL_DH structure to DER encoded DH. + * + * dh : structure to copy DH parameters from. + * out : DER buffer for DH parameters + * + * Returns size of DER on success and WOLFSSL_FAILURE if error + */ +int wolfSSL_i2d_DHparams(const WOLFSSL_DH *dh, unsigned char **out) +{ + word32 len; + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_i2d_DHparams"); + + if (dh == NULL) { + WOLFSSL_MSG("Bad parameters"); + return WOLFSSL_FAILURE; + } + + /* Get total length */ + len = 2 + mp_leading_bit((mp_int*)dh->p->internal) + + mp_unsigned_bin_size((mp_int*)dh->p->internal) + + 2 + mp_leading_bit((mp_int*)dh->g->internal) + + mp_unsigned_bin_size((mp_int*)dh->g->internal); + + /* Two bytes required for length if ASN.1 SEQ data greater than 127 bytes + * and less than 256 bytes. + */ + len = ((len > 127) ? 2 : 1) + len; + + if (out != NULL && *out != NULL) { + ret = StoreDHparams(*out, &len, (mp_int*)dh->p->internal, + (mp_int*)dh->g->internal); + if (ret != MP_OKAY) { + WOLFSSL_MSG("StoreDHparams error"); + len = 0; + } + else{ + *out += len; + } + } + return (int)len; +} +#endif /* !NO_DH */ + +#endif /* OPENSSL_ALL */ + +#endif /* OPENSSL_EXTRA */ + +#ifndef NO_FILESYSTEM + +#ifndef NO_STDIO_FILESYSTEM + +WOLFSSL_X509* wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, XFILE file) +{ + WOLFSSL_X509* newX509 = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_d2i_fp"); + + if (file != XBADFILE) { + byte* fileBuffer = NULL; + long sz = 0; + + if (XFSEEK(file, 0, XSEEK_END) != 0) + return NULL; + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) { + WOLFSSL_MSG("X509_d2i file size error"); + return NULL; + } + + fileBuffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE); + if (fileBuffer != NULL) { + int ret = (int)XFREAD(fileBuffer, 1, sz, file); + if (ret == sz) { + newX509 = wolfSSL_X509_d2i(NULL, fileBuffer, (int)sz); + } + XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE); + } + } + + if (x509 != NULL) + *x509 = newX509; + + return newX509; +} + +#endif /* NO_STDIO_FILESYSTEM */ + +WOLFSSL_ABI +WOLFSSL_X509* wolfSSL_X509_load_certificate_file(const char* fname, int format) +{ +#ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ +#else + byte staticBuffer[FILE_BUFFER_SIZE]; +#endif + byte* fileBuffer = staticBuffer; + int dynamic = 0; + int ret; + long sz = 0; + XFILE file; + + WOLFSSL_X509* x509 = NULL; + + /* Check the inputs */ + if ((fname == NULL) || + (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM)) + return NULL; + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) + return NULL; + + if (XFSEEK(file, 0, XSEEK_END) != 0){ + XFCLOSE(file); + return NULL; + } + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) { + WOLFSSL_MSG("X509_load_certificate_file size error"); + XFCLOSE(file); + return NULL; + } + + if (sz > (long)sizeof(staticBuffer)) { + fileBuffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE); + if (fileBuffer == NULL) { + XFCLOSE(file); + return NULL; + } + dynamic = 1; + } + + ret = (int)XFREAD(fileBuffer, 1, sz, file); + if (ret != sz) { + XFCLOSE(file); + if (dynamic) + XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE); + return NULL; + } + + XFCLOSE(file); + + x509 = wolfSSL_X509_load_certificate_buffer(fileBuffer, (int)sz, format); + + if (dynamic) + XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE); + + return x509; +} + +#endif /* NO_FILESYSTEM */ + + +WOLFSSL_X509* wolfSSL_X509_load_certificate_buffer( + const unsigned char* buf, int sz, int format) +{ + int ret; + WOLFSSL_X509* x509 = NULL; + DerBuffer* der = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_load_certificate_ex"); + + if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + if (PemToDer(buf, sz, CERT_TYPE, &der, NULL, NULL, NULL) != 0) { + FreeDer(&der); + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + ret = AllocDer(&der, (word32)sz, CERT_TYPE, NULL); + if (ret == 0) { + XMEMCPY(der->buffer, buf, sz); + } + } + + /* At this point we want `der` to have the certificate in DER format */ + /* ready to be decoded. */ + if (der != NULL && der->buffer != NULL) { + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert; + #else + DecodedCert cert[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_DCERT); + if (cert != NULL) + #endif + { + InitDecodedCert(cert, der->buffer, der->length, NULL); + if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) { + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + if (x509 != NULL) { + InitX509(x509, 1, NULL); + if (CopyDecodedToX509(x509, cert) != 0) { + wolfSSL_X509_free(x509); + x509 = NULL; + } + } + } + + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + #endif + } + + FreeDer(&der); + } + + return x509; +} + +#endif /* KEEP_PEER_CERT || SESSION_CERTS */ + +/* OPENSSL_EXTRA is needed for wolfSSL_X509_d21 function + KEEP_OUR_CERT is to insure ability for returning ssl certificate */ +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + defined(KEEP_OUR_CERT) +WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return NULL; + } + + if (ssl->buffers.weOwnCert) { + if (ssl->ourCert == NULL) { + if (ssl->buffers.certificate == NULL) { + WOLFSSL_MSG("Certificate buffer not set!"); + return NULL; + } + #ifndef WOLFSSL_X509_STORE_CERTS + ssl->ourCert = wolfSSL_X509_d2i(NULL, + ssl->buffers.certificate->buffer, + ssl->buffers.certificate->length); + #endif + } + return ssl->ourCert; + } + else { /* if cert not owned get parent ctx cert or return null */ + if (ssl->ctx) { + if (ssl->ctx->ourCert == NULL) { + if (ssl->ctx->certificate == NULL) { + WOLFSSL_MSG("Ctx Certificate buffer not set!"); + return NULL; + } + #ifndef WOLFSSL_X509_STORE_CERTS + ssl->ctx->ourCert = wolfSSL_X509_d2i(NULL, + ssl->ctx->certificate->buffer, + ssl->ctx->certificate->length); + #endif + ssl->ctx->ownOurCert = 1; + } + return ssl->ctx->ourCert; + } + } + + return NULL; +} +#endif /* OPENSSL_EXTRA && KEEP_OUR_CERT */ +#endif /* NO_CERTS */ + + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +#ifndef NO_ASN +void wolfSSL_ASN1_OBJECT_free(WOLFSSL_ASN1_OBJECT* obj) +{ + if (obj == NULL) { + return; + } + if ((obj->obj != NULL) && ((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0)) { + WOLFSSL_MSG("Freeing ASN1 data"); + XFREE((void*)obj->obj, obj->heap, DYNAMIC_TYPE_ASN1); + obj->obj = NULL; + } + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + if (obj->pathlen != NULL) { + wolfSSL_ASN1_INTEGER_free(obj->pathlen); + obj->pathlen = NULL; + } + #endif + if ((obj->dynamic & WOLFSSL_ASN1_DYNAMIC) != 0) { + WOLFSSL_MSG("Freeing ASN1 OBJECT"); + XFREE(obj, NULL, DYNAMIC_TYPE_ASN1); + } +} +#endif /* NO_ASN */ +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_ASN +WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_new(void) +{ + WOLFSSL_ASN1_OBJECT* obj; + + obj = (WOLFSSL_ASN1_OBJECT*)XMALLOC(sizeof(WOLFSSL_ASN1_OBJECT), NULL, + DYNAMIC_TYPE_ASN1); + if (obj == NULL) { + return NULL; + } + + XMEMSET(obj, 0, sizeof(WOLFSSL_ASN1_OBJECT)); + obj->d.ia5 = &(obj->d.ia5_internal); +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + obj->d.iPAddress = &(obj->d.iPAddress_internal); +#endif + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + return obj; +} + +/* Creates and returns a new WOLFSSL_CIPHER stack. */ +WOLFSSL_STACK* wolfSSL_sk_new_asn1_obj(void) +{ + WOLFSSL_STACK* sk; + WOLFSSL_ENTER("wolfSSL_sk_new_asn1_obj"); + + sk = wolfSSL_sk_new_null(); + if (sk == NULL) + return NULL; + sk->type = STACK_TYPE_OBJ; + + return sk; +} + +/* return 1 on success 0 on fail */ +int wolfSSL_sk_ASN1_OBJECT_push(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, + WOLFSSL_ASN1_OBJECT* obj) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_ASN1_OBJECT_push"); + + if (sk == NULL || obj == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.obj == NULL) { + sk->data.obj = obj; + sk->num += 1; + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_ASN1); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new obj onto head of stack */ + node->data.obj = sk->data.obj; + node->next = sk->next; + node->type = sk->type; + sk->next = node; + sk->data.obj = obj; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} + + +WOLFSSL_ASN1_OBJECT* wolfSSL_sk_ASN1_OBJECT_pop( + WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk) +{ + WOLFSSL_STACK* node; + WOLFSSL_ASN1_OBJECT* obj; + + if (sk == NULL) { + return NULL; + } + + node = sk->next; + obj = sk->data.obj; + + if (node != NULL) { /* update sk and remove node from stack */ + sk->data.obj = node->data.obj; + sk->next = node->next; + XFREE(node, NULL, DYNAMIC_TYPE_ASN1); + } + else { /* last obj in stack */ + sk->data.obj = NULL; + } + + if (sk->num > 0) { + sk->num -= 1; + } + + return obj; +} + + +/* Free the structure for ASN1_OBJECT stack + * + * sk stack to free nodes in + */ +void wolfSSL_sk_ASN1_OBJECT_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk) +{ + wolfSSL_sk_ASN1_OBJECT_pop_free(sk, NULL); +} + +/* Free's all nodes in ASN1_OBJECT stack. + * This is different then wolfSSL_ASN1_OBJECT_free in that it allows for + * choosing the function to use when freeing an ASN1_OBJECT stack. + * + * sk stack to free nodes in + * f X509 free function + */ +void wolfSSL_sk_ASN1_OBJECT_pop_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, + void (*f) (WOLFSSL_ASN1_OBJECT*)) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_ASN1_OBJECT_pop_free"); + + if (sk == NULL) { + WOLFSSL_MSG("Parameter error"); + return; + } + + /* parse through stack freeing each node */ + node = sk->next; + while (node && sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + if (f) + f(tmp->data.obj); + else + wolfSSL_ASN1_OBJECT_free(tmp->data.obj); + tmp->data.obj = NULL; + XFREE(tmp, NULL, DYNAMIC_TYPE_ASN1); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + if (f) + f(sk->data.obj); + else + wolfSSL_ASN1_OBJECT_free(sk->data.obj); + sk->data.obj = NULL; + } + XFREE(sk, NULL, DYNAMIC_TYPE_ASN1); +} + +int wolfSSL_ASN1_STRING_to_UTF8(unsigned char **out, WOLFSSL_ASN1_STRING *in) +{ + /* + ASN1_STRING_to_UTF8() converts the string in to UTF8 format, + the converted data is allocated in a buffer in *out. + The length of out is returned or a negative error code. + The buffer *out should be free using OPENSSL_free(). + */ + unsigned char* buf; + unsigned char* inPtr; + int inLen; + + if (!out || !in) { + return -1; + } + + inPtr = wolfSSL_ASN1_STRING_data(in); + inLen = wolfSSL_ASN1_STRING_length(in); + if (!inPtr || inLen < 0) { + return -1; + } + buf = (unsigned char*)XMALLOC(inLen + 1, NULL, DYNAMIC_TYPE_OPENSSL); + if (!buf) { + return -1; + } + XMEMCPY(buf, inPtr, inLen + 1); + *out = buf; + return inLen; +} + +/* Returns string representation of ASN1_STRING */ +char* wolfSSL_i2s_ASN1_STRING(WOLFSSL_v3_ext_method *method, + const WOLFSSL_ASN1_STRING *s) +{ + int i; + int tmpSz = 100; + int valSz = 5; + char* tmp; + char val[5]; + unsigned char* str; + + WOLFSSL_ENTER("wolfSSL_i2s_ASN1_STRING"); + (void)method; + + if(s == NULL || s->data == NULL) { + WOLFSSL_MSG("Bad Function Argument"); + return NULL; + } + str = (unsigned char*)XMALLOC(s->length, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) { + WOLFSSL_MSG("Memory Error"); + return NULL; + } + XMEMCPY(str, (unsigned char*)s->data, s->length); + + tmp = (char*)XMALLOC(tmpSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + WOLFSSL_MSG("Memory Error"); + XFREE(str, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + XMEMSET(tmp, 0, tmpSz); + + for (i = 0; i < tmpSz && i < (s->length - 1); i++) { + XSNPRINTF(val, valSz - 1, "%02X:", str[i]); + XSTRNCAT(tmp, val, valSz); + } + XSNPRINTF(val, valSz - 1, "%02X", str[i]); + XSTRNCAT(tmp, val, valSz); + XFREE(str, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return tmp; +} +#endif /* NO_ASN */ + +void wolfSSL_set_connect_state(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_set_connect_state"); + if (ssl == NULL) { + WOLFSSL_MSG("WOLFSSL struct pointer passed in was null"); + return; + } + + #ifndef NO_DH + /* client creates its own DH parameters on handshake */ + if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + ssl->buffers.serverDH_P.buffer = NULL; + if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + ssl->buffers.serverDH_G.buffer = NULL; + #endif + + if (InitSSL_Side(ssl, WOLFSSL_CLIENT_END) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error initializing client side"); + } +} +#endif /* OPENSSL_EXTRA */ + + +int wolfSSL_get_shutdown(const WOLFSSL* ssl) +{ + int isShutdown = 0; + + WOLFSSL_ENTER("wolfSSL_get_shutdown"); + + if (ssl) { + /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent * + * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */ + isShutdown = ((ssl->options.closeNotify||ssl->options.connReset) << 1) + | (ssl->options.sentNotify); + } + return isShutdown; +} + + +int wolfSSL_session_reused(WOLFSSL* ssl) +{ + int resuming = 0; + if (ssl) + resuming = ssl->options.resuming; + return resuming; +} + +#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE) +WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session) +{ +#ifdef HAVE_EXT_CACHE + WOLFSSL_SESSION* copy; + + WOLFSSL_ENTER("wolfSSL_SESSION_dup"); + + if (session == NULL) + return NULL; +#ifdef HAVE_SESSION_TICKET + if (session->isDynamic && !session->ticket) { + WOLFSSL_MSG("Session dynamic flag is set but ticket pointer is null"); + return NULL; + } +#endif + + copy = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL, + DYNAMIC_TYPE_OPENSSL); + if (copy != NULL) { + XMEMCPY(copy, session, sizeof(WOLFSSL_SESSION)); + copy->isAlloced = 1; +#ifdef HAVE_SESSION_TICKET + if (session->isDynamic) { + copy->ticket = (byte*)XMALLOC(session->ticketLen, NULL, + DYNAMIC_TYPE_SESSION_TICK); + XMEMCPY(copy->ticket, session->ticket, session->ticketLen); + } else { + copy->ticket = copy->staticTicket; + } +#endif +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + copy->peer = wolfSSL_X509_dup(session->peer); +#endif + } + return copy; +#else + WOLFSSL_MSG("wolfSSL_SESSION_dup was called " + "but HAVE_EXT_CACHE is not defined"); + (void)session; + return NULL; +#endif /* HAVE_EXT_CACHE */ +} + +void wolfSSL_SESSION_free(WOLFSSL_SESSION* session) +{ + if (session == NULL) + return; + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) + if (session->peer) { + wolfSSL_X509_free(session->peer); + } +#endif + +#ifdef HAVE_EXT_CACHE + if (session->isAlloced) { + #ifdef HAVE_SESSION_TICKET + if (session->isDynamic) + XFREE(session->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); + #endif + XFREE(session, NULL, DYNAMIC_TYPE_OPENSSL); + } +#else + /* No need to free since cache is static */ + (void)session; +#endif +} +#endif + + +/* helper function that takes in a protocol version struct and returns string */ +static const char* wolfSSL_internal_get_version(ProtocolVersion* version) +{ + WOLFSSL_ENTER("wolfSSL_get_version"); + + if (version == NULL) { + return "Bad arg"; + } + + if (version->major == SSLv3_MAJOR) { + switch (version->minor) { + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_SSLV3 + case SSLv3_MINOR : + return "SSLv3"; + #endif + #ifdef WOLFSSL_ALLOW_TLSV10 + case TLSv1_MINOR : + return "TLSv1"; + #endif + case TLSv1_1_MINOR : + return "TLSv1.1"; + #endif + case TLSv1_2_MINOR : + return "TLSv1.2"; + #ifdef WOLFSSL_TLS13 + case TLSv1_3_MINOR : + #ifdef WOLFSSL_TLS13_DRAFT + #ifdef WOLFSSL_TLS13_DRAFT_18 + return "TLSv1.3 (Draft 18)"; + #elif defined(WOLFSSL_TLS13_DRAFT_22) + return "TLSv1.3 (Draft 22)"; + #elif defined(WOLFSSL_TLS13_DRAFT_23) + return "TLSv1.3 (Draft 23)"; + #elif defined(WOLFSSL_TLS13_DRAFT_26) + return "TLSv1.3 (Draft 26)"; + #else + return "TLSv1.3 (Draft 28)"; + #endif + #else + return "TLSv1.3"; + #endif + #endif + default: + return "unknown"; + } + } +#ifdef WOLFSSL_DTLS + else if (version->major == DTLS_MAJOR) { + switch (version->minor) { + case DTLS_MINOR : + return "DTLS"; + case DTLSv1_2_MINOR : + return "DTLSv1.2"; + default: + return "unknown"; + } + } +#endif /* WOLFSSL_DTLS */ + return "unknown"; +} + + +const char* wolfSSL_get_version(WOLFSSL* ssl) +{ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument"); + return "unknown"; + } + + return wolfSSL_internal_get_version(&ssl->version); +} + + +/* current library version */ +const char* wolfSSL_lib_version(void) +{ + return LIBWOLFSSL_VERSION_STRING; +} + + +/* current library version in hex */ +word32 wolfSSL_lib_version_hex(void) +{ + return LIBWOLFSSL_VERSION_HEX; +} + + +int wolfSSL_get_current_cipher_suite(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_get_current_cipher_suite"); + if (ssl) + return (ssl->options.cipherSuite0 << 8) | ssl->options.cipherSuite; + return 0; +} + +WOLFSSL_CIPHER* wolfSSL_get_current_cipher(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_get_current_cipher"); + if (ssl) { + ssl->cipher.cipherSuite0 = ssl->options.cipherSuite0; + ssl->cipher.cipherSuite = ssl->options.cipherSuite; + return &ssl->cipher; + } + else + return NULL; +} + + +const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher) +{ + WOLFSSL_ENTER("wolfSSL_CIPHER_get_name"); + + if (cipher == NULL) { + return NULL; + } + + #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) && \ + !defined(WOLFSSL_QT) + return GetCipherNameIana(cipher->cipherSuite0, cipher->cipherSuite); + #else + return wolfSSL_get_cipher_name_from_suite(cipher->cipherSuite0, + cipher->cipherSuite); + #endif +} + +const char* wolfSSL_CIPHER_get_version(const WOLFSSL_CIPHER* cipher) +{ + WOLFSSL_ENTER("SSL_CIPHER_get_version"); + + if (cipher == NULL || cipher->ssl == NULL) { + return NULL; + } + + return wolfSSL_get_version(cipher->ssl); +} + +const char* wolfSSL_SESSION_CIPHER_get_name(WOLFSSL_SESSION* session) +{ + if (session == NULL) { + return NULL; + } + +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) + return GetCipherNameIana(session->cipherSuite0, session->cipherSuite); + #else + return GetCipherNameInternal(session->cipherSuite0, session->cipherSuite); + #endif +#else + return NULL; +#endif +} + +const char* wolfSSL_get_cipher(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_cipher"); + return wolfSSL_CIPHER_get_name(wolfSSL_get_current_cipher(ssl)); +} + +/* gets cipher name in the format DHE-RSA-... rather then TLS_DHE... */ +const char* wolfSSL_get_cipher_name(WOLFSSL* ssl) +{ + /* get access to cipher_name_idx in internal.c */ + return wolfSSL_get_cipher_name_internal(ssl); +} + +const char* wolfSSL_get_cipher_name_from_suite(const byte cipherSuite0, + const byte cipherSuite) +{ + return GetCipherNameInternal(cipherSuite0, cipherSuite); +} + +const char* wolfSSL_get_cipher_name_iana_from_suite(const byte cipherSuite0, + const byte cipherSuite) +{ + return GetCipherNameIana(cipherSuite0, cipherSuite); +} + + +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +/* Creates and returns a new WOLFSSL_CIPHER stack. */ +WOLFSSL_STACK* wolfSSL_sk_new_cipher(void) +{ + WOLFSSL_STACK* sk; + WOLFSSL_ENTER("wolfSSL_sk_new_cipher"); + + sk = wolfSSL_sk_new_null(); + if (sk == NULL) + return NULL; + sk->type = STACK_TYPE_CIPHER; + + return sk; +} + +#ifndef NO_WOLFSSL_STUB +/* Keep as stubs for now */ +/* return 1 on success 0 on fail */ +int wolfSSL_sk_CIPHER_push(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, + WOLFSSL_CIPHER* cipher) +{ + WOLFSSL_STUB("wolfSSL_sk_CIPHER_push"); + (void)sk; + (void)cipher; + return 0; +} + + +WOLFSSL_CIPHER* wolfSSL_sk_CIPHER_pop(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk) +{ + WOLFSSL_STUB("wolfSSL_sk_CIPHER_pop"); + (void)sk; + return NULL; +} +#endif /* NO_WOLFSSL_STUB */ +#endif /* WOLFSSL_QT || OPENSSL_ALL */ + +word32 wolfSSL_CIPHER_get_id(const WOLFSSL_CIPHER* cipher) +{ + word16 cipher_id = 0; + + WOLFSSL_ENTER("SSL_CIPHER_get_id"); + + if (cipher && cipher->ssl) { + cipher_id = (cipher->ssl->options.cipherSuite0 << 8) | + cipher->ssl->options.cipherSuite; + } + + return cipher_id; +} + +const WOLFSSL_CIPHER* wolfSSL_get_cipher_by_value(word16 value) +{ + const WOLFSSL_CIPHER* cipher = NULL; + byte cipherSuite0, cipherSuite; + WOLFSSL_ENTER("SSL_get_cipher_by_value"); + + /* extract cipher id information */ + cipherSuite = (value & 0xFF); + cipherSuite0 = ((value >> 8) & 0xFF); + + /* TODO: lookup by cipherSuite0 / cipherSuite */ + (void)cipherSuite0; + (void)cipherSuite; + + return cipher; +} + + +#if defined(OPENSSL_ALL) +/* Free the structure for WOLFSSL_CIPHER stack + * + * sk stack to free nodes in + */ +void wolfSSL_sk_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk) +{ + WOLFSSL_STACK* node; + WOLFSSL_STACK* tmp; + WOLFSSL_ENTER("wolfSSL_sk_CIPHER_free"); + + if (sk == NULL) + return; + + /* parse through stack freeing each node */ + node = sk->next; + while (node) { + tmp = node; + node = node->next; + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + } + + /* free head of stack */ + XFREE(sk, NULL, DYNAMIC_TYPE_ASN1); +} +#endif + +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) || \ + !defined(NO_DH) +#ifdef HAVE_FFDHE +static const char* wolfssl_ffdhe_name(word16 group) +{ + const char* str = NULL; + switch (group) { + case WOLFSSL_FFDHE_2048: + str = "FFDHE_2048"; + break; + case WOLFSSL_FFDHE_3072: + str = "FFDHE_3072"; + break; + case WOLFSSL_FFDHE_4096: + str = "FFDHE_4096"; + break; + case WOLFSSL_FFDHE_6144: + str = "FFDHE_6144"; + break; + case WOLFSSL_FFDHE_8192: + str = "FFDHE_8192"; + break; + } + return str; +} +#endif +/* Return the name of the curve used for key exchange as a printable string. + * + * ssl The SSL/TLS object. + * returns NULL if ECDH was not used, otherwise the name as a string. + */ +const char* wolfSSL_get_curve_name(WOLFSSL* ssl) +{ + const char* cName = NULL; + + if (ssl == NULL) + return NULL; + +#ifdef HAVE_FFDHE + if (ssl->namedGroup != 0) { + cName = wolfssl_ffdhe_name(ssl->namedGroup); + } +#endif + +#ifdef HAVE_CURVE25519 + if (ssl->ecdhCurveOID == ECC_X25519_OID && cName == NULL) { + cName = "X25519"; + } +#endif + +#ifdef HAVE_CURVE448 + if (ssl->ecdhCurveOID == ECC_X448_OID && cName == NULL) { + cName = "X448"; + } +#endif + +#ifdef HAVE_ECC + if (ssl->ecdhCurveOID != 0 && cName == NULL) { + cName = wc_ecc_get_name(wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, + NULL)); + } +#endif + + return cName; +} +#endif + + +#if defined(OPENSSL_EXTRA_X509_SMALL) || defined(KEEP_PEER_CERT) || \ + defined(SESSION_CERTS) +/* Smaller subset of X509 compatibility functions. Avoid increasing the size of + * this subset and its memory usage */ + +#if !defined(NO_CERTS) +/* returns a pointer to a new WOLFSSL_X509 structure on success and NULL on + * fail + */ +WOLFSSL_X509* wolfSSL_X509_new(void) +{ + WOLFSSL_X509* x509; + + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + if (x509 != NULL) { + InitX509(x509, 1, NULL); + } + + return x509; +} + +WOLFSSL_ABI +WOLFSSL_X509_NAME* wolfSSL_X509_get_subject_name(WOLFSSL_X509* cert) +{ + WOLFSSL_ENTER("wolfSSL_X509_get_subject_name"); + if (cert && cert->subject.sz != 0) + return &cert->subject; + return NULL; +} + +#if defined(OPENSSL_EXTRA) && !defined(NO_SHA) +/****************************************************************************** +* wolfSSL_X509_subject_name_hash - compute the hash digest of the raw subject name +* +* RETURNS: +* The beginning of the hash digest. Otherwise, returns zero. +* Note: +* Returns a different hash value from OpenSSL's X509_subject_name_hash() API +* depending on the subject name. +*/ +unsigned long wolfSSL_X509_subject_name_hash(const WOLFSSL_X509* x509) +{ + word32 ret = 0; + int retHash; + WOLFSSL_X509_NAME *subjectName = NULL; + +#ifdef WOLFSSL_PIC32MZ_HASH + byte digest[PIC32_DIGEST_SIZE]; +#else + byte digest[WC_SHA_DIGEST_SIZE]; +#endif + + if (x509 == NULL){ + return WOLFSSL_FAILURE; + } + + subjectName = wolfSSL_X509_get_subject_name((WOLFSSL_X509*)x509); + + if (subjectName != NULL){ + retHash = wc_ShaHash((const byte*)subjectName->name, + (word32)subjectName->sz, digest); + + if(retHash != 0){ + WOLFSSL_MSG("Hash of X509 subjectName has failed"); + return WOLFSSL_FAILURE; + } + ret = MakeWordFromHash(digest); + } + + return (unsigned long)ret; +} +#endif + +WOLFSSL_ABI +WOLFSSL_X509_NAME* wolfSSL_X509_get_issuer_name(WOLFSSL_X509* cert) +{ + WOLFSSL_ENTER("X509_get_issuer_name"); + if (cert && cert->issuer.sz != 0) + return &cert->issuer; + return NULL; +} + + +int wolfSSL_X509_get_signature_type(WOLFSSL_X509* x509) +{ + int type = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_signature_type"); + + if (x509 != NULL) + type = x509->sigOID; + + return type; +} + +#if defined(OPENSSL_EXTRA_X509_SMALL) + +/* Used to get a string from the WOLFSSL_X509_NAME structure that + * corresponds with the NID value passed in. + * + * name structure to get string from + * nid NID value to search for + * buf [out] buffer to hold results. If NULL then the buffer size minus the + * null char is returned. + * len size of "buf" passed in + * + * returns the length of string found, not including the NULL terminator. + * It's possible the function could return a negative value in the + * case that len is less than or equal to 0. A negative value is + * considered an error case. + */ +int wolfSSL_X509_NAME_get_text_by_NID(WOLFSSL_X509_NAME* name, + int nid, char* buf, int len) +{ + char *text = NULL; + int textSz = 0; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_get_text_by_NID"); + + switch (nid) { + case ASN_COMMON_NAME: + text = name->fullName.fullName + name->fullName.cnIdx; + textSz = name->fullName.cnLen; + break; + case ASN_SUR_NAME: + text = name->fullName.fullName + name->fullName.snIdx; + textSz = name->fullName.snLen; + break; + case ASN_SERIAL_NUMBER: + text = name->fullName.fullName + name->fullName.serialIdx; + textSz = name->fullName.serialLen; + break; + case ASN_COUNTRY_NAME: + text = name->fullName.fullName + name->fullName.cIdx; + textSz = name->fullName.cLen; + break; + case ASN_LOCALITY_NAME: + text = name->fullName.fullName + name->fullName.lIdx; + textSz = name->fullName.lLen; + break; + case ASN_STATE_NAME: + text = name->fullName.fullName + name->fullName.stIdx; + textSz = name->fullName.stLen; + break; + case ASN_ORG_NAME: + text = name->fullName.fullName + name->fullName.oIdx; + textSz = name->fullName.oLen; + break; + case ASN_ORGUNIT_NAME: + text = name->fullName.fullName + name->fullName.ouIdx; + textSz = name->fullName.ouLen; + break; + case ASN_DOMAIN_COMPONENT: + text = name->fullName.fullName + name->fullName.dcIdx[0]; + textSz = name->fullName.dcLen[0]; + break; + case NID_emailAddress: + text = name->fullName.fullName + name->fullName.emailIdx; + textSz = name->fullName.emailLen; + break; + #ifdef WOLFSSL_CERT_EXT + case ASN_BUS_CAT: + text = name->fullName.fullName + name->fullName.bcIdx; + textSz = name->fullName.bcLen; + break; + #endif + default: + WOLFSSL_MSG("Entry type not found"); + return WOLFSSL_FATAL_ERROR; + } + + /* if buf is NULL return size of buffer needed (minus null char) */ + if (buf == NULL) { + return textSz; + } + + if (buf != NULL && text != NULL) { + textSz = min(textSz + 1, len); /* + 1 to account for null char */ + if (textSz > 0) { + XMEMCPY(buf, text, textSz - 1); + buf[textSz - 1] = '\0'; + } + } + + WOLFSSL_LEAVE("wolfSSL_X509_NAME_get_text_by_NID", textSz); + return (textSz - 1); /* do not include null character in size */ +} + +/* Creates a new WOLFSSL_EVP_PKEY structure that has the public key from x509 + * + * returns a pointer to the created WOLFSSL_EVP_PKEY on success and NULL on fail + */ +WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) +{ + WOLFSSL_EVP_PKEY* key = NULL; + WOLFSSL_ENTER("X509_get_pubkey"); + if (x509 != NULL) { + key = wolfSSL_EVP_PKEY_new_ex(x509->heap); + if (key != NULL) { + if (x509->pubKeyOID == RSAk) { + key->type = EVP_PKEY_RSA; + } + else if (x509->pubKeyOID == DSAk) { + key->type = EVP_PKEY_DSA; + } + 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) { + wolfSSL_EVP_PKEY_free(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) { + wolfSSL_EVP_PKEY_free(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) { + wolfSSL_EVP_PKEY_free(key); + return NULL; + } + } + #endif /* NO_RSA */ + + /* decode ECC key */ + #if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) + if (key->type == EVP_PKEY_EC) { + word32 idx = 0; + + key->ownEcc = 1; + key->ecc = wolfSSL_EC_KEY_new(); + if (key->ecc == NULL || key->ecc->internal == NULL) { + wolfSSL_EVP_PKEY_free(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_EccPublicKeyDecode((const unsigned char*)key->pkey.ptr, + &idx, (ecc_key*)key->ecc->internal, key->pkey_sz) < 0) { + WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); + wolfSSL_EVP_PKEY_free(key); + return NULL; + } + + if (SetECKeyExternal(key->ecc) != SSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyExternal failed"); + wolfSSL_EVP_PKEY_free(key); + return NULL; + } + + key->ecc->inSet = 1; + } + #endif /* HAVE_ECC */ + + #ifndef NO_DSA + if (key->type == EVP_PKEY_DSA) { + key->ownDsa = 1; + key->dsa = wolfSSL_DSA_new(); + if (key->dsa == NULL) { + wolfSSL_EVP_PKEY_free(key); + return NULL; + } + + if (wolfSSL_DSA_LoadDer_ex(key->dsa, + (const unsigned char*)key->pkey.ptr, key->pkey_sz, \ + WOLFSSL_DSA_LOAD_PUBLIC) != SSL_SUCCESS) { + wolfSSL_DSA_free(key->dsa); + key->dsa = NULL; + wolfSSL_EVP_PKEY_free(key); + return NULL; + } + } + #endif /* NO_DSA */ + } + } + return key; +} +#endif /* OPENSSL_EXTRA_X509_SMALL */ +#endif /* !NO_CERTS */ + +/* End of smaller subset of X509 compatibility functions. Avoid increasing the + * size of this subset and its memory usage */ +#endif /* OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_ALL) +/* Takes two WOLFSSL_X509* certificates and performs a Sha hash of each, if the + * has values are the same, then it will do an XMEMCMP to confirm they are + * identical. Returns a 0 when certificates match, returns a negative number + * when certificates are not a match. +*/ +int wolfSSL_X509_cmp(const WOLFSSL_X509 *a, const WOLFSSL_X509 *b) +{ + const byte* derA; + const byte* derB; + int retHashA; + int retHashB; + int outSzA = 0; + int outSzB = 0; + + #ifdef WOLFSSL_PIC32MZ_HASH + byte digestA[PIC32_DIGEST_SIZE]; + byte digestB[PIC32_DIGEST_SIZE]; + #else + byte digestA[WC_SHA_DIGEST_SIZE]; + byte digestB[WC_SHA_DIGEST_SIZE]; + #endif + + if (a == NULL || b == NULL){ + return BAD_FUNC_ARG; + } + + derA = wolfSSL_X509_get_der((WOLFSSL_X509*)a, &outSzA); + if(derA == NULL){ + WOLFSSL_MSG("wolfSSL_X509_get_der - certificate A has failed"); + return WOLFSSL_FATAL_ERROR; + } + derB = wolfSSL_X509_get_der((WOLFSSL_X509*)b, &outSzB); + if(derB == NULL){ + WOLFSSL_MSG("wolfSSL_X509_get_der - certificate B has failed"); + return WOLFSSL_FATAL_ERROR; + } + + retHashA = wc_ShaHash(derA, (word32)outSzA, digestA); + if(retHashA != 0){ + WOLFSSL_MSG("Hash of certificate A has failed"); + return WOLFSSL_FATAL_ERROR; + } + retHashB = wc_ShaHash(derB, (word32)outSzB, digestB); + if(retHashB != 0){ + WOLFSSL_MSG("Hash of certificate B has failed"); + return WOLFSSL_FATAL_ERROR; + } + + if (outSzA == outSzB){ + #ifdef WOLFSSL_PIC32MZ_HASH + if(XMEMCMP(digestA, digestB, PIC32_DIGEST_SIZE) != 0){ + return WOLFSSL_FATAL_ERROR; + } + #else + if(XMEMCMP(digestA, digestB, WC_SHA_DIGEST_SIZE) != 0){ + return WOLFSSL_FATAL_ERROR; + } + #endif + else{ + WOLFSSL_LEAVE("wolfSSL_X509_cmp", 0); + return 0; + } + } + else{ + WOLFSSL_LEAVE("wolfSSL_X509_cmp", WOLFSSL_FATAL_ERROR); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + +#if defined(OPENSSL_EXTRA) +#if !defined(NO_CERTS) + int wolfSSL_X509_ext_isSet_by_NID(WOLFSSL_X509* x509, int nid) + { + int isSet = 0; + + WOLFSSL_ENTER("wolfSSL_X509_ext_isSet_by_NID"); + + if (x509 != NULL) { + switch (nid) { + case BASIC_CA_OID: isSet = x509->basicConstSet; break; + case ALT_NAMES_OID: isSet = x509->subjAltNameSet; break; + case AUTH_KEY_OID: isSet = x509->authKeyIdSet; break; + case SUBJ_KEY_OID: isSet = x509->subjKeyIdSet; break; + case KEY_USAGE_OID: isSet = x509->keyUsageSet; break; + case CRL_DIST_OID: isSet = x509->CRLdistSet; break; + case EXT_KEY_USAGE_OID: isSet = ((x509->extKeyUsageSrc) ? 1 : 0); + break; + case AUTH_INFO_OID: isSet = x509->authInfoSet; break; + #if defined(WOLFSSL_SEP) || defined(WOLFSSL_QT) + case CERT_POLICY_OID: isSet = x509->certPolicySet; break; + #endif /* WOLFSSL_SEP || WOLFSSL_QT */ + default: + WOLFSSL_MSG("NID not in table"); + } + } + + WOLFSSL_LEAVE("wolfSSL_X509_ext_isSet_by_NID", isSet); + + return isSet; + } + + + int wolfSSL_X509_ext_get_critical_by_NID(WOLFSSL_X509* x509, int nid) + { + int crit = 0; + + WOLFSSL_ENTER("wolfSSL_X509_ext_get_critical_by_NID"); + + if (x509 != NULL) { + switch (nid) { + case BASIC_CA_OID: crit = x509->basicConstCrit; break; + case ALT_NAMES_OID: crit = x509->subjAltNameCrit; break; + case AUTH_KEY_OID: crit = x509->authKeyIdCrit; break; + case SUBJ_KEY_OID: crit = x509->subjKeyIdCrit; break; + case KEY_USAGE_OID: crit = x509->keyUsageCrit; break; + case CRL_DIST_OID: crit= x509->CRLdistCrit; break; + #if defined(WOLFSSL_SEP) || defined(WOLFSSL_QT) + case CERT_POLICY_OID: crit = x509->certPolicyCrit; break; + #endif /* WOLFSSL_SEP || WOLFSSL_QT */ + } + } + + WOLFSSL_LEAVE("wolfSSL_X509_ext_get_critical_by_NID", crit); + + return crit; + } + + + int wolfSSL_X509_get_isSet_pathLength(WOLFSSL_X509* x509) + { + int isSet = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_isSet_pathLength"); + + if (x509 != NULL) + isSet = x509->basicConstPlSet; + + WOLFSSL_LEAVE("wolfSSL_X509_get_isSet_pathLength", isSet); + + return isSet; + } + + + word32 wolfSSL_X509_get_pathLength(WOLFSSL_X509* x509) + { + word32 pathLength = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_pathLength"); + + if (x509 != NULL) + pathLength = x509->pathLength; + + WOLFSSL_LEAVE("wolfSSL_X509_get_pathLength", pathLength); + + return pathLength; + } + + + unsigned int wolfSSL_X509_get_keyUsage(WOLFSSL_X509* x509) + { + word16 usage = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_keyUsage"); + + if (x509 != NULL) + usage = x509->keyUsage; + + WOLFSSL_LEAVE("wolfSSL_X509_get_keyUsage", usage); + + return usage; + } + + + byte* wolfSSL_X509_get_authorityKeyID(WOLFSSL_X509* x509, + byte* dst, int* dstLen) + { + byte *id = NULL; + int copySz = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_authorityKeyID"); + + if (x509 != NULL) { + if (x509->authKeyIdSet) { + copySz = min(dstLen != NULL ? *dstLen : 0, + (int)x509->authKeyIdSz); + id = x509->authKeyId; + } + + if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) { + XMEMCPY(dst, id, copySz); + id = dst; + *dstLen = copySz; + } + } + + WOLFSSL_LEAVE("wolfSSL_X509_get_authorityKeyID", copySz); + + return id; + } + + + byte* wolfSSL_X509_get_subjectKeyID(WOLFSSL_X509* x509, + byte* dst, int* dstLen) + { + byte *id = NULL; + int copySz = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_subjectKeyID"); + + if (x509 != NULL) { + if (x509->subjKeyIdSet) { + copySz = min(dstLen != NULL ? *dstLen : 0, + (int)x509->subjKeyIdSz); + id = x509->subjKeyId; + } + + if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) { + XMEMCPY(dst, id, copySz); + id = dst; + *dstLen = copySz; + } + } + + WOLFSSL_LEAVE("wolfSSL_X509_get_subjectKeyID", copySz); + + return id; + } + + + int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name) + { + int count = 0; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count"); + + if (name != NULL) + count = name->fullName.locSz; + + WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count); + return count; + } + + + + int wolfSSL_X509_NAME_get_index_by_NID(WOLFSSL_X509_NAME* name, + int nid, int pos) + { + int value = nid, i; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_get_index_by_NID"); + + if (name == NULL || pos >= DN_NAMES_MAX + DOMAIN_COMPONENT_MAX) { + return BAD_FUNC_ARG; + } + + if (value == NID_emailAddress) { + value = ASN_EMAIL_NAME; + } + + i = pos + 1; /* start search after index passed in */ + if (i < 0) { + i = 0; + } + + for (;i < name->fullName.locSz && + i < DN_NAMES_MAX + DOMAIN_COMPONENT_MAX; i++) { + if (name->fullName.loc[i] == value) { + return i; + } + } + return WOLFSSL_FATAL_ERROR; + } + + + WOLFSSL_ASN1_STRING* wolfSSL_X509_NAME_ENTRY_get_data( + WOLFSSL_X509_NAME_ENTRY* in) + { + WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_data"); + if (in == NULL) + return NULL; + + return in->value; + } + + + /* Creates a new WOLFSSL_ASN1_STRING structure. + * + * returns a pointer to the new structure created on success or NULL if fail + */ + WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_new(void) + { + WOLFSSL_ASN1_STRING* asn1; + + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_new"); + + asn1 = (WOLFSSL_ASN1_STRING*)XMALLOC(sizeof(WOLFSSL_ASN1_STRING), NULL, + DYNAMIC_TYPE_OPENSSL); + if (asn1 != NULL) { + XMEMSET(asn1, 0, sizeof(WOLFSSL_ASN1_STRING)); + } + + return asn1; /* no check for null because error case is returning null*/ + } + + + /* used to free a WOLFSSL_ASN1_STRING structure */ + void wolfSSL_ASN1_STRING_free(WOLFSSL_ASN1_STRING* asn1) + { + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_free"); + + if (asn1 != NULL) { + if (asn1->length > 0 && asn1->data != NULL && asn1->isDynamic) { + XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); + } + XFREE(asn1, NULL, DYNAMIC_TYPE_OPENSSL); + } + } + + + /* Creates a new WOLFSSL_ASN1_STRING structure given the input type. + * + * type is the type of set when WOLFSSL_ASN1_STRING is created + * + * returns a pointer to the new structure created on success or NULL if fail + */ + WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_type_new(int type) + { + WOLFSSL_ASN1_STRING* asn1; + + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_type_new"); + + asn1 = wolfSSL_ASN1_STRING_new(); + if (asn1 == NULL) { + return NULL; + } + asn1->type = type; + + return asn1; + } + + +/****************************************************************************** +* wolfSSL_ASN1_STRING_type - returns the type of +* +* RETURNS: +* returns the type set for . Otherwise, returns WOLFSSL_FAILURE. +*/ + int wolfSSL_ASN1_STRING_type(const WOLFSSL_ASN1_STRING* asn1) + { + + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_type"); + + if (asn1 == NULL) { + return WOLFSSL_FAILURE; + } + + return asn1->type; + } + + /* if dataSz is negative then use XSTRLEN to find length of data + * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */ + /* `data` can be NULL and only buffer will be allocated */ + int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, + int dataSz) + { + int sz; + + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_set"); + + if (asn1 == NULL || (data == NULL && dataSz < 0)) { + return WOLFSSL_FAILURE; + } + + if (dataSz < 0) { + sz = (int)XSTRLEN((const char*)data) + 1; /* +1 for null */ + } + else { + sz = dataSz; + } + + if (sz < 0) { + return WOLFSSL_FAILURE; + } + + /* free any existing data before copying */ + if (asn1->data != NULL && asn1->isDynamic) { + XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); + asn1->data = NULL; + } + + if (sz > CTC_NAME_SIZE) { + /* create new data buffer and copy over */ + asn1->data = (char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL); + if (asn1->data == NULL) { + return WOLFSSL_FAILURE; + } + asn1->isDynamic = 1; + } + else { + XMEMSET(asn1->strData, 0, CTC_NAME_SIZE); + asn1->data = asn1->strData; + asn1->isDynamic = 0; + } + if (data != NULL) { + XMEMCPY(asn1->data, data, sz); + asn1->data[sz] = '\0'; + } + asn1->length = sz; + + return WOLFSSL_SUCCESS; + } + + + unsigned char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING* asn) + { + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_data"); + + if (asn) { + return (unsigned char*)asn->data; + } + else { + return NULL; + } + } + + + int wolfSSL_ASN1_STRING_length(WOLFSSL_ASN1_STRING* asn) + { + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_length"); + + if (asn) { + return asn->length; + } + else { + return 0; + } + } + +#ifndef NO_WOLFSSL_STUB + WOLFSSL_ASN1_STRING* wolfSSL_d2i_DISPLAYTEXT(WOLFSSL_ASN1_STRING **asn, + const unsigned char **in, long len) + { + WOLFSSL_STUB("d2i_DISPLAYTEXT"); + (void)asn; + (void)in; + (void)len; + return NULL; + } +#endif + +#ifdef XSNPRINTF /* a snprintf function needs to be available */ + /* Writes the human readable form of x509 to bio. + * + * bio WOLFSSL_BIO to write to. + * x509 Certificate to write. + * + * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure + */ + int wolfSSL_X509_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, + unsigned long nmflags, unsigned long cflag) + { + WOLFSSL_ENTER("wolfSSL_X509_print_ex"); + + #ifndef NO_WOLFSSL_STUB + /* flags currently not supported */ + (void)nmflags; + (void)cflag; + #endif + + if (bio == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, "Certificate:\n", + (int)XSTRLEN("Certificate:\n")) <= 0) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, " Data:\n", + (int)XSTRLEN(" Data:\n")) <= 0) { + return WOLFSSL_FAILURE; + } + + /* print version of cert */ + { + int version; + char tmp[20]; + + if ((version = wolfSSL_X509_version(x509)) < 0) { + WOLFSSL_MSG("Error getting X509 version"); + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_write(bio, " Version:", + (int)XSTRLEN(" Version:")) <= 0) { + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp), " %d (0x%x)\n", version, (byte)version-1); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + + /* print serial number out */ + { + unsigned char serial[32]; + int sz = sizeof(serial); + + XMEMSET(serial, 0, sz); + if (wolfSSL_X509_get_serial_number(x509, serial, &sz) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error getting x509 serial number"); + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_write(bio, " Serial Number:", + (int)XSTRLEN(" Serial Number:")) <= 0) { + return WOLFSSL_FAILURE; + } + + /* if serial can fit into byte than print on the same line */ + if (sz <= (int)sizeof(byte)) { + char tmp[17]; + XSNPRINTF(tmp, sizeof(tmp), " %d (0x%x)\n", serial[0],serial[0]); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + else { + int i; + char tmp[100]; + int tmpSz = 100; + char val[5]; + int valSz = 5; + + /* serial is larger than int size so print off hex values */ + if (wolfSSL_BIO_write(bio, "\n ", + (int)XSTRLEN("\n ")) <= 0) { + return WOLFSSL_FAILURE; + } + tmp[0] = '\0'; + for (i = 0; i < sz - 1 && (3 * i) < tmpSz - valSz; i++) { + XSNPRINTF(val, sizeof(val) - 1, "%02x:", serial[i]); + val[3] = '\0'; /* make sure is null terminated */ + XSTRNCAT(tmp, val, valSz); + } + XSNPRINTF(val, sizeof(val) - 1, "%02x\n", serial[i]); + val[3] = '\0'; /* make sure is null terminated */ + XSTRNCAT(tmp, val, valSz); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + } + + /* print signature algo */ + { + int oid; + const char* sig; + + if ((oid = wolfSSL_X509_get_signature_type(x509)) <= 0) { + WOLFSSL_MSG("Error getting x509 signature type"); + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_write(bio, " Signature Algorithm: ", + (int)XSTRLEN(" Signature Algorithm: ")) <= 0) { + return WOLFSSL_FAILURE; + } + sig = GetSigName(oid); + if (wolfSSL_BIO_write(bio, sig, (int)XSTRLEN(sig)) <= 0) { + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_write(bio, "\n", (int)XSTRLEN("\n")) <= 0) { + return WOLFSSL_FAILURE; + } + } + + /* print issuer */ + { + char* issuer; + #ifdef WOLFSSL_SMALL_STACK + char* buff = NULL; + int issSz = 0; + #else + char buff[256]; + int issSz = 256; + #endif + + #if defined(WOLFSSL_QT) + issuer = wolfSSL_X509_get_name_oneline( + wolfSSL_X509_get_issuer_name(x509), buff, issSz); + #else + issuer = wolfSSL_X509_NAME_oneline( + wolfSSL_X509_get_issuer_name(x509), buff, issSz); + #endif + + if (wolfSSL_BIO_write(bio, " Issuer: ", + (int)XSTRLEN(" Issuer: ")) <= 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL); + #endif + return WOLFSSL_FAILURE; + } + if (issuer != NULL) { + if (wolfSSL_BIO_write(bio, issuer, (int)XSTRLEN(issuer)) <= 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL); + #endif + return WOLFSSL_FAILURE; + } + } + #ifdef WOLFSSL_SMALL_STACK + XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL); + #endif + if (wolfSSL_BIO_write(bio, "\n", (int)XSTRLEN("\n")) <= 0) { + return WOLFSSL_FAILURE; + } + } + + #ifndef NO_ASN_TIME + /* print validity */ + { + char tmp[80]; + + if (wolfSSL_BIO_write(bio, " Validity\n", + (int)XSTRLEN(" Validity\n")) <= 0) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, " Not Before: ", + (int)XSTRLEN(" Not Before: ")) <= 0) { + return WOLFSSL_FAILURE; + } + if (x509->notBefore.length > 0) { + if (GetTimeString(x509->notBefore.data, ASN_UTC_TIME, + tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + if (GetTimeString(x509->notBefore.data, ASN_GENERALIZED_TIME, + tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error getting not before date"); + return WOLFSSL_FAILURE; + } + } + } + else { + XSTRNCPY(tmp, "Not Set", sizeof(tmp)-1); + } + tmp[sizeof(tmp) - 1] = '\0'; /* make sure null terminated */ + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, "\n Not After : ", + (int)XSTRLEN("\n Not After : ")) <= 0) { + return WOLFSSL_FAILURE; + } + if (x509->notAfter.length > 0) { + if (GetTimeString(x509->notAfter.data, ASN_UTC_TIME, + tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + if (GetTimeString(x509->notAfter.data, ASN_GENERALIZED_TIME, + tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error getting not after date"); + return WOLFSSL_FAILURE; + } + } + } + else { + XSTRNCPY(tmp, "Not Set", sizeof(tmp)-1); + } + tmp[sizeof(tmp) - 1] = '\0'; /* make sure null terminated */ + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + #endif + + /* print subject */ + { + char* subject; + #ifdef WOLFSSL_SMALL_STACK + char* buff = NULL; + int subSz = 0; + #else + char buff[256]; + int subSz = 256; + #endif + + #if defined(WOLFSSL_QT) + subject = wolfSSL_X509_get_name_oneline( + wolfSSL_X509_get_subject_name(x509), buff, subSz); + #else + subject = wolfSSL_X509_NAME_oneline( + wolfSSL_X509_get_subject_name(x509), buff, subSz); + #endif + + if (wolfSSL_BIO_write(bio, "\n Subject: ", + (int)XSTRLEN("\n Subject: ")) <= 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL); + #endif + return WOLFSSL_FAILURE; + } + if (subject != NULL) { + if (wolfSSL_BIO_write(bio, subject, (int)XSTRLEN(subject)) <= 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL); + #endif + return WOLFSSL_FAILURE; + } + } + #ifdef WOLFSSL_SMALL_STACK + XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL); + #endif + } + + /* get and print public key */ + if (wolfSSL_BIO_write(bio, "\n Subject Public Key Info:\n", + (int)XSTRLEN("\n Subject Public Key Info:\n")) <= 0) { + return WOLFSSL_FAILURE; + } + { + #if (!defined(NO_RSA) && !defined(HAVE_USER_RSA)) || defined(HAVE_ECC) + char tmp[100]; + #endif + + switch (x509->pubKeyOID) { + #ifndef NO_RSA + case RSAk: + if (wolfSSL_BIO_write(bio, + " Public Key Algorithm: rsaEncryption\n", + (int)XSTRLEN(" Public Key Algorithm: rsaEncryption\n")) <= 0) { + return WOLFSSL_FAILURE; + } + #ifdef HAVE_USER_RSA + if (wolfSSL_BIO_write(bio, + " Build without user RSA to print key\n", + (int)XSTRLEN(" Build without user RSA to print key\n")) + <= 0) { + return WOLFSSL_FAILURE; + } + #else + { + RsaKey rsa; + word32 idx = 0; + int sz; + byte lbit = 0; + int rawLen; + unsigned char* rawKey; + + if (wc_InitRsaKey(&rsa, NULL) != 0) { + WOLFSSL_MSG("wc_InitRsaKey failure"); + return WOLFSSL_FAILURE; + } + if (wc_RsaPublicKeyDecode(x509->pubKey.buffer, + &idx, &rsa, x509->pubKey.length) != 0) { + WOLFSSL_MSG("Error decoding RSA key"); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + if ((sz = wc_RsaEncryptSize(&rsa)) < 0) { + WOLFSSL_MSG("Error getting RSA key size"); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1, "%s%s: (%d bit)\n%s\n", + " ", "Public-Key", 8 * sz, + " Modulus:"); + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + + /* print out modulus */ + XSNPRINTF(tmp, sizeof(tmp) - 1," "); + tmp[sizeof(tmp) - 1] = '\0'; + if (mp_leading_bit(&rsa.n)) { + lbit = 1; + XSTRNCAT(tmp, "00", 3); + } + + rawLen = mp_unsigned_bin_size(&rsa.n); + rawKey = (unsigned char*)XMALLOC(rawLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (rawKey == NULL) { + WOLFSSL_MSG("Memory error"); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + mp_to_unsigned_bin(&rsa.n, rawKey); + for (idx = 0; idx < (word32)rawLen; idx++) { + char val[5]; + int valSz = 5; + + if ((idx == 0) && !lbit) { + XSNPRINTF(val, valSz - 1, "%02x", rawKey[idx]); + } + else if ((idx != 0) && (((idx + lbit) % 15) == 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + XFREE(rawKey, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1, + ":\n "); + XSNPRINTF(val, valSz - 1, "%02x", rawKey[idx]); + } + else { + XSNPRINTF(val, valSz - 1, ":%02x", rawKey[idx]); + } + XSTRNCAT(tmp, val, valSz); + } + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + /* print out remaining modulus values */ + if ((idx > 0) && (((idx - 1 + lbit) % 15) != 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + + /* print out exponent values */ + rawLen = mp_unsigned_bin_size(&rsa.e); + if (rawLen < 0) { + WOLFSSL_MSG("Error getting exponent size"); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + + if ((word32)rawLen < sizeof(word32)) { + rawLen = sizeof(word32); + } + rawKey = (unsigned char*)XMALLOC(rawLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (rawKey == NULL) { + WOLFSSL_MSG("Memory error"); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + XMEMSET(rawKey, 0, rawLen); + mp_to_unsigned_bin(&rsa.e, rawKey); + if ((word32)rawLen <= sizeof(word32)) { + idx = *(word32*)rawKey; + #ifdef BIG_ENDIAN_ORDER + idx = ByteReverseWord32(idx); + #endif + } + XSNPRINTF(tmp, sizeof(tmp) - 1, + "\n Exponent: %d (0x%x)\n",idx, idx); + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wc_FreeRsaKey(&rsa); + return WOLFSSL_FAILURE; + } + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wc_FreeRsaKey(&rsa); + } + #endif /* HAVE_USER_RSA */ + break; + #endif /* NO_RSA */ + + #ifdef HAVE_ECC + case ECDSAk: + { + word32 i; + ecc_key ecc; + + if (wolfSSL_BIO_write(bio, + " Public Key Algorithm: EC\n", + (int)XSTRLEN(" Public Key Algorithm: EC\n")) <= 0) { + return WOLFSSL_FAILURE; + } + if (wc_ecc_init_ex(&ecc, x509->heap, INVALID_DEVID) + != 0) { + return WOLFSSL_FAILURE; + } + + i = 0; + if (wc_EccPublicKeyDecode(x509->pubKey.buffer, &i, + &ecc, x509->pubKey.length) != 0) { + wc_ecc_free(&ecc); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1, "%s%s: (%d bit)\n%s\n", + " ", "Public-Key", + 8 * wc_ecc_size(&ecc), + " pub:"); + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + wc_ecc_free(&ecc); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1," "); + { + word32 derSz; + byte* der; + + derSz = wc_ecc_size(&ecc) * WOLFSSL_BIT_SIZE; + der = (byte*)XMALLOC(derSz, x509->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + wc_ecc_free(&ecc); + return WOLFSSL_FAILURE; + } + + if (wc_ecc_export_x963(&ecc, der, &derSz) != 0) { + wc_ecc_free(&ecc); + XFREE(der, x509->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + for (i = 0; i < derSz; i++) { + char val[5]; + int valSz = 5; + + if (i == 0) { + XSNPRINTF(val, valSz - 1, "%02x", der[i]); + } + else if ((i % 15) == 0) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + wc_ecc_free(&ecc); + XFREE(der, x509->heap, + DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1, + ":\n "); + XSNPRINTF(val, valSz - 1, "%02x", der[i]); + } + else { + XSNPRINTF(val, valSz - 1, ":%02x", der[i]); + } + XSTRNCAT(tmp, val, valSz); + } + + /* print out remaining modulus values */ + if ((i > 0) && (((i - 1) % 15) != 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + wc_ecc_free(&ecc); + XFREE(der, x509->heap, + DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + } + + XFREE(der, x509->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + XSNPRINTF(tmp, sizeof(tmp) - 1, "\n%s%s: %s\n", + " ", "ASN1 OID", + ecc.dp->name); + if (wolfSSL_BIO_write(bio, tmp, + (int)XSTRLEN(tmp)) <= 0) { + wc_ecc_free(&ecc); + return WOLFSSL_FAILURE; + } + wc_ecc_free(&ecc); + } + break; + #endif /* HAVE_ECC */ + default: + WOLFSSL_MSG("Unknown key type"); + return WOLFSSL_FAILURE; + } + } + + /* print out extensions */ + if (wolfSSL_BIO_write(bio, " X509v3 extensions:\n", + (int)XSTRLEN(" X509v3 extensions:\n")) <= 0) { + return WOLFSSL_FAILURE; + } + + /* print subject key id */ + if (x509->subjKeyIdSet && x509->subjKeyId != NULL && + x509->subjKeyIdSz > 0) { + char tmp[100]; + word32 i; + char val[5]; + int valSz = 5; + + + if (wolfSSL_BIO_write(bio, + " X509v3 Subject Key Identifier: \n", + (int)XSTRLEN(" X509v3 Subject Key Identifier: \n")) + <= 0) { + return WOLFSSL_FAILURE; + } + + XSNPRINTF(tmp, sizeof(tmp) - 1, " "); + for (i = 0; i < sizeof(tmp) && i < (x509->subjKeyIdSz - 1); i++) { + XSNPRINTF(val, valSz - 1, "%02X:", x509->subjKeyId[i]); + XSTRNCAT(tmp, val, valSz); + } + XSNPRINTF(val, valSz - 1, "%02X\n", x509->subjKeyId[i]); + XSTRNCAT(tmp, val, valSz); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + + /* printf out authority key id */ + if (x509->authKeyIdSet && x509->authKeyId != NULL && + x509->authKeyIdSz > 0) { + char tmp[100]; + word32 i; + char val[5]; + int valSz = 5; + int len = 0; + + if (wolfSSL_BIO_write(bio, + " X509v3 Authority Key Identifier: \n", + (int)XSTRLEN(" X509v3 Authority Key Identifier: \n")) + <= 0) { + return WOLFSSL_FAILURE; + } + + XSNPRINTF(tmp, sizeof(tmp) - 1, " keyid"); + for (i = 0; i < x509->authKeyIdSz; i++) { + /* check if buffer is almost full */ + if (XSTRLEN(tmp) >= sizeof(tmp) - valSz) { + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + tmp[0] = '\0'; + } + XSNPRINTF(val, valSz - 1, ":%02X", x509->authKeyId[i]); + XSTRNCAT(tmp, val, valSz); + } + len = (int)XSTRLEN("\n"); + XSTRNCAT(tmp, "\n", len + 1); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + + /* print basic constraint */ + if (x509->basicConstSet) { + char tmp[100]; + + if (wolfSSL_BIO_write(bio, + "\n X509v3 Basic Constraints: \n", + (int)XSTRLEN("\n X509v3 Basic Constraints: \n")) + <= 0) { + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp), + " CA:%s\n", + (x509->isCa)? "TRUE": "FALSE"); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + + /* print out signature */ + if (x509->sig.length > 0) { + unsigned char* sig; + int sigSz; + int i; + char tmp[100]; + int sigOid = wolfSSL_X509_get_signature_type(x509); + + if (wolfSSL_BIO_write(bio, + " Signature Algorithm: ", + (int)XSTRLEN(" Signature Algorithm: ")) <= 0) { + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1,"%s\n", GetSigName(sigOid)); + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + + sigSz = (int)x509->sig.length; + sig = (unsigned char*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sig == NULL) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_X509_get_signature(x509, sig, &sigSz) <= 0) { + XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1," "); + tmp[sizeof(tmp) - 1] = '\0'; + for (i = 0; i < sigSz; i++) { + char val[5]; + int valSz = 5; + + if (i == 0) { + XSNPRINTF(val, valSz - 1, "%02x", sig[i]); + } + else if (((i % 18) == 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) + <= 0) { + XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1, + ":\n "); + XSNPRINTF(val, valSz - 1, "%02x", sig[i]); + } + else { + XSNPRINTF(val, valSz - 1, ":%02x", sig[i]); + } + XSTRNCAT(tmp, val, valSz); + } + XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + /* print out remaining sig values */ + if ((i > 0) && (((i - 1) % 18) != 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) + <= 0) { + return WOLFSSL_FAILURE; + } + } + } + + /* done with print out */ + if (wolfSSL_BIO_write(bio, "\n\0", (int)XSTRLEN("\n\0")) <= 0) { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; + } + int wolfSSL_X509_print(WOLFSSL_BIO* bio, WOLFSSL_X509* x509) + { + return wolfSSL_X509_print_ex(bio, x509, 0, 0); + } + +#endif /* XSNPRINTF */ + +#endif /* NO_CERTS */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) +/* Creates cipher->description based on cipher->offset + * cipher->offset is set in wolfSSL_get_ciphers_compat when it is added + * to a stack of ciphers. + * @param [in] cipher: A cipher from a stack of ciphers. + * return WOLFSSL_SUCCESS if cipher->description is set, else WOLFSSL_FAILURE + */ +int wolfSSL_sk_CIPHER_description(WOLFSSL_CIPHER* cipher) +{ + int ret = WOLFSSL_FAILURE; + int i,j,k; + int strLen; + unsigned long offset; + char* dp; + const char* name; + const char *keaStr, *authStr, *encStr, *macStr, *protocol; + char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; + unsigned char len = MAX_DESCRIPTION_SZ-1; + const CipherSuiteInfo* cipher_names; + ProtocolVersion pv; + WOLFSSL_ENTER("wolfSSL_sk_CIPHER_description"); + + if (cipher == NULL) + return WOLFSSL_FAILURE; + + dp = cipher->description; + if (dp == NULL) + return WOLFSSL_FAILURE; + + cipher_names = GetCipherNames(); + + offset = cipher->offset; + pv.major = cipher_names[offset].major; + pv.minor = cipher_names[offset].minor; + protocol = wolfSSL_internal_get_version(&pv); + + name = cipher_names[offset].name; + + if (name == NULL) + return ret; + + /* Segment cipher name into n[n0,n1,n2,n4] + * These are used later for comparisons to create: + * keaStr, authStr, encStr, macStr + * + * If cipher_name = ECDHE-ECDSA-AES256-SHA + * then n0 = "ECDHE", n1 = "ECDSA", n2 = "AES256", n3 = "SHA" + * and n = [n0,n1,n2,n3,0] + */ + strLen = (int)XSTRLEN(name); + + for (i = 0, j = 0, k = 0; i <= strLen; i++) { + if (k > MAX_SEGMENTS || j > MAX_SEGMENT_SZ) + break; + + if (name[i] != '-' && name[i] != '\0') { + n[k][j] = name[i]; /* Fill kth segment string until '-' */ + j++; + } + else { + n[k][j] = '\0'; + j = 0; + k++; + } + } + /* keaStr */ + keaStr = GetCipherKeaStr(n); + /* authStr */ + authStr = GetCipherAuthStr(n); + /* encStr */ + encStr = GetCipherEncStr(n); + if ((cipher->bits = SetCipherBits(encStr)) == WOLFSSL_FAILURE) { + WOLFSSL_MSG("Cipher Bits Not Set."); + } + /* macStr */ + macStr = GetCipherMacStr(n); + + + /* Build up the string by copying onto the end. */ + XSTRNCPY(dp, name, len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + + XSTRNCPY(dp, " ", len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + XSTRNCPY(dp, protocol, len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + + XSTRNCPY(dp, " Kx=", len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + XSTRNCPY(dp, keaStr, len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + + XSTRNCPY(dp, " Au=", len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + XSTRNCPY(dp, authStr, len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + + XSTRNCPY(dp, " Enc=", len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + XSTRNCPY(dp, encStr, len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + + XSTRNCPY(dp, " Mac=", len); + dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); + len -= (int)strLen; dp += strLen; + XSTRNCPY(dp, macStr, len); + dp[len-1] = '\0'; + + return WOLFSSL_SUCCESS; +} +#endif + +char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in, + int len) +{ + char *ret = in; + const char *keaStr, *authStr, *encStr, *macStr; + size_t strLen; + WOLFSSL_ENTER("wolfSSL_CIPHER_description"); + + if (cipher == NULL || in == NULL) + return NULL; + +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + /* if cipher is in the stack from wolfSSL_get_ciphers_compat then + * Return the description based on cipher_names[cipher->offset] + */ + if (cipher->in_stack == TRUE) { + wolfSSL_sk_CIPHER_description((WOLFSSL_CIPHER*)cipher); + XSTRNCPY(in,cipher->description,len); + return ret; + } +#endif + + /* Get the cipher description based on the SSL session cipher */ + switch (cipher->ssl->specs.kea) { + case no_kea: + keaStr = "None"; + break; +#ifndef NO_RSA + case rsa_kea: + keaStr = "RSA"; + break; +#endif +#ifndef NO_DH + case diffie_hellman_kea: + keaStr = "DHE"; + break; +#endif + case fortezza_kea: + keaStr = "FZ"; + break; +#ifndef NO_PSK + case psk_kea: + keaStr = "PSK"; + break; + #ifndef NO_DH + case dhe_psk_kea: + keaStr = "DHEPSK"; + break; + #endif + #ifdef HAVE_ECC + case ecdhe_psk_kea: + keaStr = "ECDHEPSK"; + break; + #endif +#endif +#ifdef HAVE_NTRU + case ntru_kea: + keaStr = "NTRU"; + break; +#endif +#ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + keaStr = "ECDHE"; + break; + case ecc_static_diffie_hellman_kea: + keaStr = "ECDH"; + break; +#endif + default: + keaStr = "unknown"; + break; + } + + switch (cipher->ssl->specs.sig_algo) { + case anonymous_sa_algo: + authStr = "None"; + break; +#ifndef NO_RSA + case rsa_sa_algo: + authStr = "RSA"; + break; +#endif +#ifndef NO_DSA + case dsa_sa_algo: + authStr = "DSA"; + break; +#endif +#ifdef HAVE_ECC + case ecc_dsa_sa_algo: + authStr = "ECDSA"; + break; +#endif + default: + authStr = "unknown"; + break; + } + + switch (cipher->ssl->specs.bulk_cipher_algorithm) { + case wolfssl_cipher_null: + encStr = "None"; + break; +#ifndef NO_RC4 + case wolfssl_rc4: + encStr = "RC4(128)"; + break; +#endif +#ifndef NO_DES3 + case wolfssl_triple_des: + encStr = "3DES(168)"; + break; +#endif +#ifdef HAVE_IDEA + case wolfssl_idea: + encStr = "IDEA(128)"; + break; +#endif +#ifndef NO_AES + case wolfssl_aes: + if (cipher->ssl->specs.key_size == 128) + encStr = "AES(128)"; + else if (cipher->ssl->specs.key_size == 256) + encStr = "AES(256)"; + else + encStr = "AES(?)"; + break; + #ifdef HAVE_AESGCM + case wolfssl_aes_gcm: + if (cipher->ssl->specs.key_size == 128) + encStr = "AESGCM(128)"; + else if (cipher->ssl->specs.key_size == 256) + encStr = "AESGCM(256)"; + else + encStr = "AESGCM(?)"; + break; + #endif + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + if (cipher->ssl->specs.key_size == 128) + encStr = "AESCCM(128)"; + else if (cipher->ssl->specs.key_size == 256) + encStr = "AESCCM(256)"; + else + encStr = "AESCCM(?)"; + break; + #endif +#endif +#ifdef HAVE_CHACHA + case wolfssl_chacha: + encStr = "CHACHA20/POLY1305(256)"; + break; +#endif +#ifdef HAVE_CAMELLIA + case wolfssl_camellia: + if (cipher->ssl->specs.key_size == 128) + encStr = "Camellia(128)"; + else if (cipher->ssl->specs.key_size == 256) + encStr = "Camellia(256)"; + else + encStr = "Camellia(?)"; + break; +#endif +#if defined(HAVE_HC128) && !defined(NO_HC128) + case wolfssl_hc128: + encStr = "HC128(128)"; + break; +#endif +#if defined(HAVE_RABBIT) && !defined(NO_RABBIT) + case wolfssl_rabbit: + encStr = "RABBIT(128)"; + break; +#endif + default: + encStr = "unknown"; + break; + } + + switch (cipher->ssl->specs.mac_algorithm) { + case no_mac: + macStr = "None"; + break; +#ifndef NO_MD5 + case md5_mac: + macStr = "MD5"; + break; +#endif +#ifndef NO_SHA + case sha_mac: + macStr = "SHA1"; + break; +#endif +#ifdef HAVE_SHA224 + case sha224_mac: + macStr = "SHA224"; + break; +#endif +#ifndef NO_SHA256 + case sha256_mac: + macStr = "SHA256"; + break; +#endif +#ifdef HAVE_SHA384 + case sha384_mac: + macStr = "SHA384"; + break; +#endif +#ifdef HAVE_SHA512 + case sha512_mac: + macStr = "SHA512"; + break; +#endif + default: + macStr = "unknown"; + break; + } + + /* Build up the string by copying onto the end. */ + XSTRNCPY(in, wolfSSL_CIPHER_get_name(cipher), len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + + XSTRNCPY(in, " ", len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + XSTRNCPY(in, wolfSSL_get_version(cipher->ssl), len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + + XSTRNCPY(in, " Kx=", len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + XSTRNCPY(in, keaStr, len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + + XSTRNCPY(in, " Au=", len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + XSTRNCPY(in, authStr, len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + + XSTRNCPY(in, " Enc=", len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + XSTRNCPY(in, encStr, len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + + XSTRNCPY(in, " Mac=", len); + in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; + XSTRNCPY(in, macStr, len); + in[len-1] = '\0'; + + return ret; +} + + +#ifndef NO_SESSION_CACHE + +WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return NULL; + } + + /* sessions are stored statically, no need for reference count */ + return wolfSSL_get_session(ssl); +} + +#endif /* NO_SESSION_CACHE */ + + + +/* was do nothing */ +/* +void OPENSSL_free(void* buf) +{ + (void)buf; +} +*/ + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_OCSP_parse_url(char* url, char** host, char** port, char** path, + int* ssl) +{ + (void)url; + (void)host; + (void)port; + (void)path; + (void)ssl; + WOLFSSL_STUB("OCSP_parse_url"); + return 0; +} +#endif + +#ifndef NO_MD4 + +void wolfSSL_MD4_Init(WOLFSSL_MD4_CTX* md4) +{ + /* make sure we have a big enough buffer */ + typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1]; + (void) sizeof(ok); + + WOLFSSL_ENTER("MD4_Init"); + wc_InitMd4((Md4*)md4); +} + + +void wolfSSL_MD4_Update(WOLFSSL_MD4_CTX* md4, const void* data, + unsigned long len) +{ + WOLFSSL_ENTER("MD4_Update"); + wc_Md4Update((Md4*)md4, (const byte*)data, (word32)len); +} + + +void wolfSSL_MD4_Final(unsigned char* digest, WOLFSSL_MD4_CTX* md4) +{ + WOLFSSL_ENTER("MD4_Final"); + wc_Md4Final((Md4*)md4, digest); +} + +#endif /* NO_MD4 */ + + +/* Removes a WOLFSSL_BIO struct from the WOLFSSL_BIO linked list. + * + * bio is the WOLFSSL_BIO struct in the list and removed. + * + * The return WOLFSSL_BIO struct is the next WOLFSSL_BIO in the list or NULL if + * there is none. + */ +WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO* bio) +{ + if (bio == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return NULL; + } + + if (bio->prev != NULL) { + bio->prev->next = bio->next; + } + + if (bio->next != NULL) { + bio->next->prev = bio->prev; + } + + return bio->next; +} + + + +WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_mem(void) +{ + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_mem"); + meth.type = WOLFSSL_BIO_MEMORY; + + return &meth; +} + + +WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void) +{ + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_f_base64"); + meth.type = WOLFSSL_BIO_BASE64; + + return &meth; +} + + +/* Set the flag for the bio. + * + * bio the structure to set the flag in + * flags the flag to use + */ +void wolfSSL_BIO_set_flags(WOLFSSL_BIO* bio, int flags) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_flags"); + + if (bio != NULL) { + bio->flags |= flags; + } +} + +void wolfSSL_BIO_clear_flags(WOLFSSL_BIO *bio, int flags) +{ + WOLFSSL_ENTER("wolfSSL_BIO_clear_flags"); + if (bio != NULL) { + bio->flags &= ~flags; + } +} + +/* Set ex_data for WOLFSSL_BIO + * + * bio : BIO structure to set ex_data in + * idx : Index of ex_data to set + * data : Data to set in ex_data + * + * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE on failure + */ +int wolfSSL_BIO_set_ex_data(WOLFSSL_BIO *bio, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_ex_data"); + #ifdef HAVE_EX_DATA + if (bio != NULL && idx < MAX_EX_DATA) { + return wolfSSL_CRYPTO_set_ex_data(&bio->ex_data, idx, data); + } + #else + (void)bio; + (void)idx; + (void)data; + #endif + return WOLFSSL_FAILURE; +} + +/* Get ex_data in WOLFSSL_BIO at given index + * + * bio : BIO structure to get ex_data from + * idx : Index of ex_data to get data from + * + * Returns void pointer to ex_data on success or NULL on failure + */ +void *wolfSSL_BIO_get_ex_data(WOLFSSL_BIO *bio, int idx) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_ex_data"); + #ifdef HAVE_EX_DATA + if (bio != NULL && idx < MAX_EX_DATA && idx >= 0) { + return wolfSSL_CRYPTO_get_ex_data(&bio->ex_data, idx); + } + #else + (void)bio; + (void)idx; + #endif + return NULL; +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_RAND_screen(void) +{ + WOLFSSL_STUB("RAND_screen"); +} +#endif + + + +int wolfSSL_RAND_load_file(const char* fname, long len) +{ + (void)fname; + /* wolfCrypt provides enough entropy internally or will report error */ + if (len == -1) + return 1024; + else + return (int)len; +} + + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void) +{ + WOLFSSL_STUB("COMP_zlib"); + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_COMP_METHOD* wolfSSL_COMP_rle(void) +{ + WOLFSSL_STUB("COMP_rle"); + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_COMP_add_compression_method(int method, void* data) +{ + (void)method; + (void)data; + WOLFSSL_STUB("COMP_add_compression_method"); + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_set_dynlock_create_callback(WOLFSSL_dynlock_value* (*f)( + const char*, int)) +{ + WOLFSSL_STUB("CRYPTO_set_dynlock_create_callback"); + (void)f; +} +#endif + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_set_dynlock_lock_callback( + void (*f)(int, WOLFSSL_dynlock_value*, const char*, int)) +{ + WOLFSSL_STUB("CRYPTO_set_set_dynlock_lock_callback"); + (void)f; +} +#endif + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_set_dynlock_destroy_callback( + void (*f)(WOLFSSL_dynlock_value*, const char*, int)) +{ + WOLFSSL_STUB("CRYPTO_set_set_dynlock_destroy_callback"); + (void)f; +} +#endif + + +const char* wolfSSL_X509_verify_cert_error_string(long err) +{ + return wolfSSL_ERR_reason_error_string(err); +} + + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP* lookup, const char* dir, + long len) +{ + (void)lookup; + (void)dir; + (void)len; + WOLFSSL_STUB("X509_LOOKUP_add_dir"); + return 0; +} +#endif + +int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, + const char* file, long type) +{ +#if !defined(NO_FILESYSTEM) && \ + (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) + int ret = WOLFSSL_FAILURE; + XFILE fp; + long sz; + byte* pem = NULL; + byte* curr = NULL; + byte* prev = NULL; + WOLFSSL_X509* x509; + const char* header = NULL; + const char* footer = NULL; + + if (type != X509_FILETYPE_PEM) + return BAD_FUNC_ARG; + + fp = XFOPEN(file, "r"); + if (fp == XBADFILE) + return BAD_FUNC_ARG; + + if(XFSEEK(fp, 0, XSEEK_END) != 0) { + XFCLOSE(fp); + return WOLFSSL_BAD_FILE; + } + sz = XFTELL(fp); + XREWIND(fp); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { + WOLFSSL_MSG("X509_LOOKUP_load_file size error"); + goto end; + } + + pem = (byte*)XMALLOC(sz, 0, DYNAMIC_TYPE_PEM); + if (pem == NULL) { + ret = MEMORY_ERROR; + goto end; + } + + /* Read in file which may be CRLs or certificates. */ + if (XFREAD(pem, (size_t)sz, 1, fp) != 1) + goto end; + + prev = curr = pem; + do { + /* get PEM header and footer based on type */ + if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && + XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { +#ifdef HAVE_CRL + WOLFSSL_CERT_MANAGER* cm = lookup->store->cm; + + if (cm->crl == NULL) { + if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Enable CRL failed"); + goto end; + } + } + + ret = BufferLoadCRL(cm->crl, curr, sz, WOLFSSL_FILETYPE_PEM, + NO_VERIFY); + if (ret != WOLFSSL_SUCCESS) + goto end; +#endif + curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz); + } + else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && + XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { + x509 = wolfSSL_X509_load_certificate_buffer(curr, (int)sz, + WOLFSSL_FILETYPE_PEM); + if (x509 == NULL) + goto end; + ret = wolfSSL_X509_STORE_add_cert(lookup->store, x509); + wolfSSL_X509_free(x509); + if (ret != WOLFSSL_SUCCESS) + goto end; + curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz); + } + else + goto end; + + if (curr == NULL) + goto end; + + curr++; + sz -= (long)(curr - prev); + prev = curr; + } + while (ret == WOLFSSL_SUCCESS); + +end: + if (pem != NULL) + XFREE(pem, 0, DYNAMIC_TYPE_PEM); + XFCLOSE(fp); + return ret; +#else + (void)lookup; + (void)file; + (void)type; + return WOLFSSL_FAILURE; +#endif +} + +WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_hash_dir(void) +{ + /* Method implementation in functions. */ + static WOLFSSL_X509_LOOKUP_METHOD meth = { 1 }; + return &meth; +} + +WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_file(void) +{ + /* Method implementation in functions. */ + static WOLFSSL_X509_LOOKUP_METHOD meth = { 0 }; + return &meth; +} + + +WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE* store, + WOLFSSL_X509_LOOKUP_METHOD* m) +{ + WOLFSSL_ENTER("SSL_X509_STORE_add_lookup"); + if (store == NULL) + return NULL; + + /* Method is a dummy value and is not needed. */ + (void)m; + /* Make sure the lookup has a back reference to the store. */ + store->lookup.store = store; + return &store->lookup; +} + + +#ifndef NO_CERTS +/* Converts the X509 to DER format and outputs it into bio. + * + * bio is the structure to hold output DER + * x509 certificate to create DER from + * + * returns WOLFSSL_SUCCESS on success + */ +int wolfSSL_i2d_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509* x509) +{ + WOLFSSL_ENTER("wolfSSL_i2d_X509_bio"); + + if (bio == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + if (x509->derCert != NULL) { + word32 len = x509->derCert->length; + byte* der = x509->derCert->buffer; + + if (wolfSSL_BIO_write(bio, der, len) == (int)len) { + return SSL_SUCCESS; + } + } + + return WOLFSSL_FAILURE; +} + + +/* Converts an internal structure to a DER buffer + * + * x509 structure to get DER buffer from + * out buffer to hold result. If NULL then *out is NULL then a new buffer is + * created. + * + * returns the size of the DER result on success + */ +int wolfSSL_i2d_X509(WOLFSSL_X509* x509, unsigned char** out) +{ + const unsigned char* der; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_i2d_X509"); + + if (x509 == NULL) { + WOLFSSL_LEAVE("wolfSSL_i2d_X509", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + der = wolfSSL_X509_get_der(x509, &derSz); + if (der == NULL) { + WOLFSSL_LEAVE("wolfSSL_i2d_X509", MEMORY_E); + return MEMORY_E; + } + + if (out != NULL && *out == NULL) { + *out = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); + if (*out == NULL) { + WOLFSSL_LEAVE("wolfSSL_i2d_X509", MEMORY_E); + return MEMORY_E; + } + } + + if (out != NULL) + XMEMCPY(*out, der, derSz); + + WOLFSSL_LEAVE("wolfSSL_i2d_X509", derSz); + return derSz; +} + + +/* Converts the DER from bio and creates a WOLFSSL_X509 structure from it. + * + * bio is the structure holding DER + * x509 certificate to create from DER. Can be NULL + * + * returns pointer to WOLFSSL_X509 structure on success and NULL on fail + */ +WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509) +{ + WOLFSSL_X509* localX509 = NULL; + unsigned char* mem = NULL; + int ret; + word32 size; + + WOLFSSL_ENTER("wolfSSL_d2i_X509_bio"); + + if (bio == NULL) { + WOLFSSL_MSG("Bad Function Argument bio is NULL"); + return NULL; + } + + ret = wolfSSL_BIO_get_mem_data(bio, &mem); + if (mem == NULL || ret <= 0) { + WOLFSSL_MSG("Failed to get data from bio struct"); + return NULL; + } + size = ret; + + localX509 = wolfSSL_X509_d2i(NULL, mem, size); + if (localX509 == NULL) { + return NULL; + } + + if (x509 != NULL) { + *x509 = localX509; + } + + return localX509; +} + + +#if !defined(NO_ASN) && !defined(NO_PWDBASED) +WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12) +{ + WC_PKCS12* localPkcs12 = NULL; + unsigned char* mem = NULL; + int ret; + word32 size; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio"); + + if (bio == NULL) { + WOLFSSL_MSG("Bad Function Argument bio is NULL"); + return NULL; + } + + localPkcs12 = wc_PKCS12_new(); + if (localPkcs12 == NULL) { + WOLFSSL_MSG("Memory error"); + return NULL; + } + + if (pkcs12 != NULL) { + *pkcs12 = localPkcs12; + } + + ret = wolfSSL_BIO_get_mem_data(bio, &mem); + if (mem == NULL || ret <= 0) { + WOLFSSL_MSG("Failed to get data from bio struct"); + wc_PKCS12_free(localPkcs12); + if (pkcs12 != NULL) { + *pkcs12 = NULL; + } + return NULL; + } + size = ret; + + ret = wc_d2i_PKCS12(mem, size, localPkcs12); + if (ret < 0) { + WOLFSSL_MSG("Failed to get PKCS12 sequence"); + wc_PKCS12_free(localPkcs12); + if (pkcs12 != NULL) { + *pkcs12 = NULL; + } + return NULL; + } + + return localPkcs12; +} + +/* Converts the PKCS12 to DER format and outputs it into bio. + * + * bio is the structure to hold output DER + * pkcs12 structure to create DER from + * + * return 1 for success or 0 if an error occurs + */ +int wolfSSL_i2d_PKCS12_bio(WOLFSSL_BIO *bio, WC_PKCS12 *pkcs12) +{ + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_i2d_PKCS12_bio"); + + if ((bio != NULL) && (pkcs12 != NULL)) { + word32 certSz = 0; + byte *certDer = NULL; + + certSz = wc_i2d_PKCS12(pkcs12, &certDer, NULL); + if ((certSz > 0) && (certDer != NULL)) { + if (wolfSSL_BIO_write(bio, certDer, certSz) == (int)certSz) { + ret = SSL_SUCCESS; + } + } + + if (certDer != NULL) { + XFREE(certDer, NULL, DYNAMIC_TYPE_PKCS); + } + } + + return ret; +} + +/* helper function to get raw pointer to DER buffer from WOLFSSL_EVP_PKEY */ +static int wolfSSL_EVP_PKEY_get_der(WOLFSSL_EVP_PKEY* key, unsigned char** der) +{ + if (!key) + return WOLFSSL_FAILURE; + if (der) + *der = (unsigned char*)key->pkey.ptr; + return key->pkey_sz; +} + +/* Copies unencrypted DER key buffer into "der". If "der" is null then the size + * of buffer needed is returned + * NOTE: This also advances the "der" pointer to be at the end of buffer. + * + * Returns size of key buffer on success + */ +int wolfSSL_i2d_PrivateKey(WOLFSSL_EVP_PKEY* key, unsigned char** der) +{ + if (key == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + if (key->pkey_sz <= 0 || !key->pkey.ptr) { + return WOLFSSL_FATAL_ERROR; + } + + if (der != NULL) { + /* since this function signature has no size value passed in it is + * assumed that the user has allocated a large enough buffer */ + XMEMCPY(*der, key->pkey.ptr, key->pkey_sz); + *der += key->pkey_sz; + } + return key->pkey_sz; +} + +/* Creates a new WC_PKCS12 structure + * + * pass password to use + * name friendlyName to use + * pkey private key to go into PKCS12 bundle + * cert certificate to go into PKCS12 bundle + * ca extra certificates that can be added to bundle. Can be NULL + * keyNID type of encryption to use on the key (-1 means no encryption) + * certNID type of encryption to use on the certificate + * itt number of iterations with encryption + * macItt number of iterations with mac creation + * keyType flag for signature and/or encryption key + * + * returns a pointer to a new WC_PKCS12 structure on success and NULL on fail + */ +WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name, + WOLFSSL_EVP_PKEY* pkey, WOLFSSL_X509* cert, + WOLF_STACK_OF(WOLFSSL_X509)* ca, + int keyNID, int certNID, int itt, int macItt, int keyType) +{ + WC_PKCS12* pkcs12; + WC_DerCertList* list = NULL; + word32 passSz; + byte* keyDer; + word32 keyDerSz; + byte* certDer; + int certDerSz; + + int ret; + + WOLFSSL_ENTER("wolfSSL_PKCS12_create()"); + + if (pass == NULL || pkey == NULL || cert == NULL) { + WOLFSSL_LEAVE("wolfSSL_PKCS12_create()", BAD_FUNC_ARG); + return NULL; + } + passSz = (word32)XSTRLEN(pass); + + if ((ret = wolfSSL_EVP_PKEY_get_der(pkey, &keyDer)) < 0) { + WOLFSSL_LEAVE("wolfSSL_PKCS12_create", ret); + return NULL; + } + keyDerSz = ret; + + certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz); + if (certDer == NULL) { + return NULL; + } + + if (ca != NULL) { + WC_DerCertList* cur; + unsigned long numCerts = ca->num; + byte* curDer; + int curDerSz = 0; + WOLFSSL_STACK* sk = ca; + + while (numCerts > 0 && sk != NULL) { + cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL, + DYNAMIC_TYPE_PKCS); + if (cur == NULL) { + wc_FreeCertList(list, NULL); + return NULL; + } + + curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz); + if (curDer == NULL || curDerSz < 0) { + XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); + wc_FreeCertList(list, NULL); + return NULL; + } + + cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS); + if (cur->buffer == NULL) { + XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); + wc_FreeCertList(list, NULL); + return NULL; + } + XMEMCPY(cur->buffer, curDer, curDerSz); + cur->bufferSz = curDerSz; + cur->next = list; + list = cur; + + sk = sk->next; + numCerts--; + } + } + + pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz, + certDer, certDerSz, list, keyNID, certNID, itt, macItt, + keyType, NULL); + + if (ca != NULL) { + wc_FreeCertList(list, NULL); + } + + return pkcs12; +} + + +/* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure */ +int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, + WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, WOLF_STACK_OF(WOLFSSL_X509)** ca) +{ + DecodedCert DeCert; + void* heap = NULL; + int ret; + byte* certData = NULL; + word32 certDataSz; + byte* pk = NULL; + word32 pkSz; + WC_DerCertList* certList = NULL; + + WOLFSSL_ENTER("wolfSSL_PKCS12_parse"); + + /* make sure we init return args */ + if (pkey) *pkey = NULL; + if (cert) *cert = NULL; + if (ca) *ca = NULL; + + if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) { + WOLFSSL_MSG("Bad argument value"); + return WOLFSSL_FAILURE; + } + + heap = wc_PKCS12_GetHeap(pkcs12); + + if (ca == NULL) { + ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, + NULL); + } + else { + ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, + &certList); + } + if (ret < 0) { + WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret); + return WOLFSSL_FAILURE; + } + + /* Decode cert and place in X509 stack struct */ + if (certList != NULL) { + WC_DerCertList* current = certList; + + *ca = (WOLF_STACK_OF(WOLFSSL_X509)*)XMALLOC(sizeof(WOLF_STACK_OF(WOLFSSL_X509)), + heap, DYNAMIC_TYPE_X509); + if (*ca == NULL) { + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (certData != NULL) { + XFREE(*cert, heap, DYNAMIC_TYPE_PKCS); *cert = NULL; + } + /* Free up WC_DerCertList and move on */ + while (current != NULL) { + WC_DerCertList* next = current->next; + + XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(current, heap, DYNAMIC_TYPE_PKCS); + current = next; + } + return WOLFSSL_FAILURE; + } + XMEMSET(*ca, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509))); + + /* add list of DER certs as X509's to stack */ + while (current != NULL) { + WC_DerCertList* toFree = current; + WOLFSSL_X509* x509; + + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, + DYNAMIC_TYPE_X509); + InitX509(x509, 1, heap); + InitDecodedCert(&DeCert, current->buffer, current->bufferSz, heap); + if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { + WOLFSSL_MSG("Issue with parsing certificate"); + FreeDecodedCert(&DeCert); + wolfSSL_X509_free(x509); + } + else { + if ((ret = CopyDecodedToX509(x509, &DeCert)) != 0) { + WOLFSSL_MSG("Failed to copy decoded cert"); + FreeDecodedCert(&DeCert); + wolfSSL_X509_free(x509); + wolfSSL_sk_X509_free(*ca); *ca = NULL; + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (certData != NULL) { + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + /* Free up WC_DerCertList */ + while (current != NULL) { + WC_DerCertList* next = current->next; + + XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(current, heap, DYNAMIC_TYPE_PKCS); + current = next; + } + return WOLFSSL_FAILURE; + } + FreeDecodedCert(&DeCert); + + if (wolfSSL_sk_X509_push(*ca, x509) != 1) { + WOLFSSL_MSG("Failed to push x509 onto stack"); + wolfSSL_X509_free(x509); + wolfSSL_sk_X509_free(*ca); *ca = NULL; + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (certData != NULL) { + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + + /* Free up WC_DerCertList */ + while (current != NULL) { + WC_DerCertList* next = current->next; + + XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(current, heap, DYNAMIC_TYPE_PKCS); + current = next; + } + return WOLFSSL_FAILURE; + } + } + current = current->next; + XFREE(toFree->buffer, heap, DYNAMIC_TYPE_PKCS); + XFREE(toFree, heap, DYNAMIC_TYPE_PKCS); + } + } + + + /* Decode cert and place in X509 struct */ + if (certData != NULL) { + *cert = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, + DYNAMIC_TYPE_X509); + if (*cert == NULL) { + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + return WOLFSSL_FAILURE; + } + InitX509(*cert, 1, heap); + InitDecodedCert(&DeCert, certData, certDataSz, heap); + if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { + WOLFSSL_MSG("Issue with parsing certificate"); + } + if ((ret = CopyDecodedToX509(*cert, &DeCert)) != 0) { + WOLFSSL_MSG("Failed to copy decoded cert"); + FreeDecodedCert(&DeCert); + if (pk != NULL) { + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + wolfSSL_X509_free(*cert); *cert = NULL; + return WOLFSSL_FAILURE; + } + FreeDecodedCert(&DeCert); + XFREE(certData, heap, DYNAMIC_TYPE_PKCS); + } + + + /* get key type */ + ret = BAD_STATE_E; + if (pk != NULL) { /* decode key if present */ + *pkey = wolfSSL_EVP_PKEY_new_ex(heap); + if (*pkey == NULL) { + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); + return WOLFSSL_FAILURE; + } + #ifndef NO_RSA + { + word32 keyIdx = 0; + RsaKey key; + + if (wc_InitRsaKey(&key, heap) != 0) { + ret = BAD_STATE_E; + } + else { + if ((ret = wc_RsaPrivateKeyDecode(pk, &keyIdx, &key, pkSz)) + == 0) { + (*pkey)->type = EVP_PKEY_RSA; + (*pkey)->rsa = wolfSSL_RSA_new(); + (*pkey)->ownRsa = 1; /* we own RSA */ + if ((*pkey)->rsa == NULL) { + WOLFSSL_MSG("issue creating EVP RSA key"); + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; + XFREE(pk, heap, DYNAMIC_TYPE_PKCS); + return WOLFSSL_FAILURE; + } + if ((ret = wolfSSL_RSA_LoadDer_ex((*pkey)->rsa, pk, pkSz, + WOLFSSL_RSA_LOAD_PRIVATE)) != SSL_SUCCESS) { + WOLFSSL_MSG("issue loading RSA key"); + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; + XFREE(pk, heap, DYNAMIC_TYPE_PKCS); + return WOLFSSL_FAILURE; + } + + WOLFSSL_MSG("Found PKCS12 RSA key"); + ret = 0; /* set in success state for upcoming ECC check */ + } + wc_FreeRsaKey(&key); + } + } + #endif /* NO_RSA */ + + #ifdef HAVE_ECC + { + word32 keyIdx = 0; + ecc_key key; + + if (ret != 0) { /* if is in fail state check if ECC key */ + if (wc_ecc_init(&key) != 0) { + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; + XFREE(pk, heap, DYNAMIC_TYPE_PKCS); + return WOLFSSL_FAILURE; + } + + if ((ret = wc_EccPrivateKeyDecode(pk, &keyIdx, &key, pkSz)) + != 0) { + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; + XFREE(pk, heap, DYNAMIC_TYPE_PKCS); + WOLFSSL_MSG("Bad PKCS12 key format"); + return WOLFSSL_FAILURE; + } + (*pkey)->type = EVP_PKEY_EC; + (*pkey)->pkey_curve = key.dp->oidSum; + wc_ecc_free(&key); + WOLFSSL_MSG("Found PKCS12 ECC key"); + } + } + #else + if (ret != 0) { /* if is in fail state and no ECC then fail */ + wolfSSL_X509_free(*cert); *cert = NULL; + if (ca != NULL) { + wolfSSL_sk_X509_free(*ca); *ca = NULL; + } + wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; + XFREE(pk, heap, DYNAMIC_TYPE_PKCS); + WOLFSSL_MSG("Bad PKCS12 key format"); + return WOLFSSL_FAILURE; + } + #endif /* HAVE_ECC */ + + (*pkey)->save_type = 0; + (*pkey)->pkey_sz = pkSz; + (*pkey)->pkey.ptr = (char*)pk; + } + + (void)ret; + (void)ca; + + return WOLFSSL_SUCCESS; +} +#endif /* !defined(NO_ASN) && !defined(NO_PWDBASED) */ + + +/* no-op function. Was initially used for adding encryption algorithms available + * for PKCS12 */ +void wolfSSL_PKCS12_PBE_add(void) +{ + WOLFSSL_ENTER("wolfSSL_PKCS12_PBE_add"); +} + + + +WOLFSSL_STACK* wolfSSL_X509_STORE_CTX_get_chain(WOLFSSL_X509_STORE_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_chain"); + + if (ctx == NULL) { + return NULL; + } + +#ifdef SESSION_CERTS + /* if chain is null but sesChain is available then populate stack */ + if (ctx->chain == NULL && ctx->sesChain != NULL) { + int i; + WOLFSSL_X509_CHAIN* c = ctx->sesChain; + WOLFSSL_STACK* sk = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), + NULL, DYNAMIC_TYPE_X509); + + if (sk == NULL) { + return NULL; + } + + XMEMSET(sk, 0, sizeof(WOLFSSL_STACK)); + ctx->chain = sk; + + for (i = 0; i < c->count && i < MAX_CHAIN_DEPTH; i++) { + WOLFSSL_X509* x509 = wolfSSL_get_chain_X509(c, i); + + if (x509 == NULL) { + WOLFSSL_MSG("Unable to get x509 from chain"); + wolfSSL_sk_X509_free(sk); + return NULL; + } + + if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) { + WOLFSSL_MSG("Unable to load x509 into stack"); + wolfSSL_sk_X509_free(sk); + wolfSSL_X509_free(x509); + return NULL; + } + } + +#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) + /* add CA used to verify top of chain to the list */ + if (c->count > 0) { + WOLFSSL_X509* x509 = wolfSSL_get_chain_X509(c, c->count - 1); + if (x509 != NULL) { + WOLFSSL_X509* issuer = NULL; + if (wolfSSL_X509_STORE_CTX_get1_issuer(&issuer, ctx, x509) + == WOLFSSL_SUCCESS) { + /* check that the certificate being looked up is not self + * signed and that a issuer was found */ + if (issuer != NULL && wolfSSL_X509_NAME_cmp(&x509->issuer, + &x509->subject) != 0) { + if (wolfSSL_sk_X509_push(sk, issuer) != SSL_SUCCESS) { + WOLFSSL_MSG("Unable to load CA x509 into stack"); + wolfSSL_sk_X509_free(sk); + wolfSSL_X509_free(issuer); + return NULL; + } + } + else { + WOLFSSL_MSG("Certificate is self signed"); + if (issuer != NULL) + wolfSSL_X509_free(issuer); + } + } + else { + WOLFSSL_MSG("Could not find CA for certificate"); + } + } + } +#endif + + } +#endif /* SESSION_CERTS */ + + return ctx->chain; +} + +/* make shallow copy of the stack, data pointers are copied by reference */ +WOLFSSL_STACK* wolfSSL_sk_X509_dup(WOLFSSL_STACK* sk) +{ + unsigned long i; + WOLFSSL_STACK* dup = NULL; + WOLFSSL_STACK* node = NULL; + WOLFSSL_STACK *dIdx = NULL, *sIdx = sk; + + if (sk == NULL) { + return NULL; + } + + for (i = 0; i < sk->num; i++) { + + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_X509); + if (node == NULL) { + if (i != 0) { + wolfSSL_sk_free(dup); + } + WOLFSSL_MSG("Memory error"); + return NULL; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* copy sk node to new node, data by reference */ + node->data.x509 = sIdx->data.x509; + node->num = sIdx->num; + + /* insert node into list, progress idx */ + if (i == 0) { + dup = node; + } else { + dIdx->next = node; + } + + dIdx = node; + sIdx = sIdx->next; + } + + return dup; +} + + +/* like X509_STORE_CTX_get_chain(), but return a copy with data reference + counts increased */ +WOLFSSL_STACK* wolfSSL_X509_STORE_CTX_get1_chain(WOLFSSL_X509_STORE_CTX* ctx) +{ + unsigned long i; + WOLFSSL_STACK* ref; + WOLFSSL_STACK* dup; + + if (ctx == NULL) { + return NULL; + } + + /* get chain in ctx */ + ref = wolfSSL_X509_STORE_CTX_get_chain(ctx); + if (ref == NULL) { + return ref; + } + + /* create duplicate of ctx chain */ + dup = wolfSSL_sk_X509_dup(ref); + if (dup == NULL) { + return NULL; + } + + /* increase ref counts of inner data X509 */ + ref = dup; + for (i = 0; i < dup->num && ref != NULL; i++) { + if (wc_LockMutex(&ref->data.x509->refMutex) != 0) { + WOLFSSL_MSG("Failed to lock x509 mutex"); + } + ref->data.x509->refCount++; + wc_UnLockMutex(&ref->data.x509->refMutex); + ref = ref->next; + } + + return dup; +} + + +int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) +{ + int result = WOLFSSL_FATAL_ERROR; + + WOLFSSL_ENTER("wolfSSL_X509_STORE_add_cert"); + if (store != NULL && store->cm != NULL && x509 != NULL + && x509->derCert != NULL) { + DerBuffer* derCert = NULL; + + result = AllocDer(&derCert, x509->derCert->length, + x509->derCert->type, NULL); + if (result == 0) { + /* AddCA() frees the buffer. */ + XMEMCPY(derCert->buffer, + x509->derCert->buffer, x509->derCert->length); + result = AddCA(store->cm, &derCert, WOLFSSL_USER_CA, VERIFY); + } + } + + WOLFSSL_LEAVE("wolfSSL_X509_STORE_add_cert", result); + + if (result != WOLFSSL_SUCCESS) { + result = WOLFSSL_FATAL_ERROR; + } + + return result; +} + +WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) +{ + WOLFSSL_X509_STORE* store = NULL; + WOLFSSL_ENTER("SSL_X509_STORE_new"); + + if ((store = (WOLFSSL_X509_STORE*)XMALLOC(sizeof(WOLFSSL_X509_STORE), NULL, + DYNAMIC_TYPE_X509_STORE)) == NULL) + goto err_exit; + + XMEMSET(store, 0, sizeof(WOLFSSL_X509_STORE)); + store->isDynamic = 1; + + if ((store->cm = wolfSSL_CertManagerNew()) == NULL) + goto err_exit; + +#ifdef HAVE_CRL + store->crl = NULL; + if ((store->crl = (WOLFSSL_X509_CRL *)XMALLOC(sizeof(WOLFSSL_X509_CRL), + NULL, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) + goto err_exit; + if (InitCRL(store->crl, NULL) < 0) + goto err_exit; +#endif + +#ifdef OPENSSL_EXTRA + if ((store->param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC( + sizeof(WOLFSSL_X509_VERIFY_PARAM), + NULL,DYNAMIC_TYPE_OPENSSL)) == NULL) + goto err_exit; + +#endif + + return store; + +err_exit: + if (store == NULL) + return NULL; + + wolfSSL_X509_STORE_free(store); + + return NULL; +} + + +void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) +{ + if (store != NULL && store->isDynamic) { + if (store->cm != NULL) + wolfSSL_CertManagerFree(store->cm); +#ifdef HAVE_CRL + if (store->crl != NULL) + wolfSSL_X509_CRL_free(store->crl); +#endif +#ifdef OPENSSL_EXTRA + if (store->param != NULL) + XFREE(store->param, NULL, DYNAMIC_TYPE_OPENSSL); +#endif + XFREE(store, NULL, DYNAMIC_TYPE_X509_STORE); + } +} + + +int wolfSSL_X509_STORE_set_flags(WOLFSSL_X509_STORE* store, unsigned long flag) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_X509_STORE_set_flags"); + + if (store == NULL) + return WOLFSSL_FAILURE; + + if ((flag & WOLFSSL_CRL_CHECKALL) || (flag & WOLFSSL_CRL_CHECK)) { + ret = wolfSSL_CertManagerEnableCRL(store->cm, (int)flag); + } + + (void)store; + (void)flag; + + return ret; +} + + +int wolfSSL_X509_STORE_set_default_paths(WOLFSSL_X509_STORE* store) +{ + (void)store; + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_X509_STORE_get_by_subject(WOLFSSL_X509_STORE_CTX* ctx, int idx, + WOLFSSL_X509_NAME* name, WOLFSSL_X509_OBJECT* obj) +{ + (void)ctx; + (void)idx; + (void)name; + (void)obj; + WOLFSSL_STUB("X509_STORE_get_by_subject"); + return 0; +} +#endif + +WOLFSSL_X509_STORE_CTX* wolfSSL_X509_STORE_CTX_new(void) +{ + WOLFSSL_X509_STORE_CTX* ctx; + WOLFSSL_ENTER("X509_STORE_CTX_new"); + + ctx = (WOLFSSL_X509_STORE_CTX*)XMALLOC(sizeof(WOLFSSL_X509_STORE_CTX), NULL, + DYNAMIC_TYPE_X509_CTX); + if (ctx != NULL) { + ctx->param = NULL; + wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL); + } + + return ctx; +} + + +int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx, + WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509, WOLF_STACK_OF(WOLFSSL_X509)* sk) +{ + WOLFSSL_X509* x509_cert; + int ret = 0; + (void)sk; + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_init"); + + if (ctx != NULL) { + ctx->store = store; + #ifndef WOLFSSL_X509_STORE_CERTS + ctx->current_cert = x509; + #else + if(x509 != NULL){ + ctx->current_cert = wolfSSL_X509_d2i(NULL, x509->derCert->buffer,x509->derCert->length); + if(ctx->current_cert == NULL) + return WOLFSSL_FATAL_ERROR; + } else + ctx->current_cert = NULL; + #endif + + ctx->chain = sk; + /* Add intermediate certificates from stack to store */ + while (sk != NULL) { + x509_cert = sk->data.x509; + if (x509_cert != NULL && x509_cert->isCa) { + ret = wolfSSL_X509_STORE_add_cert(store, x509_cert); + if (ret < 0) { + return WOLFSSL_FATAL_ERROR; + } + } + sk = sk->next; + } + + ctx->sesChain = NULL; + ctx->domain = NULL; +#if defined(HAVE_EX_DATA) || defined(FORTRESS) + XMEMSET(&ctx->ex_data, 0, sizeof(ctx->ex_data)); +#endif + ctx->userCtx = NULL; + ctx->error = 0; + ctx->error_depth = 0; + ctx->discardSessionCerts = 0; +#ifdef OPENSSL_EXTRA + if (ctx->param == NULL) { + ctx->param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC( + sizeof(WOLFSSL_X509_VERIFY_PARAM), + NULL,DYNAMIC_TYPE_OPENSSL); + if (ctx->param == NULL){ + WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_init failed"); + return SSL_FATAL_ERROR; + } + } +#endif + return SSL_SUCCESS; + } + return WOLFSSL_FATAL_ERROR; +} + + +void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx) +{ + WOLFSSL_ENTER("X509_STORE_CTX_free"); + if (ctx != NULL) { + #if !defined(OPENSSL_ALL) && !defined(WOLFSSL_QT) + if (ctx->store != NULL) + wolfSSL_X509_STORE_free(ctx->store); + #ifndef WOLFSSL_KEEP_STORE_CERTS + if (ctx->current_cert != NULL) + wolfSSL_FreeX509(ctx->current_cert); + #endif + #endif /* !OPENSSL_ALL && !WOLFSSL_QT */ +#ifdef OPENSSL_EXTRA + if (ctx->param != NULL){ + XFREE(ctx->param,NULL,DYNAMIC_TYPE_OPENSSL); + } +#endif + XFREE(ctx, NULL, DYNAMIC_TYPE_X509_CTX); + } +} + + +void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX* ctx) +{ + (void)ctx; + /* Do nothing */ +} + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) +/* Returns corresponding X509 error from internal ASN error */ +static int GetX509Error(int e) +{ + switch (e) { + case ASN_BEFORE_DATE_E: + return X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; + case ASN_AFTER_DATE_E: + return X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; + case ASN_NO_SIGNER_E: + return X509_V_ERR_INVALID_CA; + case ASN_SELF_SIGNED_E: + return X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; + case ASN_PATHLEN_INV_E: + case ASN_PATHLEN_SIZE_E: + return X509_V_ERR_PATH_LENGTH_EXCEEDED; + case ASN_SIG_OID_E: + case ASN_SIG_CONFIRM_E: + case ASN_SIG_HASH_E: + case ASN_SIG_KEY_E: + return X509_V_ERR_CERT_SIGNATURE_FAILURE; + default: + WOLFSSL_MSG("Error not configured or implemented yet"); + return e; + } +} +#endif + +/* Verifies certificate chain using WOLFSSL_X509_STORE_CTX + * returns 0 on success or < 0 on failure. + */ +int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) +{ + int ret = 0; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + int depth = 0; + int error; + byte *afterDate, *beforeDate; +#endif + WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); + + if (ctx != NULL && ctx->store != NULL && ctx->store->cm != NULL + && ctx->current_cert != NULL && ctx->current_cert->derCert != NULL) { + ret = wolfSSL_CertManagerVerifyBuffer(ctx->store->cm, + ctx->current_cert->derCert->buffer, + ctx->current_cert->derCert->length, + WOLFSSL_FILETYPE_ASN1); + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + /* If there was an error, process it and add it to CTX */ + if (ret < 0) { + /* Get corresponding X509 error */ + error = GetX509Error(ret); + /* Set error depth */ + if (ctx->chain) + depth = (int)ctx->chain->num; + + wolfSSL_X509_STORE_CTX_set_error(ctx, error); + wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth); + ctx->store->verify_cb(0, ctx); + } + + error = 0; + /* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or + ASN_BEFORE_DATE_E if there are no additional errors found in the + cert. Therefore, check if the cert is expired or not yet valid + in order to return the correct expected error. */ + afterDate = ctx->current_cert->notAfter.data; + beforeDate = ctx->current_cert->notBefore.data; + + if (ValidateDate(afterDate, ctx->current_cert->notAfter.type, + AFTER) < 1) { + error = X509_V_ERR_CERT_HAS_EXPIRED; + } + else if (ValidateDate(beforeDate, ctx->current_cert->notBefore.type, + BEFORE) < 1) { + error = X509_V_ERR_CERT_NOT_YET_VALID; + } + + if (error != 0 ) { + wolfSSL_X509_STORE_CTX_set_error(ctx, error); + wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth); + if (ctx->store && ctx->store->verify_cb) + ctx->store->verify_cb(0, ctx); + } +#endif /* OPENSSL_ALL || WOLFSSL_QT */ + return ret; + } + return WOLFSSL_FATAL_ERROR; +} + + +/* Use the public key to verify the signature. Note: this only verifies + * the certificate signature. + * returns WOLFSSL_SUCCESS on successful signature verification */ +int wolfSSL_X509_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) +{ + int ret; + const byte* der; + int derSz = 0; + int type; + + if (x509 == NULL || pkey == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + der = wolfSSL_X509_get_der(x509, &derSz); + if (der == NULL) { + WOLFSSL_MSG("Error getting WOLFSSL_X509 DER"); + return WOLFSSL_FATAL_ERROR; + } + + switch (pkey->type) { + case EVP_PKEY_RSA: + type = RSAk; + break; + + case EVP_PKEY_EC: + type = ECDSAk; + break; + + case EVP_PKEY_DSA: + type = DSAk; + break; + + default: + WOLFSSL_MSG("Unknown pkey key type"); + return WOLFSSL_FATAL_ERROR; + } + + ret = CheckCertSignaturePubKey(der, derSz, x509->heap, + (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); + if (ret == 0) { + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} +#endif /* NO_CERTS */ + +#if !defined(NO_FILESYSTEM) +static void *wolfSSL_d2i_X509_fp_ex(XFILE file, void **x509, int type) +{ + void *newx509 = NULL; + byte *fileBuffer = NULL; + long sz = 0; + + /* init variable */ + if (x509) + *x509 = NULL; + + /* argument check */ + if (file == XBADFILE) { + return NULL; + } + + /* determine file size */ + if (XFSEEK(file, 0, XSEEK_END) != 0) { + return NULL; + } + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { + WOLFSSL_MSG("d2i_X509_fp_ex file size error"); + return NULL; + } + + fileBuffer = (byte *)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE); + if (fileBuffer != NULL) { + if ((long)XFREAD(fileBuffer, 1, sz, file) != sz) { + WOLFSSL_MSG("File read failed"); + goto err_exit; + } + if (type == CERT_TYPE) { + newx509 = (void *)wolfSSL_X509_d2i(NULL, fileBuffer, (int)sz); + } + #ifdef HAVE_CRL + else if (type == CRL_TYPE) { + newx509 = (void *)wolfSSL_d2i_X509_CRL(NULL, fileBuffer, (int)sz); + } + #endif + #if !defined(NO_ASN) && !defined(NO_PWDBASED) + else if (type == PKCS12_TYPE) { + if ((newx509 = wc_PKCS12_new()) == NULL) { + goto err_exit; + } + if (wc_d2i_PKCS12(fileBuffer, (int)sz, (WC_PKCS12*)newx509) < 0) { + goto err_exit; + } + } + #endif + else { + goto err_exit; + } + if (newx509 == NULL) { + WOLFSSL_MSG("X509 failed"); + goto err_exit; + } + } + + if (x509) + *x509 = newx509; + + goto _exit; + +err_exit: +#if !defined(NO_ASN) && !defined(NO_PWDBASED) + if ((newx509 != NULL) && (type == PKCS12_TYPE)) { + wc_PKCS12_free((WC_PKCS12*)newx509); + newx509 = NULL; + } +#endif +_exit: + if (fileBuffer != NULL) + XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE); + + return newx509; +} + +WOLFSSL_X509_PKCS12 *wolfSSL_d2i_PKCS12_fp(XFILE fp, WOLFSSL_X509_PKCS12 **pkcs12) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_fp"); + return (WOLFSSL_X509_PKCS12 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)pkcs12, PKCS12_TYPE); +} + +WOLFSSL_X509 *wolfSSL_d2i_X509_fp(XFILE fp, WOLFSSL_X509 **x509) +{ + WOLFSSL_ENTER("wolfSSL_d2i_X509_fp"); + return (WOLFSSL_X509 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)x509, CERT_TYPE); +} +#endif /* !NO_FILESYSTEM */ + + +#ifdef HAVE_CRL +#ifndef NO_FILESYSTEM +WOLFSSL_X509_CRL *wolfSSL_d2i_X509_CRL_fp(XFILE fp, WOLFSSL_X509_CRL **crl) +{ + WOLFSSL_ENTER("wolfSSL_d2i_X509_CRL_fp"); + return (WOLFSSL_X509_CRL *)wolfSSL_d2i_X509_fp_ex(fp, (void **)crl, CRL_TYPE); +} +#endif /* !NO_FILESYSTEM */ + + +WOLFSSL_X509_CRL* wolfSSL_d2i_X509_CRL(WOLFSSL_X509_CRL** crl, + const unsigned char* in, int len) +{ + WOLFSSL_X509_CRL *newcrl = NULL; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_d2i_X509_CRL"); + + if (in == NULL) { + WOLFSSL_MSG("Bad argument value"); + } else { + newcrl = (WOLFSSL_X509_CRL*)XMALLOC(sizeof(WOLFSSL_X509_CRL), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (newcrl == NULL){ + WOLFSSL_MSG("New CRL allocation failed"); + } else { + ret = InitCRL(newcrl, NULL); + if (ret < 0) { + WOLFSSL_MSG("Init tmp CRL failed"); + } else { + ret = BufferLoadCRL(newcrl, in, len, WOLFSSL_FILETYPE_ASN1, + NO_VERIFY); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Buffer Load CRL failed"); + } else { + if (crl) { + *crl = newcrl; + } + } + } + } + } + + if((ret != WOLFSSL_SUCCESS) && (newcrl != NULL)) { + wolfSSL_X509_CRL_free(newcrl); + newcrl = NULL; + } + + return newcrl; +} + +void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl) +{ + WOLFSSL_ENTER("wolfSSL_X509_CRL_free"); + + FreeCRL(crl, 1); + return; +} +#endif /* HAVE_CRL */ + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL* crl) +{ + (void)crl; + WOLFSSL_STUB("X509_CRL_get_lastUpdate"); + return 0; +} +#endif +#ifndef NO_WOLFSSL_STUB +WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl) +{ + (void)crl; + WOLFSSL_STUB("X509_CRL_get_nextUpdate"); + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* key) +{ + (void)crl; + (void)key; + WOLFSSL_STUB("X509_CRL_verify"); + return 0; +} +#endif +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_EXTRA + +/* Gets pointer to X509_STORE that was used to create context. + * + * Return valid pointer on success, NULL if ctx was NULL or not initialized + */ +WOLFSSL_X509_STORE* wolfSSL_X509_STORE_CTX_get0_store( + WOLFSSL_X509_STORE_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get0_store"); + + if (ctx == NULL) + return NULL; + + return ctx->store; +} + +WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get0_cert(WOLFSSL_X509_STORE_CTX* ctx) +{ + if (ctx == NULL) + return NULL; + + return ctx->current_cert; +} + +void wolfSSL_X509_STORE_CTX_set_time(WOLFSSL_X509_STORE_CTX* ctx, + unsigned long flags, + time_t t) +{ + (void)flags; + + if (ctx == NULL || ctx->param == NULL) + return; + + ctx->param->check_time = t; + ctx->param->flags |= WOLFSSL_USE_CHECK_TIME; +} + +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +#ifndef NO_WOLFSSL_STUB +int wolfSSL_X509_STORE_CTX_set_purpose(WOLFSSL_X509_STORE_CTX *ctx, + int purpose) +{ + (void)ctx; + (void)purpose; + WOLFSSL_STUB("wolfSSL_X509_STORE_CTX_set_purpose"); + return 0; +} +#endif +#endif /* WOLFSSL_QT || OPENSSL_ALL */ + +#ifndef NO_WOLFSSL_STUB +/* Returns default file name and path of config file. However + a wolfssl.cnf file is not currently supported */ +char* wolfSSL_CONF_get1_default_config_file(void) +{ + WOLFSSL_ENTER("wolfSSL_CONF_get1_default_config_file"); + WOLFSSL_STUB("CONF_get1_default_config_file"); + return NULL; +} +#endif +/****************************************************************************** +* wolfSSL_X509_VERIFY_PARAM_set1_host - sets the DNS hostname to name +* hostnames is cleared if name is NULL or empty. +* +* RETURNS: +* +*/ +int wolfSSL_X509_VERIFY_PARAM_set1_host(WOLFSSL_X509_VERIFY_PARAM* pParam, + const char* name, + unsigned int nameSz) +{ + unsigned int sz = 0; + + if (pParam == NULL) + return WOLFSSL_FAILURE; + + XMEMSET(pParam->hostName, 0, WOLFSSL_HOST_NAME_MAX); + + if (name == NULL) + return WOLFSSL_SUCCESS; + + sz = (unsigned int)XSTRLEN(name); + + /* If name is NUL-terminated, namelen can be set to zero. */ + if(nameSz == 0 || nameSz > sz) + nameSz = sz; + + if (nameSz > 0 && name[nameSz - 1] == '\0') + nameSz--; + + if (nameSz > WOLFSSL_HOST_NAME_MAX-1) + nameSz = WOLFSSL_HOST_NAME_MAX-1; + + if (nameSz > 0) + XMEMCPY(pParam->hostName, name, nameSz); + + pParam->hostName[nameSz] = '\0'; + + return WOLFSSL_SUCCESS; +} +/****************************************************************************** +* wolfSSL_get0_param - return a pointer to the SSL verification parameters +* +* RETURNS: +* returns pointer to the SSL verification parameters on success, +* otherwise returns NULL +*/ +WOLFSSL_X509_VERIFY_PARAM* wolfSSL_get0_param(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return NULL; + } + return ssl->param; +} + +/* Set the host flag in the X509_VERIFY_PARAM structure */ +void wolfSSL_X509_VERIFY_PARAM_set_hostflags(WOLFSSL_X509_VERIFY_PARAM* param, + unsigned int flags) +{ + if (param != NULL) { + param->hostFlags = flags; + } +} + +/* Sets the expected IP address to ipasc. + * + * param is a pointer to the X509_VERIFY_PARAM structure + * ipasc is a NULL-terminated string with N.N.N.N for IPv4 and + * HH:HH ... HH:HH for IPv6. There is no validation performed on the + * parameter, and it must be an exact match with the IP in the cert. + * + * return 1 for success and 0 for failure*/ +int wolfSSL_X509_VERIFY_PARAM_set1_ip_asc(WOLFSSL_X509_VERIFY_PARAM *param, + const char *ipasc) +{ + int ret = WOLFSSL_FAILURE; + + if (param != NULL) { + if (ipasc == NULL) { + param->ipasc[0] = '\0'; + } + else { + XSTRNCPY(param->ipasc, ipasc, WOLFSSL_MAX_IPSTR-1); + param->ipasc[WOLFSSL_MAX_IPSTR-1] = '\0'; + } + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_X509_OBJECT_free_contents(WOLFSSL_X509_OBJECT* obj) +{ + (void)obj; + WOLFSSL_STUB("X509_OBJECT_free_contents"); +} +#endif + +#ifndef NO_ASN_TIME +int wolfSSL_X509_cmp_current_time(const WOLFSSL_ASN1_TIME* asnTime) +{ + return wolfSSL_X509_cmp_time(asnTime, NULL); +} + +/* return -1 if asnTime is earlier than or equal to cmpTime, and 1 otherwise + * return 0 on error + */ +int wolfSSL_X509_cmp_time(const WOLFSSL_ASN1_TIME* asnTime, time_t* cmpTime) +{ + int ret = WOLFSSL_FAILURE, i = 0; + time_t tmpTime, *pTime = &tmpTime; + byte data_ptr[MAX_TIME_STRING_SZ], inv = 0; + struct tm ts, *tmpTs, *ct; +#if defined(NEED_TMP_TIME) + /* for use with gmtime_r */ + struct tm tmpTimeStorage; + + tmpTs = &tmpTimeStorage; +#else + tmpTs = NULL; +#endif + (void)tmpTs; + + if (asnTime == NULL) { + return WOLFSSL_FAILURE; + } + + if (cmpTime == NULL) { + /* Use current time */ + *pTime = XTIME(0); + } + else { + pTime = cmpTime; + } + + /* Convert ASN1_time to time_t */ + XMEMSET(&ts, 0, sizeof(struct tm)); + + /* Check type */ + if (asnTime->type == ASN_UTC_TIME) { + /* 2-digit year */ + XMEMCPY(data_ptr, &asnTime->data[i], ASN_UTC_TIME_SIZE); + ts.tm_year = (data_ptr[i] - '0') * 10; i++; + ts.tm_year += data_ptr[i] - '0'; i++; + if (ts.tm_year < 70) { + ts.tm_year += 100; + } + } + else if (asnTime->type == ASN_GENERALIZED_TIME) { + /* 4-digit year */ + XMEMCPY(data_ptr, &asnTime->data[i], ASN_GENERALIZED_TIME_SIZE); + ts.tm_year = (data_ptr[i] - '0') * 1000; i++; + ts.tm_year += (data_ptr[i] - '0') * 100; i++; + ts.tm_year += (data_ptr[i] - '0') * 10; i++; + ts.tm_year += data_ptr[i] - '0'; i++; + ts.tm_year -= 1900; + } + else { + /* Invalid type */ + inv = 1; + } + + if (inv != 1) { + ts.tm_mon = (data_ptr[i] - '0') * 10; i++; + ts.tm_mon += (data_ptr[i] - '0') - 1; i++; /* January is 0 not 1 */ + ts.tm_mday = (data_ptr[i] - '0') * 10; i++; + ts.tm_mday += (data_ptr[i] - '0'); i++; + ts.tm_hour = (data_ptr[i] - '0') * 10; i++; + ts.tm_hour += (data_ptr[i] - '0'); i++; + ts.tm_min = (data_ptr[i] - '0') * 10; i++; + ts.tm_min += (data_ptr[i] - '0'); i++; + ts.tm_sec = (data_ptr[i] - '0') * 10; i++; + ts.tm_sec += (data_ptr[i] - '0'); + + /* Convert to time struct*/ + ct = XGMTIME(pTime, tmpTs); + + if (ct == NULL) + return GETTIME_ERROR; + + /* DateGreaterThan returns 1 for >; 0 for <= */ + ret = DateGreaterThan(&ts, ct) ? 1 : -1; + } + + return ret; +} +#endif /* !NO_ASN_TIME */ + +#if defined(OPENSSL_EXTRA) && !defined(NO_ASN_TIME) && !defined(USER_TIME) && \ + !defined(TIME_OVERRIDES) +WOLFSSL_ASN1_TIME *wolfSSL_X509_time_adj_ex(WOLFSSL_ASN1_TIME *asnTime, + int offset_day, long offset_sec, time_t *in_tm) +{ + /* get current time if in_tm is null */ + time_t t = in_tm ? *in_tm : XTIME(0); + return wolfSSL_ASN1_TIME_adj(asnTime, t, offset_day, offset_sec); +} + +WOLFSSL_ASN1_TIME *wolfSSL_X509_time_adj(WOLFSSL_ASN1_TIME *asnTime, + long offset_sec, time_t *in_tm) +{ + return wolfSSL_X509_time_adj_ex(asnTime, 0, offset_sec, in_tm); +} +#endif + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_X509_REVOKED* revoked) +{ + (void)revoked; + WOLFSSL_STUB("sk_X509_REVOKED_num"); + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_X509_REVOKED* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl) +{ + (void)crl; + WOLFSSL_STUB("X509_CRL_get_REVOKED"); + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_X509_REVOKED* wolfSSL_sk_X509_REVOKED_value( + WOLFSSL_X509_REVOKED* revoked, int value) +{ + (void)revoked; + (void)value; + WOLFSSL_STUB("sk_X509_REVOKED_value"); + return 0; +} +#endif + +/* Used to create a new WOLFSSL_ASN1_INTEGER structure. + * returns a pointer to new structure on success and NULL on failure + */ +WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_new(void) +{ + WOLFSSL_ASN1_INTEGER* a; + + a = (WOLFSSL_ASN1_INTEGER*)XMALLOC(sizeof(WOLFSSL_ASN1_INTEGER), NULL, + DYNAMIC_TYPE_OPENSSL); + if (a == NULL) { + return NULL; + } + + XMEMSET(a, 0, sizeof(WOLFSSL_ASN1_INTEGER)); + a->data = a->intData; + a->dataMax = WOLFSSL_ASN1_INTEGER_MAX; + a->length = 0; + return a; +} + + +/* free's internal elements of WOLFSSL_ASN1_INTEGER and free's "in" itself */ +void wolfSSL_ASN1_INTEGER_free(WOLFSSL_ASN1_INTEGER* in) +{ + if (in != NULL) { + if (in->isDynamic) { + XFREE(in->data, NULL, DYNAMIC_TYPE_OPENSSL); + } + XFREE(in, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + + +/* Duplicate all WOLFSSL_ASN1_INTEGER members from src to dup + * src : WOLFSSL_ASN1_INTEGER to duplicate + * Returns pointer to duplicate WOLFSSL_ASN1_INTEGER + */ +WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_dup(const WOLFSSL_ASN1_INTEGER* src) +{ + WOLFSSL_ASN1_INTEGER* dup; + WOLFSSL_ENTER("wolfSSL_ASN1_INTEGER_dup"); + if (!src) + return NULL; + + dup = wolfSSL_ASN1_INTEGER_new(); + + if (dup == NULL) + return NULL; + + dup->negative = src->negative; + dup->dataMax = src->dataMax; + dup->isDynamic = src->isDynamic; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + dup->length = src->length; +#endif + XSTRNCPY((char*)dup->intData,(const char*)src->intData,WOLFSSL_ASN1_INTEGER_MAX); + + if (dup->isDynamic && src->data && dup->dataMax) { + dup->data = (unsigned char*) + XMALLOC(src->dataMax,NULL,DYNAMIC_TYPE_OPENSSL); + if (dup->data == NULL) { + wolfSSL_ASN1_INTEGER_free(dup); + return NULL; + } + XMEMCPY(dup->data,src->data,dup->dataMax); + } + return dup; +} + + +/* sets the value of WOLFSSL_ASN1_INTEGER a to the long value v. */ +int wolfSSL_ASN1_INTEGER_set(WOLFSSL_ASN1_INTEGER *a, long v) +{ + int ret = WOLFSSL_SUCCESS; /* return 1 for success and 0 for failure */ + int j; + unsigned int i = 0; + unsigned char tmp[sizeof(long)+1] = {0}; + + if (a != NULL) { + /* dynamically create data buffer, +2 for type and length */ + a->data = (unsigned char*)XMALLOC((sizeof(long)+1) + 2, NULL, + DYNAMIC_TYPE_OPENSSL); + if (a->data == NULL) { + wolfSSL_ASN1_INTEGER_free(a); + ret = WOLFSSL_FAILURE; + } + else { + a->dataMax = (int)(sizeof(long)+1) + 2; + a->isDynamic = 1; + } + } + else { + /* Invalid parameter */ + ret = WOLFSSL_FAILURE; + } + + + if (ret != WOLFSSL_FAILURE) { + /* Set type */ + a->data[i++] = ASN_INTEGER; + + /* Check for negative */ + if (v < 0) { + a->negative = 1; + v *= -1; + } + + /* Create char buffer */ + for (j = 0; j < (int)sizeof(long); j++) { + if (v == 0) { + break; + } + tmp[j] = (unsigned char)(v & 0xff); + v >>= 8; + } + + /* Set length */ + a->data[i++] = (unsigned char)((j == 0) ? ++j : j); + /* +2 for type and length */ + a->length = j + 2; + + /* Copy to data */ + for (; j > 0; j--) { + a->data[i++] = tmp[j-1]; + } + } + + return ret; +} + + +WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509* x509) +{ + WOLFSSL_ASN1_INTEGER* a; + int i = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_serialNumber"); + + a = wolfSSL_ASN1_INTEGER_new(); + if (a == NULL) + return NULL; + + /* Make sure there is space for the data, ASN.1 type and length. */ + if (x509->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) { + /* dynamically create data buffer, +2 for type and length */ + a->data = (unsigned char*)XMALLOC(x509->serialSz + 2, NULL, + DYNAMIC_TYPE_OPENSSL); + if (a->data == NULL) { + wolfSSL_ASN1_INTEGER_free(a); + return NULL; + } + a->dataMax = x509->serialSz + 2; + a->isDynamic = 1; + } else { + /* Use array instead of dynamic memory */ + a->data = a->intData; + a->dataMax = WOLFSSL_ASN1_INTEGER_MAX; + } + + #ifdef WOLFSSL_QT + XMEMCPY(&a->data[i], x509->serial, x509->serialSz); + a->length = x509->serialSz; + #else + a->data[i++] = ASN_INTEGER; + i += SetLength(x509->serialSz, a->data + i); + XMEMCPY(&a->data[i], x509->serial, x509->serialSz); + a->length = x509->serialSz + 2; + #endif + + x509->serialNumber = a; + + return a; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) +#ifndef NO_ASN_TIME +int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime) +{ + char buf[MAX_TIME_STRING_SZ]; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_print"); + + if (bio == NULL || asnTime == NULL) { + WOLFSSL_MSG("NULL function argument"); + return WOLFSSL_FAILURE; + } + + if (wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)asnTime, buf, + sizeof(buf)) == NULL) { + XMEMSET(buf, 0, MAX_TIME_STRING_SZ); + XMEMCPY(buf, "Bad time value", 14); + ret = WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, buf, (int)XSTRLEN(buf)) <= 0) { + WOLFSSL_MSG("Unable to write to bio"); + return WOLFSSL_FAILURE; + } + + return ret; +} + +char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len) +{ + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_to_string"); + + if (t == NULL || buf == NULL || len < 5) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + if (t->length > len) { + WOLFSSL_MSG("Length of date is longer then buffer"); + return NULL; + } + + if (!GetTimeString(t->data, t->type, buf, len)) { + return NULL; + } + + return buf; +} +#endif /* !NO_ASN_TIME */ +#endif /* WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA*/ + + +#ifdef OPENSSL_EXTRA + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER* a, + const WOLFSSL_ASN1_INTEGER* b) +{ + (void)a; + (void)b; + WOLFSSL_STUB("ASN1_INTEGER_cmp"); + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER* i) +{ + (void)i; + WOLFSSL_STUB("ASN1_INTEGER_get"); + return 0; +} +#endif + +/* get X509_STORE_CTX ex_data, max idx is MAX_EX_DATA */ +void* wolfSSL_X509_STORE_CTX_get_ex_data(WOLFSSL_X509_STORE_CTX* ctx, int idx) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_ex_data"); + #if defined(HAVE_EX_DATA) || defined(FORTRESS) + if (ctx != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx); + } + #else + (void)ctx; + (void)idx; + #endif + return NULL; +} + + +/* set X509_STORE_CTX ex_data, max idx is MAX_EX_DATA. Return WOLFSSL_SUCCESS + * on success, WOLFSSL_FAILURE on error. */ +int wolfSSL_X509_STORE_CTX_set_ex_data(WOLFSSL_X509_STORE_CTX* ctx, int idx, + void *data) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_ex_data"); + #if defined(HAVE_EX_DATA) || defined(FORTRESS) + if (ctx != NULL) + { + return wolfSSL_CRYPTO_set_ex_data(&ctx->ex_data, idx, data); + } + #else + (void)ctx; + (void)idx; + (void)data; + #endif + return WOLFSSL_FAILURE; +} + +#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) +void wolfSSL_X509_STORE_CTX_set_depth(WOLFSSL_X509_STORE_CTX* ctx, int depth) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_depth"); + if (ctx) + ctx->depth = depth; +} +#endif + + +WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get0_current_issuer( + WOLFSSL_X509_STORE_CTX* ctx) +{ + int ret; + WOLFSSL_X509* issuer; + + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get0_current_issuer"); + + if (ctx == NULL) { + return NULL; + } + + ret = wolfSSL_X509_STORE_CTX_get1_issuer(&issuer, ctx, ctx->current_cert); + if (ret == WOLFSSL_SUCCESS) { + return issuer; + } + + return NULL; +} + + +/* Gets an index to store SSL structure at. + * + * Returns positive index on success and negative values on failure + */ +int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void) +{ + WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx"); + + /* store SSL at index 0 */ + return 0; +} + + +/* Set an error stat in the X509 STORE CTX + * + */ +void wolfSSL_X509_STORE_CTX_set_error(WOLFSSL_X509_STORE_CTX* ctx, int er) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_error"); + + if (ctx != NULL) { + ctx->error = er; + } +} + +/* Set the error depth in the X509 STORE CTX */ +void wolfSSL_X509_STORE_CTX_set_error_depth(WOLFSSL_X509_STORE_CTX* ctx, + int depth) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_error_depth"); + + if (ctx != NULL) { + ctx->error_depth = depth; + } +} + +/* Sets a function callback that will send information about the state of all + * WOLFSSL objects that have been created by the WOLFSSL_CTX structure passed + * in. + * + * ctx WOLFSSL_CTX structure to set callback function in + * f callback function to use + */ +void wolfSSL_CTX_set_info_callback(WOLFSSL_CTX* ctx, + void (*f)(const WOLFSSL* ssl, int type, int val)) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_info_callback"); + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); + } + else { + ctx->CBIS = f; + } +} + + +unsigned long wolfSSL_ERR_peek_error(void) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_error"); + + return wolfSSL_ERR_peek_error_line_data(NULL, NULL, NULL, NULL); +} + +int wolfSSL_ERR_GET_LIB(unsigned long err) +{ + switch (err) { + case PEM_R_NO_START_LINE: + case PEM_R_PROBLEMS_GETTING_PASSWORD: + case PEM_R_BAD_PASSWORD_READ: + case PEM_R_BAD_DECRYPT: + return ERR_LIB_PEM; + case EVP_R_BAD_DECRYPT: + case EVP_R_BN_DECODE_ERROR: + case EVP_R_DECODE_ERROR: + case EVP_R_PRIVATE_KEY_DECODE_ERROR: + return ERR_LIB_EVP; + default: + return 0; + } +} + +/* This function is to find global error values that are the same through out + * all library version. With wolfSSL having only one set of error codes the + * return value is pretty straight forward. The only thing needed is all wolfSSL + * error values are typically negative. + * + * Returns the error reason + */ +int wolfSSL_ERR_GET_REASON(unsigned long err) +{ + int ret = (int)err; + + WOLFSSL_ENTER("wolfSSL_ERR_GET_REASON"); + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + /* Nginx looks for this error to know to stop parsing certificates. */ + if (err == ((ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE)) + return PEM_R_NO_START_LINE; +#endif + + /* check if error value is in range of wolfSSL errors */ + ret = 0 - ret; /* setting as negative value */ + /* wolfCrypt range is less than MAX (-100) + wolfSSL range is MIN (-300) and lower */ + if (ret < MAX_CODE_E && ret > MIN_CODE_E) { + return ret; + } + else { + WOLFSSL_MSG("Not in range of typical error values"); + ret = (int)err; + } + + return ret; +} + + +/* returns a string that describes the alert + * + * alertID the alert value to look up + */ +const char* wolfSSL_alert_type_string_long(int alertID) +{ + WOLFSSL_ENTER("wolfSSL_alert_type_string_long"); + + switch (alertID) { + case close_notify: + { + static const char close_notify_str[] = + "close_notify"; + return close_notify_str; + } + + case unexpected_message: + { + static const char unexpected_message_str[] = + "unexpected_message"; + return unexpected_message_str; + } + + case bad_record_mac: + { + static const char bad_record_mac_str[] = + "bad_record_mac"; + return bad_record_mac_str; + } + + case record_overflow: + { + static const char record_overflow_str[] = + "record_overflow"; + return record_overflow_str; + } + + case decompression_failure: + { + static const char decompression_failure_str[] = + "decompression_failure"; + return decompression_failure_str; + } + + case handshake_failure: + { + static const char handshake_failure_str[] = + "handshake_failure"; + return handshake_failure_str; + } + + case no_certificate: + { + static const char no_certificate_str[] = + "no_certificate"; + return no_certificate_str; + } + + case bad_certificate: + { + static const char bad_certificate_str[] = + "bad_certificate"; + return bad_certificate_str; + } + + case unsupported_certificate: + { + static const char unsupported_certificate_str[] = + "unsupported_certificate"; + return unsupported_certificate_str; + } + + case certificate_revoked: + { + static const char certificate_revoked_str[] = + "certificate_revoked"; + return certificate_revoked_str; + } + + case certificate_expired: + { + static const char certificate_expired_str[] = + "certificate_expired"; + return certificate_expired_str; + } + + case certificate_unknown: + { + static const char certificate_unknown_str[] = + "certificate_unknown"; + return certificate_unknown_str; + } + + case illegal_parameter: + { + static const char illegal_parameter_str[] = + "illegal_parameter"; + return illegal_parameter_str; + } + + case unknown_ca: + { + static const char unknown_ca_str[] = + "unknown_ca"; + return unknown_ca_str; + } + + case decode_error: + { + static const char decode_error_str[] = + "decode_error"; + return decode_error_str; + } + + case decrypt_error: + { + static const char decrypt_error_str[] = + "decrypt_error"; + return decrypt_error_str; + } + + #ifdef WOLFSSL_MYSQL_COMPATIBLE + /* catch name conflict for enum protocol with MYSQL build */ + case wc_protocol_version: + { + static const char wc_protocol_version_str[] = + "wc_protocol_version"; + return wc_protocol_version_str; + } + + #else + case protocol_version: + { + static const char protocol_version_str[] = + "protocol_version"; + return protocol_version_str; + } + + #endif + case no_renegotiation: + { + static const char no_renegotiation_str[] = + "no_renegotiation"; + return no_renegotiation_str; + } + + case unrecognized_name: + { + static const char unrecognized_name_str[] = + "unrecognized_name"; + return unrecognized_name_str; + } + + case bad_certificate_status_response: + { + static const char bad_certificate_status_response_str[] = + "bad_certificate_status_response"; + return bad_certificate_status_response_str; + } + + case no_application_protocol: + { + static const char no_application_protocol_str[] = + "no_application_protocol"; + return no_application_protocol_str; + } + + default: + WOLFSSL_MSG("Unknown Alert"); + return NULL; + } +} + + +const char* wolfSSL_alert_desc_string_long(int alertID) +{ + WOLFSSL_ENTER("wolfSSL_alert_desc_string_long"); + return wolfSSL_alert_type_string_long(alertID); +} + + +/* Gets the current state of the WOLFSSL structure + * + * ssl WOLFSSL structure to get state of + * + * Returns a human readable string of the WOLFSSL structure state + */ +const char* wolfSSL_state_string_long(const WOLFSSL* ssl) +{ + + static const char* OUTPUT_STR[14][6][3] = { + { + {"SSLv3 Initialization","SSLv3 Initialization","SSLv3 Initialization"}, + {"TLSv1 Initialization","TLSv2 Initialization","TLSv2 Initialization"}, + {"TLSv1_1 Initialization","TLSv1_1 Initialization","TLSv1_1 Initialization"}, + {"TLSv1_2 Initialization","TLSv1_2 Initialization","TLSv1_2 Initialization"}, + {"DTLSv1 Initialization","DTLSv1 Initialization","DTLSv1 Initialization"}, + {"DTLSv1_2 Initialization","DTLSv1_2 Initialization","DTLSv1_2 Initialization"}, + }, + { + {"SSLv3 read Server Hello Verify Request", + "SSLv3 write Server Hello Verify Request", + "SSLv3 Server Hello Verify Request"}, + {"TLSv1 read Server Hello Verify Request", + "TLSv1 write Server Hello Verify Request", + "TLSv1 Server Hello Verify Request"}, + {"TLSv1_1 read Server Hello Verify Request", + "TLSv1_1 write Server Hello Verify Request", + "TLSv1_1 Server Hello Verify Request"}, + {"TLSv1_2 read Server Hello Verify Request", + "TLSv1_2 write Server Hello Verify Request", + "TLSv1_2 Server Hello Verify Request"}, + {"DTLSv1 read Server Hello Verify Request", + "DTLSv1 write Server Hello Verify Request", + "DTLSv1 Server Hello Verify Request"}, + {"DTLSv1_2 read Server Hello Verify Request", + "DTLSv1_2 write Server Hello Verify Request", + "DTLSv1_2 Server Hello Verify Request"}, + }, + { + {"SSLv3 read Server Hello", + "SSLv3 write Server Hello", + "SSLv3 Server Hello"}, + {"TLSv1 read Server Hello", + "TLSv1 write Server Hello", + "TLSv1 Server Hello"}, + {"TLSv1_1 read Server Hello", + "TLSv1_1 write Server Hello", + "TLSv1_1 Server Hello"}, + {"TLSv1_2 read Server Hello", + "TLSv1_2 write Server Hello", + "TLSv1_2 Server Hello"}, + {"DTLSv1 read Server Hello", + "DTLSv1 write Server Hello", + "DTLSv1 Server Hello"}, + {"DTLSv1_2 read Server Hello" + "DTLSv1_2 write Server Hello", + "DTLSv1_2 Server Hello", + }, + }, + { + {"SSLv3 read Server Session Ticket", + "SSLv3 write Server Session Ticket", + "SSLv3 Server Session Ticket"}, + {"TLSv1 read Server Session Ticket", + "TLSv1 write Server Session Ticket", + "TLSv1 Server Session Ticket"}, + {"TLSv1_1 read Server Session Ticket", + "TLSv1_1 write Server Session Ticket", + "TLSv1_1 Server Session Ticket"}, + {"TLSv1_2 read Server Session Ticket", + "TLSv1_2 write Server Session Ticket", + "TLSv1_2 Server Session Ticket"}, + {"DTLSv1 read Server Session Ticket", + "DTLSv1 write Server Session Ticket", + "DTLSv1 Server Session Ticket"}, + {"DTLSv1_2 read Server Session Ticket", + "DTLSv1_2 write Server Session Ticket", + "DTLSv1_2 Server Session Ticket"}, + }, + { + {"SSLv3 read Server Cert", + "SSLv3 write Server Cert", + "SSLv3 Server Cert"}, + {"TLSv1 read Server Cert", + "TLSv1 write Server Cert", + "TLSv1 Server Cert"}, + {"TLSv1_1 read Server Cert", + "TLSv1_1 write Server Cert", + "TLSv1_1 Server Cert"}, + {"TLSv1_2 read Server Cert", + "TLSv1_2 write Server Cert", + "TLSv1_2 Server Cert"}, + {"DTLSv1 read Server Cert", + "DTLSv1 write Server Cert", + "DTLSv1 Server Cert"}, + {"DTLSv1_2 read Server Cert", + "DTLSv1_2 write Server Cert", + "DTLSv1_2 Server Cert"}, + }, + { + {"SSLv3 read Server Key Exchange", + "SSLv3 write Server Key Exchange", + "SSLv3 Server Key Exchange"}, + {"TLSv1 read Server Key Exchange", + "TLSv1 write Server Key Exchange", + "TLSv1 Server Key Exchange"}, + {"TLSv1_1 read Server Key Exchange", + "TLSv1_1 write Server Key Exchange", + "TLSv1_1 Server Key Exchange"}, + {"TLSv1_2 read Server Key Exchange", + "TLSv1_2 write Server Key Exchange", + "TLSv1_2 Server Key Exchange"}, + {"DTLSv1 read Server Key Exchange", + "DTLSv1 write Server Key Exchange", + "DTLSv1 Server Key Exchange"}, + {"DTLSv1_2 read Server Key Exchange", + "DTLSv1_2 write Server Key Exchange", + "DTLSv1_2 Server Key Exchange"}, + }, + { + {"SSLv3 read Server Hello Done", + "SSLv3 write Server Hello Done", + "SSLv3 Server Hello Done"}, + {"TLSv1 read Server Hello Done", + "TLSv1 write Server Hello Done", + "TLSv1 Server Hello Done"}, + {"TLSv1_1 read Server Hello Done", + "TLSv1_1 write Server Hello Done", + "TLSv1_1 Server Hello Done"}, + {"TLSv1_2 read Server Hello Done", + "TLSv1_2 write Server Hello Done", + "TLSv1_2 Server Hello Done"}, + {"DTLSv1 read Server Hello Done", + "DTLSv1 write Server Hello Done", + "DTLSv1 Server Hello Done"}, + {"DTLSv1_2 read Server Hello Done", + "DTLSv1_2 write Server Hello Done", + "DTLSv1_2 Server Hello Done"}, + }, + { + {"SSLv3 read Server Change CipherSpec", + "SSLv3 write Server Change CipherSpec", + "SSLv3 Server Change CipherSpec"}, + {"TLSv1 read Server Change CipherSpec", + "TLSv1 write Server Change CipherSpec", + "TLSv1 Server Change CipherSpec"}, + {"TLSv1_1 read Server Change CipherSpec", + "TLSv1_1 write Server Change CipherSpec", + "TLSv1_1 Server Change CipherSpec"}, + {"TLSv1_2 read Server Change CipherSpec", + "TLSv1_2 write Server Change CipherSpec", + "TLSv1_2 Server Change CipherSpec"}, + {"DTLSv1 read Server Change CipherSpec", + "DTLSv1 write Server Change CipherSpec", + "DTLSv1 Server Change CipherSpec"}, + {"DTLSv1_2 read Server Change CipherSpec", + "DTLSv1_2 write Server Change CipherSpec", + "DTLSv1_2 Server Change CipherSpec"}, + }, + { + {"SSLv3 read Server Finished", + "SSLv3 write Server Finished", + "SSLv3 Server Finished"}, + {"TLSv1 read Server Finished", + "TLSv1 write Server Finished", + "TLSv1 Server Finished"}, + {"TLSv1_1 read Server Finished", + "TLSv1_1 write Server Finished", + "TLSv1_1 Server Finished"}, + {"TLSv1_2 read Server Finished", + "TLSv1_2 write Server Finished", + "TLSv1_2 Server Finished"}, + {"DTLSv1 read Server Finished", + "DTLSv1 write Server Finished", + "DTLSv1 Server Finished"}, + {"DTLSv1_2 read Server Finished", + "DTLSv1_2 write Server Finished", + "DTLSv1_2 Server Finished"}, + }, + { + {"SSLv3 read Client Hello", + "SSLv3 write Client Hello", + "SSLv3 Client Hello"}, + {"TLSv1 read Client Hello", + "TLSv1 write Client Hello", + "TLSv1 Client Hello"}, + {"TLSv1_1 read Client Hello", + "TLSv1_1 write Client Hello", + "TLSv1_1 Client Hello"}, + {"TLSv1_2 read Client Hello", + "TLSv1_2 write Client Hello", + "TLSv1_2 Client Hello"}, + {"DTLSv1 read Client Hello", + "DTLSv1 write Client Hello", + "DTLSv1 Client Hello"}, + {"DTLSv1_2 read Client Hello", + "DTLSv1_2 write Client Hello", + "DTLSv1_2 Client Hello"}, + }, + { + {"SSLv3 read Client Key Exchange", + "SSLv3 write Client Key Exchange", + "SSLv3 Client Key Exchange"}, + {"TLSv1 read Client Key Exchange", + "TLSv1 write Client Key Exchange", + "TLSv1 Client Key Exchange"}, + {"TLSv1_1 read Client Key Exchange", + "TLSv1_1 write Client Key Exchange", + "TLSv1_1 Client Key Exchange"}, + {"TLSv1_2 read Client Key Exchange", + "TLSv1_2 write Client Key Exchange", + "TLSv1_2 Client Key Exchange"}, + {"DTLSv1 read Client Key Exchange", + "DTLSv1 write Client Key Exchange", + "DTLSv1 Client Key Exchange"}, + {"DTLSv1_2 read Client Key Exchange", + "DTLSv1_2 write Client Key Exchange", + "DTLSv1_2 Client Key Exchange"}, + }, + { + {"SSLv3 read Client Change CipherSpec", + "SSLv3 write Client Change CipherSpec", + "SSLv3 Client Change CipherSpec"}, + {"TLSv1 read Client Change CipherSpec", + "TLSv1 write Client Change CipherSpec", + "TLSv1 Client Change CipherSpec"}, + {"TLSv1_1 read Client Change CipherSpec", + "TLSv1_1 write Client Change CipherSpec", + "TLSv1_1 Client Change CipherSpec"}, + {"TLSv1_2 read Client Change CipherSpec", + "TLSv1_2 write Client Change CipherSpec", + "TLSv1_2 Client Change CipherSpec"}, + {"DTLSv1 read Client Change CipherSpec", + "DTLSv1 write Client Change CipherSpec", + "DTLSv1 Client Change CipherSpec"}, + {"DTLSv1_2 read Client Change CipherSpec", + "DTLSv1_2 write Client Change CipherSpec", + "DTLSv1_2 Client Change CipherSpec"}, + }, + { + {"SSLv3 read Client Finished", + "SSLv3 write Client Finished", + "SSLv3 Client Finished"}, + {"TLSv1 read Client Finished", + "TLSv1 write Client Finished", + "TLSv1 Client Finished"}, + {"TLSv1_1 read Client Finished", + "TLSv1_1 write Client Finished", + "TLSv1_1 Client Finished"}, + {"TLSv1_2 read Client Finished", + "TLSv1_2 write Client Finished", + "TLSv1_2 Client Finished"}, + {"DTLSv1 read Client Finished", + "DTLSv1 write Client Finished", + "DTLSv1 Client Finished"}, + {"DTLSv1_2 read Client Finished", + "DTLSv1_2 write Client Finished", + "DTLSv1_2 Client Finished"}, + }, + { + {"SSLv3 Handshake Done", + "SSLv3 Handshake Done", + "SSLv3 Handshake Done"}, + {"TLSv1 Handshake Done", + "TLSv1 Handshake Done", + "TLSv1 Handshake Done"}, + {"TLSv1_1 Handshake Done", + "TLSv1_1 Handshake Done", + "TLSv1_1 Handshake Done"}, + {"TLSv1_2 Handshake Done", + "TLSv1_2 Handshake Done", + "TLSv1_2 Handshake Done"}, + {"DTLSv1 Handshake Done", + "DTLSv1 Handshake Done", + "DTLSv1 Handshake Done"}, + {"DTLSv1_2 Handshake Done" + "DTLSv1_2 Handshake Done" + "DTLSv1_2 Handshake Done"} + } + }; + enum ProtocolVer { + SSL_V3 = 0, + TLS_V1, + TLS_V1_1, + TLS_V1_2, + DTLS_V1, + DTLS_V1_2, + UNKNOWN = 100 + }; + + enum IOMode { + SS_READ = 0, + SS_WRITE, + SS_NEITHER + }; + + enum SslState { + ss_null_state = 0, + ss_server_helloverify, + ss_server_hello, + ss_sessionticket, + ss_server_cert, + ss_server_keyexchange, + ss_server_hellodone, + ss_server_changecipherspec, + ss_server_finished, + ss_client_hello, + ss_client_keyexchange, + ss_client_changecipherspec, + ss_client_finished, + ss_handshake_done + }; + + int protocol = 0; + int cbmode = 0; + int state = 0; + + WOLFSSL_ENTER("wolfSSL_state_string_long"); + if (ssl == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return NULL; + } + + /* Get state of callback */ + if (ssl->cbmode == SSL_CB_MODE_WRITE){ + cbmode = SS_WRITE; + } else if (ssl->cbmode == SSL_CB_MODE_READ){ + cbmode = SS_READ; + } else { + cbmode = SS_NEITHER; + } + + /* Get protocol version */ + switch (ssl->version.major){ + case SSLv3_MAJOR: + switch (ssl->version.minor){ + case TLSv1_MINOR: + protocol = TLS_V1; + break; + case TLSv1_1_MINOR: + protocol = TLS_V1_1; + break; + case TLSv1_2_MINOR: + protocol = TLS_V1_2; + break; + case SSLv3_MINOR: + protocol = SSL_V3; + break; + default: + protocol = UNKNOWN; + } + break; + case DTLS_MAJOR: + switch (ssl->version.minor){ + case DTLS_MINOR: + protocol = DTLS_V1; + break; + case DTLSv1_2_MINOR: + protocol = DTLS_V1_2; + break; + default: + protocol = UNKNOWN; + } + break; + default: + protocol = UNKNOWN; + } + + /* accept process */ + if (ssl->cbmode == SSL_CB_MODE_READ){ + state = ssl->cbtype; + switch (state) { + case hello_verify_request: + state = ss_server_helloverify; + break; + case session_ticket: + state = ss_sessionticket; + break; + case server_hello: + state = ss_server_hello; + break; + case server_hello_done: + state = ss_server_hellodone; + break; + case certificate: + state = ss_server_cert; + break; + case server_key_exchange: + state = ss_server_keyexchange; + break; + case client_hello: + state = ss_client_hello; + break; + case client_key_exchange: + state = ss_client_keyexchange; + break; + case finished: + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ss_client_finished; + else if (ssl->options.side == WOLFSSL_CLIENT_END) + state = ss_server_finished; + else { + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + break; + default: + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + } else { + /* Send process */ + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ssl->options.serverState; + else + state = ssl->options.clientState; + + switch(state){ + case SERVER_HELLOVERIFYREQUEST_COMPLETE: + state = ss_server_helloverify; + break; + case SERVER_HELLO_COMPLETE: + state = ss_server_hello; + break; + case SERVER_CERT_COMPLETE: + state = ss_server_cert; + break; + case SERVER_KEYEXCHANGE_COMPLETE: + state = ss_server_keyexchange; + break; + case SERVER_HELLODONE_COMPLETE: + state = ss_server_hellodone; + break; + case SERVER_CHANGECIPHERSPEC_COMPLETE: + state = ss_server_changecipherspec; + break; + case SERVER_FINISHED_COMPLETE: + state = ss_server_finished; + break; + case CLIENT_HELLO_COMPLETE: + state = ss_client_hello; + break; + case CLIENT_KEYEXCHANGE_COMPLETE: + state = ss_client_keyexchange; + break; + case CLIENT_CHANGECIPHERSPEC_COMPLETE: + state = ss_client_changecipherspec; + break; + case CLIENT_FINISHED_COMPLETE: + state = ss_client_finished; + break; + case HANDSHAKE_DONE: + state = ss_handshake_done; + break; + default: + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + } + + if (protocol == UNKNOWN) + return NULL; + else + return OUTPUT_STR[state][protocol][cbmode]; +} + +/* + * Sets default PEM callback password if null is passed into + * the callback parameter of a PEM_read_bio_* function. + * + * Returns callback phrase size on success or WOLFSSL_FAILURE otherwise. + */ +int wolfSSL_PEM_def_callback(char* name, int num, int w, void* key) +{ + int sz; + (void)w; + WOLFSSL_ENTER("wolfSSL_PEM_def_callback"); + + /* We assume that the user passes a default password as userdata */ + if (key) { + sz = (int)XSTRLEN((const char*)key); + sz = (sz > num) ? num : sz; + XMEMCPY(name, key, sz); + return sz; + } else { + WOLFSSL_MSG("Error, default password cannot be created."); + return WOLFSSL_FAILURE; + } +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) +static long wolf_set_options(long old_op, long op) +{ + /* if SSL_OP_ALL then turn all bug workarounds on */ + if ((op & SSL_OP_ALL) == SSL_OP_ALL) { + WOLFSSL_MSG("\tSSL_OP_ALL"); + } + + /* by default cookie exchange is on with DTLS */ + if ((op & SSL_OP_COOKIE_EXCHANGE) == SSL_OP_COOKIE_EXCHANGE) { + WOLFSSL_MSG("\tSSL_OP_COOKIE_EXCHANGE : on by default"); + } + + if ((op & WOLFSSL_OP_NO_SSLv2) == WOLFSSL_OP_NO_SSLv2) { + WOLFSSL_MSG("\tWOLFSSL_OP_NO_SSLv2 : wolfSSL does not support SSLv2"); + } + +#ifdef SSL_OP_NO_TLSv1_3 + if ((op & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_3"); + } +#endif + + if ((op & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_2"); + } + + if ((op & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_1"); + } + + if ((op & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1"); + } + + if ((op & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) { + WOLFSSL_MSG("\tSSL_OP_NO_SSLv3"); + } + + if ((op & SSL_OP_CIPHER_SERVER_PREFERENCE) == SSL_OP_CIPHER_SERVER_PREFERENCE) { + WOLFSSL_MSG("\tSSL_OP_CIPHER_SERVER_PREFERENCE"); + } + + if ((op & SSL_OP_NO_COMPRESSION) == SSL_OP_NO_COMPRESSION) { + #ifdef HAVE_LIBZ + WOLFSSL_MSG("SSL_OP_NO_COMPRESSION"); + #else + WOLFSSL_MSG("SSL_OP_NO_COMPRESSION: compression not compiled in"); + #endif + } + + return old_op | op; +} +#endif + +#ifdef OPENSSL_EXTRA +long wolfSSL_set_options(WOLFSSL* ssl, long op) +{ + word16 haveRSA = 1; + word16 havePSK = 0; + int keySz = 0; + + WOLFSSL_ENTER("wolfSSL_set_options"); + + if (ssl == NULL) { + return 0; + } + + ssl->options.mask = wolf_set_options(ssl->options.mask, op); + +#ifdef SSL_OP_NO_TLSv1_3 + if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) { + if (ssl->version.minor == TLSv1_3_MINOR) + ssl->version.minor = TLSv1_2_MINOR; + } +#endif + + if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) { + if (ssl->version.minor == TLSv1_2_MINOR) + ssl->version.minor = TLSv1_1_MINOR; + } + + if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) { + if (ssl->version.minor == TLSv1_1_MINOR) + ssl->version.minor = TLSv1_MINOR; + } + + if ((ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) { + if (ssl->version.minor == TLSv1_MINOR) + ssl->version.minor = SSLv3_MINOR; + } + + if ((ssl->options.mask & SSL_OP_NO_COMPRESSION) == SSL_OP_NO_COMPRESSION) { + #ifdef HAVE_LIBZ + ssl->options.usingCompression = 0; + #endif + } + + /* in the case of a version change the cipher suites should be reset */ +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif +#ifdef NO_RSA + haveRSA = 0; +#endif +#ifndef NO_CERTS + keySz = ssl->buffers.keySz; +#endif + + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); + + return ssl->options.mask; +} + + +long wolfSSL_get_options(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_options"); + if(ssl == NULL) + return WOLFSSL_FAILURE; + return ssl->options.mask; +} + +long wolfSSL_clear_options(WOLFSSL* ssl, long opt) +{ + WOLFSSL_ENTER("SSL_clear_options"); + if(ssl == NULL) + return WOLFSSL_FAILURE; + ssl->options.mask &= ~opt; + return ssl->options.mask; +} + + +#if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) +/* clears the counter for number of renegotiations done + * returns the current count before it is cleared */ +long wolfSSL_clear_num_renegotiations(WOLFSSL *s) +{ + long total; + + WOLFSSL_ENTER("wolfSSL_clear_num_renegotiations"); + if (s == NULL) + return 0; + + total = s->secure_rene_count; + s->secure_rene_count = 0; + return total; +} + + +/* return the number of renegotiations since wolfSSL_new */ +long wolfSSL_total_renegotiations(WOLFSSL *s) +{ + WOLFSSL_ENTER("wolfSSL_total_renegotiations"); + return wolfSSL_num_renegotiations(s); +} + + +/* return the number of renegotiations since wolfSSL_new */ +long wolfSSL_num_renegotiations(WOLFSSL* s) +{ + if (s == NULL) { + return 0; + } + + return s->secure_rene_count; +} +#endif /* HAVE_SECURE_RENEGOTIATION || HAVE_SERVER_RENEGOTIATION_INFO */ + +#ifndef NO_DH +long wolfSSL_set_tmp_dh(WOLFSSL *ssl, WOLFSSL_DH *dh) +{ + int pSz, gSz; + byte *p, *g; + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_set_tmp_dh"); + + if (!ssl || !dh) + return BAD_FUNC_ARG; + + /* Get needed size for p and g */ + pSz = wolfSSL_BN_bn2bin(dh->p, NULL); + gSz = wolfSSL_BN_bn2bin(dh->g, NULL); + + if (pSz <= 0 || gSz <= 0) + return WOLFSSL_FATAL_ERROR; + + p = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (!p) + return MEMORY_E; + + g = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (!g) { + XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + return MEMORY_E; + } + + pSz = wolfSSL_BN_bn2bin(dh->p, p); + gSz = wolfSSL_BN_bn2bin(dh->g, g); + + if (pSz >= 0 && gSz >= 0) /* Conversion successful */ + ret = wolfSSL_SetTmpDH(ssl, p, pSz, g, gSz); + + XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + + return pSz > 0 && gSz > 0 ? ret : WOLFSSL_FATAL_ERROR; +} +#endif /* !NO_DH */ + + +#ifdef HAVE_PK_CALLBACKS +long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) +{ + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + + ssl->loggingCtx = arg; + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_PK_CALLBACKS */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) +const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *sess, unsigned int *sid_ctx_length) +{ + const byte *c = wolfSSL_SESSION_get_id((SSL_SESSION *)sess, sid_ctx_length); + return c; +} +#endif + +/*** TBD ***/ +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API int wolfSSL_sk_SSL_COMP_zero(WOLFSSL_STACK* st) +{ + (void)st; + WOLFSSL_STUB("wolfSSL_sk_SSL_COMP_zero"); + /* wolfSSL_set_options(ssl, SSL_OP_NO_COMPRESSION); */ + return WOLFSSL_FAILURE; +} +#endif + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST +long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) +{ + WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type"); + + if (s == NULL){ + return BAD_FUNC_ARG; + } + + if (type == TLSEXT_STATUSTYPE_ocsp){ + int r = 0; + r = TLSX_UseCertificateStatusRequest(&s->extensions, type, 0, s, + s->heap, s->devId); + return (long)r; + } else { + WOLFSSL_MSG( + "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type."); + return SSL_FAILURE; + } + +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_get_tlsext_status_exts"); + return WOLFSSL_FAILURE; +} +#endif + +/*** TBD ***/ +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_set_tlsext_status_exts"); + return WOLFSSL_FAILURE; +} +#endif + +/*** TBD ***/ +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_get_tlsext_status_ids"); + return WOLFSSL_FAILURE; +} +#endif + +/*** TBD ***/ +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_set_tlsext_status_ids"); + return WOLFSSL_FAILURE; +} +#endif + +/*** TBD ***/ +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API int SSL_SESSION_set1_id(WOLFSSL_SESSION *s, const unsigned char *sid, unsigned int sid_len) +{ + (void)s; + (void)sid; + (void)sid_len; + WOLFSSL_STUB("SSL_SESSION_set1_id"); + return WOLFSSL_FAILURE; +} +#endif + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API int SSL_SESSION_set1_id_context(WOLFSSL_SESSION *s, const unsigned char *sid_ctx, unsigned int sid_ctx_len) +{ + (void)s; + (void)sid_ctx; + (void)sid_ctx_len; + WOLFSSL_STUB("SSL_SESSION_set1_id_context"); + return WOLFSSL_FAILURE; +} +#endif + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD) \ + || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) +WOLFSSL_X509_ALGOR* wolfSSL_X509_ALGOR_new(void) +{ + WOLFSSL_X509_ALGOR* ret; + ret = (WOLFSSL_X509_ALGOR*)XMALLOC(sizeof(WOLFSSL_X509_ALGOR), NULL, + DYNAMIC_TYPE_OPENSSL); + if (ret) { + XMEMSET(ret, 0, sizeof(WOLFSSL_X509_ALGOR)); + } + return ret; +} + +void wolfSSL_X509_ALGOR_free(WOLFSSL_X509_ALGOR *alg) +{ + if (alg) { + wolfSSL_ASN1_OBJECT_free(alg->algorithm); + wolfSSL_ASN1_TYPE_free(alg->parameter); + XFREE(alg, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +/* Returns X509_ALGOR struct with signature algorithm */ +const WOLFSSL_X509_ALGOR* wolfSSL_X509_get0_tbs_sigalg(const WOLFSSL_X509 *x509) +{ + WOLFSSL_ENTER("X509_get0_tbs_sigalg"); + + if (x509 == NULL) { + WOLFSSL_MSG("x509 struct NULL error"); + return NULL; + } + + return &x509->algor; +} + +/* Sets paobj pointer to X509_ALGOR signature algorithm */ +void wolfSSL_X509_ALGOR_get0(const WOLFSSL_ASN1_OBJECT **paobj, int *pptype, + const void **ppval, const WOLFSSL_X509_ALGOR *algor) +{ + WOLFSSL_ENTER("X509_ALGOR_get0"); + + if (!algor) { + WOLFSSL_MSG("algor object is NULL"); + return; + } + + if (paobj) + *paobj = algor->algorithm; + if (ppval) + *ppval = algor->algorithm; + if (pptype) { + if (algor->parameter) { + *pptype = algor->parameter->type; + } + else { + /* Default to V_ASN1_OBJECT */ + *pptype = V_ASN1_OBJECT; + } + } +} + +/** + * Populate algor members. + * + * @param algor The object to be set + * @param aobj The value to be set in algor->algorithm + * @param ptype The type of algor->parameter + * @param pval The value of algor->parameter + * @return WOLFSSL_SUCCESS on success + * WOLFSSL_FAILURE on missing parameters or bad malloc + */ +int wolfSSL_X509_ALGOR_set0(WOLFSSL_X509_ALGOR *algor, WOLFSSL_ASN1_OBJECT *aobj, + int ptype, void *pval) +{ + if (!algor) { + return WOLFSSL_FAILURE; + } + if (aobj) { + algor->algorithm = aobj; + } + if (pval) { + if (!algor->parameter) { + algor->parameter = wolfSSL_ASN1_TYPE_new(); + if (!algor->parameter) { + return WOLFSSL_FAILURE; + } + } + wolfSSL_ASN1_TYPE_set(algor->parameter, ptype, pval); + } + return WOLFSSL_SUCCESS; +} + +/** + * Set `a` in a smart way. + * + * @param a Object to set + * @param type The type of object in value + * @param value Object to set + */ +void wolfSSL_ASN1_TYPE_set(WOLFSSL_ASN1_TYPE *a, int type, void *value) +{ + if (!a || !value) { + return; + } + switch (type) { + case V_ASN1_OBJECT: + a->value.object = value; + break; + case V_ASN1_UTCTIME: + a->value.utctime = value; + break; + case V_ASN1_GENERALIZEDTIME: + a->value.generalizedtime = value; + break; + default: + WOLFSSL_MSG("Unknown or unsupported ASN1_TYPE"); + return; + } + a->type = type; +} + +/** + * Allocate a new WOLFSSL_ASN1_TYPE object. + * + * @return New zero'ed WOLFSSL_ASN1_TYPE object + */ +WOLFSSL_ASN1_TYPE* wolfSSL_ASN1_TYPE_new(void) +{ + WOLFSSL_ASN1_TYPE* ret = (WOLFSSL_ASN1_TYPE*)XMALLOC(sizeof(WOLFSSL_ASN1_TYPE), + NULL, DYNAMIC_TYPE_OPENSSL); + if (!ret) + return NULL; + XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TYPE)); + return ret; +} + +/** + * Free WOLFSSL_ASN1_TYPE and all its members. + * + * @param at Object to free + */ +void wolfSSL_ASN1_TYPE_free(WOLFSSL_ASN1_TYPE* at) +{ + if (at) { + switch (at->type) { + case V_ASN1_OBJECT: + wolfSSL_ASN1_OBJECT_free(at->value.object); + break; + case V_ASN1_UTCTIME: + wolfSSL_ASN1_TIME_free(at->value.utctime); + break; + case V_ASN1_GENERALIZEDTIME: + wolfSSL_ASN1_TIME_free(at->value.generalizedtime); + break; + default: + WOLFSSL_MSG("Unknown or unsupported ASN1_TYPE"); + break; + } + XFREE(at, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +/** + * Allocate a new WOLFSSL_X509_PUBKEY object. + * + * @return New zero'ed WOLFSSL_X509_PUBKEY object + */ +WOLFSSL_X509_PUBKEY *wolfSSL_X509_PUBKEY_new(void) +{ + WOLFSSL_X509_PUBKEY *ret; + ret = (WOLFSSL_X509_PUBKEY*)XMALLOC(sizeof(WOLFSSL_X509_PUBKEY), NULL, + DYNAMIC_TYPE_OPENSSL); + if (!ret) { + return NULL; + } + XMEMSET(ret, 0, sizeof(WOLFSSL_X509_PUBKEY)); + ret->algor = wolfSSL_X509_ALGOR_new(); + if (!ret->algor) { + wolfSSL_X509_PUBKEY_free(ret); + return NULL; + } + return ret; +} + +/** + * Free WOLFSSL_X509_PUBKEY and all its members. + * + * @param at Object to free + */ +void wolfSSL_X509_PUBKEY_free(WOLFSSL_X509_PUBKEY *x) +{ + if (x) { + if (x->algor) { + wolfSSL_X509_ALGOR_free(x->algor); + } + if (x->pkey) { + wolfSSL_EVP_PKEY_free(x->pkey); + } + XFREE(x, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +/* Returns X509_PUBKEY structure containing X509_ALGOR and EVP_PKEY */ +WOLFSSL_X509_PUBKEY* wolfSSL_X509_get_X509_PUBKEY(const WOLFSSL_X509* x509) +{ + WOLFSSL_ENTER("X509_get_X509_PUBKEY"); + + if (x509 == NULL) { + WOLFSSL_MSG("x509 struct NULL error"); + return NULL; + } + + return (WOLFSSL_X509_PUBKEY*)&x509->key; +} + +/* Sets ppkalg pointer to X509_PUBKEY algorithm. Returns WOLFSSL_SUCCESS on + success or WOLFSSL_FAILURE on error. */ +int wolfSSL_X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, WOLFSSL_X509_ALGOR **pa, + WOLFSSL_X509_PUBKEY *pub) +{ + WOLFSSL_ENTER("X509_PUBKEY_get0_param"); + + if (!pub || !pub->pubKeyOID) { + WOLFSSL_MSG("X509_PUBKEY struct not populated"); + return WOLFSSL_FAILURE; + } + + if (!pub->algor) { + if (!(pub->algor = wolfSSL_X509_ALGOR_new())) { + return WOLFSSL_FAILURE; + } + pub->algor->algorithm = wolfSSL_OBJ_nid2obj(pub->pubKeyOID); + if (pub->algor->algorithm == NULL) { + WOLFSSL_MSG("Failed to create object from NID"); + return WOLFSSL_FAILURE; + } + } + + if (pa) + *pa = pub->algor; + if (ppkalg) + *ppkalg = pub->algor->algorithm; + if (pk) + wolfSSL_EVP_PKEY_get_der(pub->pkey, (unsigned char **)pk); + if (ppklen) + *ppklen = wolfSSL_EVP_PKEY_get_der(pub->pkey, NULL); + + return WOLFSSL_SUCCESS; +} + +/* Returns a pointer to the pkey when passed a key */ +WOLFSSL_EVP_PKEY* wolfSSL_X509_PUBKEY_get(WOLFSSL_X509_PUBKEY* key) +{ + WOLFSSL_ENTER("wolfSSL_X509_PUBKEY_get"); + if(key == NULL || key->pkey == NULL){ + WOLFSSL_LEAVE("wolfSSL_X509_PUBKEY_get", BAD_FUNC_ARG); + return NULL; + } + WOLFSSL_LEAVE("wolfSSL_X509_PUBKEY_get", WOLFSSL_SUCCESS); + return key->pkey; +} + +int wolfSSL_X509_PUBKEY_set(WOLFSSL_X509_PUBKEY **x, WOLFSSL_EVP_PKEY *key) +{ + WOLFSSL_X509_PUBKEY *pk = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_PUBKEY_set"); + + if (!x || !key) { + return WOLFSSL_FAILURE; + } + + if (!(pk = wolfSSL_X509_PUBKEY_new())) { + return WOLFSSL_FAILURE; + } + + switch (key->type) { +#ifndef NO_RSA + case EVP_PKEY_RSA: + pk->algor->algorithm= wolfSSL_OBJ_nid2obj(RSAk); + break; +#endif +#ifndef NO_DSA + case EVP_PKEY_DSA: + pk->algor->algorithm = wolfSSL_OBJ_nid2obj(DSAk); + break; +#endif +#ifdef HAVE_ECC + case EVP_PKEY_EC: + pk->algor->algorithm = wolfSSL_OBJ_nid2obj(ECDSAk); + break; +#endif + default: + WOLFSSL_MSG("Unknown key type"); + goto error; + } + + if (!pk->algor->algorithm) { + WOLFSSL_MSG("Failed to create algorithm object"); + goto error; + } + + if (!wolfSSL_EVP_PKEY_up_ref(key)) { + WOLFSSL_MSG("Failed to up key reference"); + goto error; + } + pk->pkey = key; + + wolfSSL_X509_PUBKEY_free(*x); + *x = pk; + return WOLFSSL_SUCCESS; +error: + if (pk) { + wolfSSL_X509_PUBKEY_free(pk); + } + return WOLFSSL_FAILURE; +} + +#endif /* OPENSSL_ALL || WOLFSSL_APACHE_HTTPD || WOLFSSL_HAPROXY*/ + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl) +{ + (void)ssl; + WOLFSSL_STUB("SSL_get_privatekey"); + return NULL; +} +#endif + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API int i2t_ASN1_OBJECT(char *buf, int buf_len, WOLFSSL_ASN1_OBJECT *a) +{ + (void)buf; + (void)buf_len; + (void)a; + WOLFSSL_STUB("i2t_ASN1_OBJECT"); + return -1; +} +#endif + +/* Return number of bytes written to BIO on success. 0 on failure. */ +WOLFSSL_API int wolfSSL_i2a_ASN1_OBJECT(WOLFSSL_BIO *bp, + WOLFSSL_ASN1_OBJECT *a) +{ + int length = 0; + word32 idx = 0; + const char null_str[] = "NULL"; + + WOLFSSL_ENTER("wolfSSL_i2a_ASN1_OBJECT"); + + if (bp == NULL) + return WOLFSSL_FAILURE; + + if (a == NULL) { + /* Write "NULL" */ + if (wolfSSL_BIO_write(bp, null_str, (int)XSTRLEN(null_str)) == + (int)XSTRLEN(null_str)) { + return (int)XSTRLEN(null_str); + } + else { + return WOLFSSL_FAILURE; + } + } + + + if ((a->obj == NULL) || (a->obj[idx++] != ASN_OBJECT_ID)) { + WOLFSSL_MSG("Bad ASN1 Object"); + return WOLFSSL_FAILURE; + } + + if (GetLength((const byte*)a->obj, &idx, &length, + a->objSz) < 0 || length < 0) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bp, a->obj + idx, length) == (int)length) { + return length; + } + + return WOLFSSL_FAILURE; +} + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API size_t SSL_get_finished(const WOLFSSL *s, void *buf, size_t count) +{ + (void)s; + (void)buf; + (void)count; + WOLFSSL_STUB("SSL_get_finished"); + return WOLFSSL_FAILURE; +} +#endif + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API size_t SSL_get_peer_finished(const WOLFSSL *s, void *buf, size_t count) +{ + (void)s; + (void)buf; + (void)count; + WOLFSSL_STUB("SSL_get_peer_finished"); + return WOLFSSL_FAILURE; +} +#endif +#endif /* WOLFSSL_HAPROXY */ + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API void SSL_CTX_set_tmp_dh_callback(WOLFSSL_CTX *ctx, WOLFSSL_DH *(*dh) (WOLFSSL *ssl, int is_export, int keylength)) +{ + (void)ctx; + (void)dh; + WOLFSSL_STUB("SSL_CTX_set_tmp_dh_callback"); +} +#endif + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API WOLF_STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void) +{ + WOLFSSL_STUB("SSL_COMP_get_compression_methods"); + return NULL; +} +#endif + + +int wolfSSL_sk_SSL_CIPHER_num(const WOLF_STACK_OF(WOLFSSL_CIPHER)* p) +{ + WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_num"); + if (p == NULL) { + return WOLFSSL_FATAL_ERROR; + } + return (int)p->num; +} + +#if !defined(NO_FILESYSTEM) +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + (void)fp; + (void)x; + (void)cb; + (void)u; + WOLFSSL_STUB("PEM_read_PrivateKey"); + return NULL; +} +#endif +#endif + +#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) +/* Loads certificate(s) files in pem format into X509_STORE struct from either + * a file or directory. + * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE if an error occurs. + */ +WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, + const char *file, const char *dir) +{ + WOLFSSL_CTX* ctx; + char *name = NULL; + int ret = WOLFSSL_SUCCESS; + int successes = 0; +#ifdef WOLFSSL_SMALL_STACK + ReadDirCtx* readCtx = NULL; +#else + ReadDirCtx readCtx[1]; +#endif + + WOLFSSL_ENTER("X509_STORE_load_locations"); + + if (str == NULL || str->cm == NULL || (file == NULL && dir == NULL)) + return WOLFSSL_FAILURE; + + /* tmp ctx for setting our cert manager */ + ctx = wolfSSL_CTX_new(cm_pick_method()); + if (ctx == NULL) + return WOLFSSL_FAILURE; + + wolfSSL_CertManagerFree(ctx->cm); + ctx->cm = str->cm; + +#ifdef HAVE_CRL + if (str->cm->crl == NULL) { + if (wolfSSL_CertManagerEnableCRL(str->cm, 0) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Enable CRL failed"); + wolfSSL_CTX_free(ctx); + return WOLFSSL_FAILURE; + } + } +#endif + + /* Load individual file */ + if (file) { + /* Try to process file with type DETECT_CERT_TYPE to parse the + correct certificate header and footer type */ + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, DETECT_CERT_TYPE, + NULL, 0, str->cm->crl, 0); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to load file"); + ret = WOLFSSL_FAILURE; + } + } + + /* Load files in dir */ + if (dir && ret == WOLFSSL_SUCCESS) { + #ifdef WOLFSSL_SMALL_STACK + readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (readCtx == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + #endif + + /* try to load each regular file in dir */ + ret = wc_ReadDirFirst(readCtx, dir, &name); + while (ret == 0 && name) { + WOLFSSL_MSG(name); + /* Try to process file with type DETECT_CERT_TYPE to parse the + correct certificate header and footer type */ + ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, DETECT_CERT_TYPE, + NULL, 0, str->cm->crl, 0); + /* Not failing on load errors */ + if (ret != WOLFSSL_SUCCESS) + WOLFSSL_MSG("Failed to load file in path, continuing"); + else + successes++; + + ret = wc_ReadDirNext(readCtx, dir, &name); + } + wc_ReadDirClose(readCtx); + + /* Success if at least one file in dir was loaded */ + if (successes > 0) + ret = WOLFSSL_SUCCESS; + else { + WOLFSSL_ERROR(ret); + ret = WOLFSSL_FAILURE; + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX); + #endif + } + + ctx->cm = NULL; + wolfSSL_CTX_free(ctx); + + return ret; +} +#endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */ + +#ifndef NO_WOLFSSL_STUB +/*** TBD ***/ +WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(void *ciphers, int idx) +{ + (void)ciphers; + (void)idx; + WOLFSSL_STUB("wolfSSL_sk_SSL_CIPHER_value"); + return NULL; +} +#endif + +WOLFSSL_API void ERR_load_SSL_strings(void) +{ + +} + +#ifdef HAVE_OCSP +WOLFSSL_API long wolfSSL_get_tlsext_status_ocsp_resp(WOLFSSL *s, unsigned char **resp) +{ + if (s == NULL || resp == NULL) + return 0; + + *resp = s->ocspResp; + return s->ocspRespSz; +} + +WOLFSSL_API long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *s, unsigned char *resp, int len) +{ + if (s == NULL) + return WOLFSSL_FAILURE; + + s->ocspResp = resp; + s->ocspRespSz = len; + + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_OCSP */ + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +long wolfSSL_get_verify_result(const WOLFSSL *ssl) +{ + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + + return ssl->peerVerifyRet; +} +#endif + +#ifdef OPENSSL_EXTRA + +#ifndef NO_WOLFSSL_STUB +/* shows the number of accepts attempted by CTX in it's lifetime */ +long wolfSSL_CTX_sess_accept(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_accept"); + (void)ctx; + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +/* shows the number of connects attempted CTX in it's lifetime */ +long wolfSSL_CTX_sess_connect(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_connect"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +/* shows the number of accepts completed by CTX in it's lifetime */ +long wolfSSL_CTX_sess_accept_good(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_accept_good"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +/* shows the number of connects completed by CTX in it's lifetime */ +long wolfSSL_CTX_sess_connect_good(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_connect_good"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +/* shows the number of renegotiation accepts attempted by CTX */ +long wolfSSL_CTX_sess_accept_renegotiate(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_accept_renegotiate"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +/* shows the number of renegotiation accepts attempted by CTX */ +long wolfSSL_CTX_sess_connect_renegotiate(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_connect_renegotiate"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_sess_hits(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_hits"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_sess_cb_hits(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_cb_hits"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_sess_cache_full(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_cache_full"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_sess_misses(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_misses"); + (void)ctx; + return 0; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_sess_timeouts(WOLFSSL_CTX* ctx) +{ + WOLFSSL_STUB("wolfSSL_CTX_sess_timeouts"); + (void)ctx; + return 0; +} +#endif + + +/* Return the total number of sessions */ +long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx) +{ + word32 total = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_sess_number"); + (void)ctx; + +#ifdef WOLFSSL_SESSION_STATS + if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != SSL_SUCCESS) { + WOLFSSL_MSG("Error getting session stats"); + } +#else + WOLFSSL_MSG("Please use macro WOLFSSL_SESSION_STATS for session stats"); +#endif + + return (long)total; +} + + +#ifndef NO_CERTS +long wolfSSL_CTX_add_extra_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + byte* chain = NULL; + long chainSz = 0; + int derSz; + const byte* der; + int ret; + int idx = 0; + DerBuffer *derBuffer = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_add_extra_chain_cert"); + + if (ctx == NULL || x509 == NULL) { + WOLFSSL_MSG("Bad Argument"); + return WOLFSSL_FAILURE; + } + + der = wolfSSL_X509_get_der(x509, &derSz); + if (der == NULL || derSz <= 0) { + WOLFSSL_MSG("Error getting X509 DER"); + return WOLFSSL_FAILURE; + } + + if (ctx->certificate == NULL) { + WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); + + /* Process buffer makes first certificate the leaf. */ + ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, + NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx)); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); + return WOLFSSL_FAILURE; + } + } + else { + /* TODO: Do this elsewhere. */ + ret = AllocDer(&derBuffer, derSz, CERT_TYPE, ctx->heap); + if (ret != 0) { + WOLFSSL_MSG("Memory Error"); + return WOLFSSL_FAILURE; + } + XMEMCPY(derBuffer->buffer, der, derSz); + ret = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA, + GET_VERIFY_SETTING_CTX(ctx)); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); + return WOLFSSL_FAILURE; + } + + /* adding cert to existing chain */ + if (ctx->certChain != NULL && ctx->certChain->length > 0) { + chainSz += ctx->certChain->length; + } + chainSz += OPAQUE24_LEN + derSz; + + chain = (byte*)XMALLOC(chainSz, ctx->heap, DYNAMIC_TYPE_DER); + if (chain == NULL) { + WOLFSSL_MSG("Memory Error"); + return WOLFSSL_FAILURE; + } + + if (ctx->certChain != NULL && ctx->certChain->length > 0) { + XMEMCPY(chain, ctx->certChain->buffer, ctx->certChain->length); + idx = ctx->certChain->length; + } + c32to24(derSz, chain + idx); + idx += OPAQUE24_LEN, + XMEMCPY(chain + idx, der, derSz); + idx += derSz; +#ifdef WOLFSSL_TLS13 + ctx->certChainCnt++; +#endif + + FreeDer(&ctx->certChain); + ret = AllocDer(&ctx->certChain, idx, CERT_TYPE, ctx->heap); + if (ret == 0) { + XMEMCPY(ctx->certChain->buffer, chain, idx); + } + } + + /* on success WOLFSSL_X509 memory is responsibility of ctx */ + wolfSSL_X509_free(x509); + if (chain != NULL) + XFREE(chain, ctx->heap, DYNAMIC_TYPE_DER); + + return WOLFSSL_SUCCESS; +} + + +long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) +{ + if (ctx == NULL || ctx->cm == NULL) { + return WOLFSSL_FAILURE; + } + + ctx->cm->ocspIOCtx = arg; + return WOLFSSL_SUCCESS; +} + +#endif /* NO_CERTS */ + + +/* Get the session cache mode for CTX + * + * ctx WOLFSSL_CTX struct to get cache mode from + * + * Returns a bit mask that has the session cache mode */ +WOLFSSL_API long wolfSSL_CTX_get_session_cache_mode(WOLFSSL_CTX* ctx) +{ + long m = 0; + + WOLFSSL_ENTER("SSL_CTX_set_session_cache_mode"); + + if (ctx == NULL) { + return m; + } + + if (ctx->sessionCacheOff != 1) { + m |= SSL_SESS_CACHE_SERVER; + } + + if (ctx->sessionCacheFlushOff == 1) { + m |= SSL_SESS_CACHE_NO_AUTO_CLEAR; + } + +#ifdef HAVE_EXT_CACHE + if (ctx->internalCacheOff == 1) { + m |= SSL_SESS_CACHE_NO_INTERNAL_STORE; + } +#endif + + return m; +} + + +int wolfSSL_CTX_get_read_ahead(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) { + return WOLFSSL_FAILURE; + } + + return ctx->readAhead; +} + + +int wolfSSL_CTX_set_read_ahead(WOLFSSL_CTX* ctx, int v) +{ + if (ctx == NULL) { + return WOLFSSL_FAILURE; + } + + ctx->readAhead = (byte)v; + + return WOLFSSL_SUCCESS; +} + + +long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg(WOLFSSL_CTX* ctx, + void* arg) +{ + if (ctx == NULL) { + return WOLFSSL_FAILURE; + } + + ctx->userPRFArg = arg; + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_DES3 +/* 0 on success */ +int wolfSSL_DES_set_key(WOLFSSL_const_DES_cblock* myDes, + WOLFSSL_DES_key_schedule* key) +{ +#ifdef WOLFSSL_CHECK_DESKEY + return wolfSSL_DES_set_key_checked(myDes, key); +#else + wolfSSL_DES_set_key_unchecked(myDes, key); + return 0; +#endif +} + + + +/* return true in fail case (1) */ +static int DES_check(word32 mask, word32 mask2, unsigned char* key) +{ + word32 value[2]; + + /* sanity check on length made in wolfSSL_DES_set_key_checked */ + value[0] = mask; + value[1] = mask2; + return (XMEMCMP(value, key, sizeof(value)) == 0)? 1: 0; +} + + +/* check that the key is odd parity and is not a weak key + * returns -1 if parity is wrong, -2 if weak/null key and 0 on success */ +int wolfSSL_DES_set_key_checked(WOLFSSL_const_DES_cblock* myDes, + WOLFSSL_DES_key_schedule* key) +{ + if (myDes == NULL || key == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_DES_set_key_checked"); + return -2; + } + else { + word32 sz = sizeof(WOLFSSL_DES_key_schedule); + + /* sanity check before call to DES_check */ + if (sz != (sizeof(word32) * 2)) { + WOLFSSL_MSG("Unexpected WOLFSSL_DES_key_schedule size"); + return -2; + } + + /* check odd parity */ + if (wolfSSL_DES_check_key_parity(myDes) != 1) { + WOLFSSL_MSG("Odd parity test fail"); + return -1; + } + + if (wolfSSL_DES_is_weak_key(myDes) == 1) { + WOLFSSL_MSG("Weak key found"); + return -2; + } + + /* passed tests, now copy over key */ + XMEMCPY(key, myDes, sizeof(WOLFSSL_const_DES_cblock)); + + return 0; + } +} + + +/* check is not weak. Weak key list from Nist "Recommendation for the Triple + * Data Encryption Algorithm (TDEA) Block Cipher" + * + * returns 1 if is weak 0 if not + */ +int wolfSSL_DES_is_weak_key(WOLFSSL_const_DES_cblock* key) +{ + word32 mask, mask2; + + WOLFSSL_ENTER("wolfSSL_DES_is_weak_key"); + + if (key == NULL) { + WOLFSSL_MSG("NULL key passed in"); + return 1; + } + + mask = 0x01010101; mask2 = 0x01010101; + if (DES_check(mask, mask2, *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0xFEFEFEFE; mask2 = 0xFEFEFEFE; + if (DES_check(mask, mask2, *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0xE0E0E0E0; mask2 = 0xF1F1F1F1; + if (DES_check(mask, mask2, *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0x1F1F1F1F; mask2 = 0x0E0E0E0E; + if (DES_check(mask, mask2, *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + /* semi-weak *key check (list from same Nist paper) */ + mask = 0x011F011F; mask2 = 0x010E010E; + if (DES_check(mask, mask2, *key) || + DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0x01E001E0; mask2 = 0x01F101F1; + if (DES_check(mask, mask2, *key) || + DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0x01FE01FE; mask2 = 0x01FE01FE; + if (DES_check(mask, mask2, *key) || + DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0x1FE01FE0; mask2 = 0x0EF10EF1; + if (DES_check(mask, mask2, *key) || + DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + mask = 0x1FFE1FFE; mask2 = 0x0EFE0EFE; + if (DES_check(mask, mask2, *key) || + DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { + WOLFSSL_MSG("Weak key found"); + return 1; + } + + return 0; +} + + +void wolfSSL_DES_set_key_unchecked(WOLFSSL_const_DES_cblock* myDes, + WOLFSSL_DES_key_schedule* key) +{ + if (myDes != NULL && key != NULL) { + XMEMCPY(key, myDes, sizeof(WOLFSSL_const_DES_cblock)); + } +} + + +/* Sets the parity of the DES key for use */ +void wolfSSL_DES_set_odd_parity(WOLFSSL_DES_cblock* myDes) +{ + word32 i; + word32 sz = sizeof(WOLFSSL_DES_cblock); + + WOLFSSL_ENTER("wolfSSL_DES_set_odd_parity"); + + for (i = 0; i < sz; i++) { + unsigned char c = (*myDes)[i]; + if (( + ((c >> 1) & 0x01) ^ + ((c >> 2) & 0x01) ^ + ((c >> 3) & 0x01) ^ + ((c >> 4) & 0x01) ^ + ((c >> 5) & 0x01) ^ + ((c >> 6) & 0x01) ^ + ((c >> 7) & 0x01)) == (c & 0x01)) { + WOLFSSL_MSG("Flipping parity bit"); + (*myDes)[i] = c ^ 0x01; + } + } +} + +int wolfSSL_DES_check_key_parity(WOLFSSL_DES_cblock *myDes) +{ + word32 i; + word32 sz = sizeof(WOLFSSL_DES_cblock); + + WOLFSSL_ENTER("wolfSSL_DES_check_key_parity"); + + for (i = 0; i < sz; i++) { + unsigned char c = (*myDes)[i]; + if (( + ((c >> 1) & 0x01) ^ + ((c >> 2) & 0x01) ^ + ((c >> 3) & 0x01) ^ + ((c >> 4) & 0x01) ^ + ((c >> 5) & 0x01) ^ + ((c >> 6) & 0x01) ^ + ((c >> 7) & 0x01)) == (c & 0x01)) { + return 0; + } + } + return 1; +} + +#ifdef WOLFSSL_DES_ECB +/* Encrypt or decrypt input message desa with key and get output in desb. + * if enc is DES_ENCRYPT,input message is encrypted or + * if enc is DES_DECRYPT,input message is decrypted. + * */ +void wolfSSL_DES_ecb_encrypt(WOLFSSL_DES_cblock* desa, + WOLFSSL_DES_cblock* desb, WOLFSSL_DES_key_schedule* key, int enc) +{ + Des myDes; + + WOLFSSL_ENTER("wolfSSL_DES_ecb_encrypt"); + + if (desa == NULL || key == NULL || desb == NULL || + (enc != DES_ENCRYPT && enc != DES_DECRYPT)) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_DES_ecb_encrypt"); + } else { + if (wc_Des_SetKey(&myDes, (const byte*) key, + (const byte*) NULL, !enc) != 0) { + WOLFSSL_MSG("wc_Des_SetKey return error."); + return; + } + if (enc){ + if (wc_Des_EcbEncrypt(&myDes, (byte*) desb, (const byte*) desa, + sizeof(WOLFSSL_DES_cblock)) != 0){ + WOLFSSL_MSG("wc_Des_EcbEncrypt return error."); + } + } else { + if (wc_Des_EcbDecrypt(&myDes, (byte*) desb, (const byte*) desa, + sizeof(WOLFSSL_DES_cblock)) != 0){ + WOLFSSL_MSG("wc_Des_EcbDecrpyt return error."); + } + } + } +} +#endif +#endif /* NO_DES3 */ + +#ifndef NO_RC4 +/* Set the key state for Arc4 structure. + * + * key Arc4 structure to use + * len length of data buffer + * data initial state to set Arc4 structure + */ +void wolfSSL_RC4_set_key(WOLFSSL_RC4_KEY* key, int len, + const unsigned char* data) +{ + typedef char rc4_test[sizeof(WOLFSSL_RC4_KEY) >= sizeof(Arc4) ? 1 : -1]; + (void)sizeof(rc4_test); + + WOLFSSL_ENTER("wolfSSL_RC4_set_key"); + + if (key == NULL || len < 0) { + WOLFSSL_MSG("bad argument passed in"); + return; + } + + XMEMSET(key, 0, sizeof(WOLFSSL_RC4_KEY)); + wc_Arc4SetKey((Arc4*)key, data, (word32)len); +} + + +/* Encrypt/decrypt with Arc4 structure. + * + * len length of buffer to encrypt/decrypt (in/out) + * in buffer to encrypt/decrypt + * out results of encryption/decryption + */ +void wolfSSL_RC4(WOLFSSL_RC4_KEY* key, size_t len, + const unsigned char* in, unsigned char* out) +{ + WOLFSSL_ENTER("wolfSSL_RC4"); + + if (key == NULL || in == NULL || out == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return; + } + + wc_Arc4Process((Arc4*)key, out, in, (word32)len); +} +#endif /* NO_RC4 */ + +#ifndef NO_AES + +#ifdef WOLFSSL_AES_DIRECT +/* AES encrypt direct, it is expected to be blocks of AES_BLOCK_SIZE for input. + * + * input Data to encrypt + * output Encrypted data after done + * key AES key to use for encryption + */ +void wolfSSL_AES_encrypt(const unsigned char* input, unsigned char* output, + AES_KEY *key) +{ + WOLFSSL_ENTER("wolfSSL_AES_encrypt"); + + if (input == NULL || output == NULL || key == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return; + } + + wc_AesEncryptDirect((Aes*)key, output, input); +} + + +/* AES decrypt direct, it is expected to be blocks of AES_BLOCK_SIZE for input. + * + * input Data to decrypt + * output Decrypted data after done + * key AES key to use for encryption + */ +void wolfSSL_AES_decrypt(const unsigned char* input, unsigned char* output, + AES_KEY *key) +{ + WOLFSSL_ENTER("wolfSSL_AES_decrypt"); + + if (input == NULL || output == NULL || key == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return; + } + + wc_AesDecryptDirect((Aes*)key, output, input); +} +#endif /* WOLFSSL_AES_DIRECT */ + +/* Setup of an AES key to use for encryption. + * + * key key in bytes to use for encryption + * bits size of key in bits + * aes AES structure to initialize + */ +int wolfSSL_AES_set_encrypt_key(const unsigned char *key, const int bits, + AES_KEY *aes) +{ + typedef char aes_test[sizeof(AES_KEY) >= sizeof(Aes) ? 1 : -1]; + (void)sizeof(aes_test); + + WOLFSSL_ENTER("wolfSSL_AES_set_encrypt_key"); + + if (key == NULL || aes == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return -1; + } + + XMEMSET(aes, 0, sizeof(AES_KEY)); + if (wc_AesSetKey((Aes*)aes, key, ((bits)/8), NULL, AES_ENCRYPTION) != 0) { + WOLFSSL_MSG("Error in setting AES key"); + return -1; + } + return 0; +} + + +/* Setup of an AES key to use for decryption. + * + * key key in bytes to use for decryption + * bits size of key in bits + * aes AES structure to initialize + */ +int wolfSSL_AES_set_decrypt_key(const unsigned char *key, const int bits, + AES_KEY *aes) +{ + typedef char aes_test[sizeof(AES_KEY) >= sizeof(Aes) ? 1 : -1]; + (void)sizeof(aes_test); + + WOLFSSL_ENTER("wolfSSL_AES_set_decrypt_key"); + + if (key == NULL || aes == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return -1; + } + + XMEMSET(aes, 0, sizeof(AES_KEY)); + if (wc_AesSetKey((Aes*)aes, key, ((bits)/8), NULL, AES_DECRYPTION) != 0) { + WOLFSSL_MSG("Error in setting AES key"); + return -1; + } + return 0; +} + + +#ifdef HAVE_AES_ECB +/* Encrypt/decrypt a 16 byte block of data using the key passed in. + * + * in buffer to encrypt/decrypt + * out buffer to hold result of encryption/decryption + * key AES structure to use with encryption/decryption + * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption + */ +void wolfSSL_AES_ecb_encrypt(const unsigned char *in, unsigned char* out, + AES_KEY *key, const int enc) +{ + Aes* aes; + + WOLFSSL_ENTER("wolfSSL_AES_ecb_encrypt"); + + if (key == NULL || in == NULL || out == NULL) { + WOLFSSL_MSG("Error, Null argument passed in"); + return; + } + + aes = (Aes*)key; + if (enc == AES_ENCRYPT) { + if (wc_AesEcbEncrypt(aes, out, in, AES_BLOCK_SIZE) != 0) { + WOLFSSL_MSG("Error with AES CBC encrypt"); + } + } + else { + #ifdef HAVE_AES_DECRYPT + if (wc_AesEcbDecrypt(aes, out, in, AES_BLOCK_SIZE) != 0) { + WOLFSSL_MSG("Error with AES CBC decrypt"); + } + #else + WOLFSSL_MSG("AES decryption not compiled in"); + #endif + } +} +#endif /* HAVE_AES_ECB */ + +#ifdef HAVE_AES_CBC +/* Encrypt data using key and iv passed in. iv gets updated to most recent iv + * state after encryption/decryption. + * + * in buffer to encrypt/decrypt + * out buffer to hold result of encryption/decryption + * len length of input buffer + * key AES structure to use with encryption/decryption + * iv iv to use with operation + * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption + */ +void wolfSSL_AES_cbc_encrypt(const unsigned char *in, unsigned char* out, + size_t len, AES_KEY *key, unsigned char* iv, const int enc) +{ + Aes* aes; + + WOLFSSL_ENTER("wolfSSL_AES_cbc_encrypt"); + + if (key == NULL || in == NULL || out == NULL || iv == NULL || len == 0) { + WOLFSSL_MSG("Error, Null argument passed in"); + return; + } + + aes = (Aes*)key; + if (wc_AesSetIV(aes, (const byte*)iv) != 0) { + WOLFSSL_MSG("Error with setting iv"); + return; + } + + if (enc == AES_ENCRYPT) { + if (wc_AesCbcEncrypt(aes, out, in, (word32)len) != 0) { + WOLFSSL_MSG("Error with AES CBC encrypt"); + } + } + else { + if (wc_AesCbcDecrypt(aes, out, in, (word32)len) != 0) { + WOLFSSL_MSG("Error with AES CBC decrypt"); + } + } + + /* to be compatible copy iv to iv buffer after completing operation */ + XMEMCPY(iv, (byte*)(aes->reg), AES_BLOCK_SIZE); +} +#endif /* HAVE_AES_CBC */ + + +/* Encrypt data using CFB mode with key and iv passed in. iv gets updated to + * most recent iv state after encryption/decryption. + * + * in buffer to encrypt/decrypt + * out buffer to hold result of encryption/decryption + * len length of input buffer + * key AES structure to use with encryption/decryption + * iv iv to use with operation + * num contains the amount of block used + * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption + */ +void wolfSSL_AES_cfb128_encrypt(const unsigned char *in, unsigned char* out, + size_t len, AES_KEY *key, unsigned char* iv, int* num, + const int enc) +{ +#ifndef WOLFSSL_AES_CFB + WOLFSSL_MSG("CFB mode not enabled please use macro WOLFSSL_AES_CFB"); + (void)in; + (void)out; + (void)len; + (void)key; + (void)iv; + (void)num; + (void)enc; + + return; +#else + Aes* aes; + + WOLFSSL_ENTER("wolfSSL_AES_cbc_encrypt"); + if (key == NULL || in == NULL || out == NULL || iv == NULL) { + WOLFSSL_MSG("Error, Null argument passed in"); + return; + } + + aes = (Aes*)key; + if (wc_AesSetIV(aes, (const byte*)iv) != 0) { + WOLFSSL_MSG("Error with setting iv"); + return; + } + + if (enc == AES_ENCRYPT) { + if (wc_AesCfbEncrypt(aes, out, in, (word32)len) != 0) { + WOLFSSL_MSG("Error with AES CBC encrypt"); + } + } + else { + if (wc_AesCfbDecrypt(aes, out, in, (word32)len) != 0) { + WOLFSSL_MSG("Error with AES CBC decrypt"); + } + } + + /* to be compatible copy iv to iv buffer after completing operation */ + XMEMCPY(iv, (byte*)(aes->reg), AES_BLOCK_SIZE); + + /* store number of left over bytes to num */ + *num = (aes->left)? AES_BLOCK_SIZE - aes->left : 0; +#endif /* WOLFSSL_AES_CFB */ +} +#endif /* NO_AES */ + +#ifndef NO_FILESYSTEM + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wformat-nonliteral" + #endif +#endif + +#if !defined(NO_FILESYSTEM) && defined (OPENSSL_EXTRA) +/* returns amount printed on success, negative in fail case */ +int wolfSSL_BIO_vprintf(WOLFSSL_BIO* bio, const char* format, va_list args) +{ + int ret = -1; + + if (bio == NULL) + return WOLFSSL_FATAL_ERROR; + + switch (bio->type) { + case WOLFSSL_BIO_FILE: + if (bio->ptr == NULL) { + va_end(args); + return -1; + } + ret = vfprintf((XFILE)bio->ptr, format, args); + break; + + case WOLFSSL_BIO_MEMORY: + #if defined(OPENSSL_EXTRA) && !defined(_WIN32) + case WOLFSSL_BIO_SSL: + { + int count; + char* pt = NULL; + va_list copy; + + va_copy(copy, args); + count = vsnprintf(NULL, 0, format, args); + if (count >= 0) + { + pt = (char*)XMALLOC(count + 1, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (pt != NULL) + { + count = vsnprintf(pt, count + 1, format, copy); + if (count >= 0) + { + ret = wolfSSL_BIO_write(bio, pt, count); + } + XFREE(pt, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + } + va_end(copy); + } + break; + #endif + + default: + WOLFSSL_MSG("Unsupported WOLFSSL_BIO type for wolfSSL_BIO_printf"); + break; + } + + return ret; +} + +/* returns amount printed on success, negative in fail case */ +int wolfSSL_BIO_printf(WOLFSSL_BIO* bio, const char* format, ...) +{ + int ret; + va_list args; + va_start(args, format); + + ret = wolfSSL_BIO_vprintf(bio, format, args); + + va_end(args); + + return ret; +} + +#endif /* !defined(NO_FILESYSTEM) && defined (OPENSSL_EXTRA) */ + +#if !defined(NO_FILESYSTEM) && defined(__clang__) +#pragma clang diagnostic pop +#endif + +#undef LINE_LEN +#define LINE_LEN 16 +int wolfSSL_BIO_dump(WOLFSSL_BIO *bio, const char *buf, int length) +{ + int ret = 0; + + if (bio == NULL) + return 0; + +#ifndef NO_FILESYSTEM + if (bio->type == WOLFSSL_BIO_FILE) { + int i; + char line[80]; + + if (!buf) { + return fputs("\tNULL", (XFILE)bio->ptr); + } + + sprintf(line, "\t"); + for (i = 0; i < LINE_LEN; i++) { + if (i < length) + sprintf(line + 1 + i * 3,"%02x ", buf[i]); + else + sprintf(line + 1 + i * 3, " "); + } + sprintf(line + 1 + LINE_LEN * 3, "| "); + for (i = 0; i < LINE_LEN; i++) { + if (i < length) { + sprintf(line + 3 + LINE_LEN * 3 + i, + "%c", 31 < buf[i] && buf[i] < 127 ? buf[i] : '.'); + } + } + ret += fputs(line, (XFILE)bio->ptr); + + if (length > LINE_LEN) + ret += wolfSSL_BIO_dump(bio, buf + LINE_LEN, length - LINE_LEN); + } +#else + (void)buf; + (void)length; +#endif + + return ret; +} + +#ifndef NO_ASN_TIME +int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a) +{ + WOLFSSL_ENTER("ASN1_UTCTIME_print"); + if (bio == NULL || a == NULL) { + return WOLFSSL_FAILURE; + } + if (a->type != ASN_UTC_TIME) { + WOLFSSL_MSG("Error, not UTC_TIME"); + return WOLFSSL_FAILURE; + } + + return wolfSSL_ASN1_TIME_print(bio, a); +} + +/* Checks the ASN1 syntax of "a" + * returns WOLFSSL_SUCCESS (1) if correct otherwise WOLFSSL_FAILURE (0) */ +int wolfSSL_ASN1_TIME_check(const WOLFSSL_ASN1_TIME* a) +{ + char buf[MAX_TIME_STRING_SZ]; + + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_check"); + + /* if can parse the WOLFSSL_ASN1_TIME passed in then consider syntax good */ + if (wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)a, buf, + MAX_TIME_STRING_SZ) == NULL) { + return WOLFSSL_FAILURE; + } + return WOLFSSL_SUCCESS; +} +#endif /* !NO_ASN_TIME */ + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_ASN1_TIME_diff(int *pday, int *psec, + const WOLFSSL_ASN1_TIME *from, const WOLFSSL_ASN1_TIME *to) +{ + WOLFSSL_STUB("wolfSSL_ASN1_TIME_diff"); + (void)pday; + (void)psec; + (void)from; + (void)to; + return 0; +} + +WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *s, time_t t) +{ + WOLFSSL_STUB("wolfSSL_ASN1_TIME_set"); + (void)s; + (void)t; + return s; +} +#endif /* !NO_WOLFSSL_STUB */ + +/* Return the month as a string. + * + * n The number of the month as a two characters (1 based). + * returns the month as a string. + */ +static WC_INLINE const char* MonthStr(const char* n) +{ + static const char monthStr[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + return monthStr[(n[0] - '0') * 10 + (n[1] - '0') - 1]; +} + +int wolfSSL_ASN1_GENERALIZEDTIME_print(WOLFSSL_BIO* bio, + const WOLFSSL_ASN1_GENERALIZEDTIME* asnTime) +{ + const char* p; + WOLFSSL_ENTER("wolfSSL_ASN1_GENERALIZEDTIME_print"); + + if (bio == NULL || asnTime == NULL) + return BAD_FUNC_ARG; + + if (asnTime->type != ASN_GENERALIZED_TIME) { + WOLFSSL_MSG("Error, not GENERALIZED_TIME"); + return WOLFSSL_FAILURE; + } + p = (const char *)(asnTime->data); + /* GetTimeString not always available. */ + wolfSSL_BIO_write(bio, MonthStr(p + 4), 3); + wolfSSL_BIO_write(bio, " ", 1); + /* Day */ + wolfSSL_BIO_write(bio, p + 6, 2); + wolfSSL_BIO_write(bio, " ", 1); + /* Hour */ + wolfSSL_BIO_write(bio, p + 8, 2); + wolfSSL_BIO_write(bio, ":", 1); + /* Min */ + wolfSSL_BIO_write(bio, p + 10, 2); + wolfSSL_BIO_write(bio, ":", 1); + /* Secs */ + wolfSSL_BIO_write(bio, p + 12, 2); + wolfSSL_BIO_write(bio, " ", 1); + wolfSSL_BIO_write(bio, p, 4); + + return 0; +} + +void wolfSSL_ASN1_GENERALIZEDTIME_free(WOLFSSL_ASN1_TIME* asn1Time) +{ + WOLFSSL_ENTER("wolfSSL_ASN1_GENERALIZEDTIME_free"); + if (asn1Time == NULL) + return; + XMEMSET(asn1Time->data, 0, sizeof(asn1Time->data)); +} + +int wolfSSL_sk_num(WOLFSSL_STACK* sk) +{ + WOLFSSL_ENTER("wolfSSL_sk_num"); + if (sk == NULL) + return 0; + return (int)sk->num; +} + +void* wolfSSL_sk_value(WOLFSSL_STACK* sk, int i) +{ +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + int offset = i; +#endif + WOLFSSL_ENTER("wolfSSL_sk_value"); + + for (; sk != NULL && i > 0; i--) + sk = sk->next; + if (sk == NULL) + return NULL; + + switch (sk->type) { + case STACK_TYPE_X509: + return (void*)sk->data.x509; + case STACK_TYPE_CIPHER: + #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + sk->data.cipher.offset = offset; + #endif + return (void*)&sk->data.cipher; + case STACK_TYPE_GEN_NAME: + return (void*)sk->data.gn; + case STACK_TYPE_ACCESS_DESCRIPTION: + return (void*)sk->data.access; + case STACK_TYPE_OBJ: + return (void*)sk->data.obj; + case STACK_TYPE_X509_EXT: + return (void*)sk->data.ext; + case STACK_TYPE_CONF_VALUE: + return (void*)sk->data.conf->value; + case STACK_TYPE_NULL: + default: + return (void*)sk->data.generic; + } +} + +/* Free the structure for ASN1_OBJECT stack */ +void wolfSSL_sk_free(WOLFSSL_STACK* sk) +{ + WOLFSSL_ENTER("wolfSSL_sk_free"); + + if (sk == NULL) { + WOLFSSL_MSG("Error, BAD_FUNC_ARG"); + return; + } + + switch (sk->type) { + case STACK_TYPE_X509: + wolfSSL_sk_X509_free(sk); + break; + #if defined(OPENSSL_ALL) + case STACK_TYPE_CIPHER: + wolfSSL_sk_CIPHER_free(sk); + break; + #endif + case STACK_TYPE_GEN_NAME: + wolfSSL_sk_GENERAL_NAME_free(sk); + break; + #if defined(OPENSSL_ALL) || defined (WOLFSSL_QT) + case STACK_TYPE_ACCESS_DESCRIPTION: + wolfSSL_sk_ACCESS_DESCRIPTION_free(sk); + break; + #endif + case STACK_TYPE_OBJ: + wolfSSL_sk_ASN1_OBJECT_free(sk); + break; + #ifdef OPENSSL_ALL + case STACK_TYPE_X509_INFO: + wolfSSL_sk_X509_INFO_free(sk); + break; + case STACK_TYPE_X509_NAME: + wolfSSL_sk_X509_NAME_free(sk); + break; + case STACK_TYPE_CONF_VALUE: + wolfSSL_sk_CONF_VALUE_free(sk); + break; + #endif + case STACK_TYPE_NULL: + default: + wolfSSL_sk_GENERIC_free(sk); + } +} +/* Frees each node in the stack and frees the stack. + * Does not free any internal members of the stack nodes. + */ +void wolfSSL_sk_GENERIC_pop_free(WOLFSSL_STACK* sk, + void (*f) (void*)) +{ + WOLFSSL_STACK* node; + WOLFSSL_STACK* tmp; + WOLFSSL_ENTER("wolfSSL_sk_GENERIC_pop_free"); + + if (sk == NULL) + return; + + /* parse through stack freeing each node */ + node = sk->next; + while (node) { + tmp = node; + node = node->next; + if (f) + f(tmp->data.generic); + tmp->data.generic = NULL; + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + } + + /* free head of stack */ + XFREE(sk, NULL, DYNAMIC_TYPE_ASN1); +} + +/* return 1 on success 0 on fail */ +int wolfSSL_sk_GENERIC_push(WOLFSSL_STACK* sk, void* generic) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_GENERIC_push"); + + if (sk == NULL || generic == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.generic == NULL) { + sk->data.generic = generic; + sk->num += 1; + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK),NULL,DYNAMIC_TYPE_SSL); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new node onto head of stack */ + node->type = sk->type; + node->data.generic = sk->data.generic; + node->next = sk->next; + sk->next = node; + sk->data.generic = generic; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} +void wolfSSL_sk_GENERIC_free(WOLFSSL_STACK* sk) +{ + wolfSSL_sk_GENERIC_pop_free(sk, NULL); +} + + +/* Free all nodes in a stack */ +void wolfSSL_sk_pop_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, + wolfSSL_sk_freefunc func) +{ + WOLFSSL_ENTER("wolfSSL_sk_pop_free"); + + if (sk == NULL) { + WOLFSSL_MSG("Error, BAD_FUNC_ARG"); + return; + } + + switch(sk->type) { + #if defined(OPENSSL_ALL) || defined (WOLFSSL_QT) + case STACK_TYPE_ACCESS_DESCRIPTION: + wolfSSL_sk_ACCESS_DESCRIPTION_pop_free(sk, + wolfSSL_ACCESS_DESCRIPTION_free); + break; + #endif + case STACK_TYPE_X509: + wolfSSL_sk_X509_pop_free(sk,(void (*)(WOLFSSL_X509*))func); + break; + case STACK_TYPE_OBJ: + wolfSSL_sk_ASN1_OBJECT_pop_free(sk, + (void (*)(WOLFSSL_ASN1_OBJECT*))func); + break; + case STACK_TYPE_GEN_NAME: + wolfSSL_sk_GENERAL_NAME_pop_free(sk, + (void (*)(WOLFSSL_GENERAL_NAME*))func); + break; + #ifdef OPENSSL_ALL + case STACK_TYPE_X509_NAME: + wolfSSL_sk_X509_NAME_pop_free(sk, + (void (*)(WOLFSSL_X509_NAME*))func); + break; + case STACK_TYPE_X509_EXT: + wolfSSL_sk_X509_EXTENSION_pop_free(sk, + (void (*)(WOLFSSL_X509_EXTENSION*))func); + break; + #endif + #if defined(OPENSSL_ALL) + case STACK_TYPE_X509_INFO: + wolfSSL_sk_X509_INFO_pop_free(sk, + (void (*)(WOLFSSL_X509_INFO*))func); + break; + #endif + default: + wolfSSL_sk_GENERIC_pop_free(sk, + (void (*)(void*))func); + break; + } +} + +#if defined(OPENSSL_ALL) +/* Free the structure for WOLFSSL_CONF_VALUE stack + * + * sk stack to free nodes in + */ +void wolfSSL_sk_CONF_VALUE_free(WOLF_STACK_OF(WOLFSSL_CONF_VALUE)* sk) +{ + WOLFSSL_STACK* node; + WOLFSSL_STACK* tmp; + WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_free"); + + if (sk == NULL) + return; + + /* parse through stack freeing each node */ + node = sk->next; + while (node) { + tmp = node; + node = node->next; + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + } + + /* free head of stack */ + XFREE(sk, NULL, DYNAMIC_TYPE_ASN1); +} +#endif + +/* Creates and returns a new null stack. */ +WOLFSSL_STACK* wolfSSL_sk_new_null(void) +{ + WOLFSSL_STACK* sk; + WOLFSSL_ENTER("wolfSSL_sk_new_null"); + + sk = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_OPENSSL); + if (sk == NULL) { + WOLFSSL_MSG("WOLFSSL_STACK memory error"); + return NULL; + } + + XMEMSET(sk, 0, sizeof(WOLFSSL_STACK)); + sk->type = STACK_TYPE_NULL; + + return sk; +} + +/* frees the wolfSSL_BASIC_CONSTRAINTS object */ +void wolfSSL_BASIC_CONSTRAINTS_free(WOLFSSL_BASIC_CONSTRAINTS *bc) +{ + WOLFSSL_ENTER("wolfSSL_BASIC_CONSTRAINTS_free"); + if (bc == NULL) { + WOLFSSL_MSG("Argument is NULL"); + return; + } + if (bc->pathlen) { + wolfSSL_ASN1_INTEGER_free(bc->pathlen); + } + XFREE(bc, NULL, DYNAMIC_TYPE_OPENSSL); +} + +/* frees the wolfSSL_AUTHORITY_KEYID object */ +void wolfSSL_AUTHORITY_KEYID_free(WOLFSSL_AUTHORITY_KEYID *id) +{ + WOLFSSL_ENTER("wolfSSL_AUTHORITY_KEYID_free"); + if(id == NULL) { + WOLFSSL_MSG("Argument is NULL"); + return; + } + if (id->keyid) { + wolfSSL_ASN1_STRING_free(id->keyid); + } + if (id->issuer) { + wolfSSL_ASN1_OBJECT_free(id->issuer); + } + if (id->serial) { + wolfSSL_ASN1_INTEGER_free(id->serial); + } + XFREE(id, NULL, DYNAMIC_TYPE_OPENSSL); +} + +int wolfSSL_sk_SSL_COMP_num(WOLF_STACK_OF(WOLFSSL_COMP)* sk) +{ + if (sk == NULL) + return 0; + return (int)sk->num; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE) +/* stunnel 4.28 needs + * + * Callback that is called if a session tries to resume but could not find + * the session to resume it. + */ +void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx, + WOLFSSL_SESSION*(*f)(WOLFSSL*, unsigned char*, int, int*)) +{ + if (ctx == NULL) + return; + +#ifdef HAVE_EXT_CACHE + ctx->get_sess_cb = f; +#else + (void)f; +#endif +} + +void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx, + int (*f)(WOLFSSL*, WOLFSSL_SESSION*)) +{ + if (ctx == NULL) + return; + +#ifdef HAVE_EXT_CACHE + ctx->new_sess_cb = f; +#else + (void)f; +#endif +} + +void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*, + WOLFSSL_SESSION*)) +{ + if (ctx == NULL) + return; + +#ifdef HAVE_EXT_CACHE + ctx->rem_sess_cb = f; +#else + (void)f; +#endif +} +#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */ + +#ifdef OPENSSL_EXTRA + +/* + * + * Note: It is expected that the importing and exporting function have been + * built with the same settings. For example if session tickets was + * enabled with the wolfSSL library exporting a session then it is + * expected to be turned on with the wolfSSL library importing the session. + */ +int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) +{ + int size = 0; +#ifdef HAVE_EXT_CACHE + int idx = 0; +#ifdef SESSION_CERTS + int i; +#endif + unsigned char *data; + + if (sess == NULL) { + return BAD_FUNC_ARG; + } + + /* bornOn | timeout | sessionID len | sessionID | masterSecret | haveEMS */ + size += OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN + sess->sessionIDSz + + SECRET_LEN + OPAQUE8_LEN; +#ifdef SESSION_CERTS + /* Peer chain */ + size += OPAQUE8_LEN; + for (i = 0; i < sess->chain.count; i++) + size += OPAQUE16_LEN + sess->chain.certs[i].length; +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + /* Protocol version */ + size += OPAQUE16_LEN; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + /* cipher suite */ + size += OPAQUE16_LEN; +#endif +#ifndef NO_CLIENT_CACHE + /* ServerID len | ServerID */ + size += OPAQUE16_LEN + sess->idLen; +#endif +#ifdef OPENSSL_EXTRA + /* session context ID len | session context ID */ + size += OPAQUE8_LEN + sess->sessionCtxSz; +#endif +#ifdef WOLFSSL_TLS13 + /* namedGroup */ + size += OPAQUE16_LEN; +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13 + /* ticketSeen | ticketAdd */ + size += OPAQUE32_LEN + OPAQUE32_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* ticketNonce */ + size += OPAQUE8_LEN + sess->ticketNonce.len; +#endif +#endif +#ifdef WOLFSSL_EARLY_DATA + size += OPAQUE32_LEN; +#endif +#endif +#ifdef HAVE_SESSION_TICKET + /* ticket len | ticket */ + size += OPAQUE16_LEN + sess->ticketLen; +#endif + + if (p != NULL) { + if (*p == NULL) + *p = (unsigned char*)XMALLOC(size, NULL, DYNAMIC_TYPE_OPENSSL); + if (*p == NULL) + return 0; + data = *p; + + c32toa(sess->bornOn, data + idx); idx += OPAQUE32_LEN; + c32toa(sess->timeout, data + idx); idx += OPAQUE32_LEN; + data[idx++] = sess->sessionIDSz; + XMEMCPY(data + idx, sess->sessionID, sess->sessionIDSz); + idx += sess->sessionIDSz; + XMEMCPY(data + idx, sess->masterSecret, SECRET_LEN); idx += SECRET_LEN; + data[idx++] = (byte)sess->haveEMS; +#ifdef SESSION_CERTS + data[idx++] = (byte)sess->chain.count; + for (i = 0; i < sess->chain.count; i++) { + c16toa((word16)sess->chain.certs[i].length, data + idx); + idx += OPAQUE16_LEN; + XMEMCPY(data + idx, sess->chain.certs[i].buffer, + sess->chain.certs[i].length); + idx += sess->chain.certs[i].length; + } +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + data[idx++] = sess->version.major; + data[idx++] = sess->version.minor; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + data[idx++] = sess->cipherSuite0; + data[idx++] = sess->cipherSuite; +#endif +#ifndef NO_CLIENT_CACHE + c16toa(sess->idLen, data + idx); idx += OPAQUE16_LEN; + XMEMCPY(data + idx, sess->serverID, sess->idLen); + idx += sess->idLen; +#endif +#ifdef OPENSSL_EXTRA + data[idx++] = sess->sessionCtxSz; + XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz); + idx += sess->sessionCtxSz; +#endif +#ifdef WOLFSSL_TLS13 + c16toa(sess->namedGroup, data + idx); + idx += OPAQUE16_LEN; +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13 + c32toa(sess->ticketSeen, data + idx); + idx += OPAQUE32_LEN; + c32toa(sess->ticketAdd, data + idx); + idx += OPAQUE32_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + data[idx++] = sess->ticketNonce.len; + XMEMCPY(data + idx, sess->ticketNonce.data, sess->ticketNonce.len); + idx += sess->ticketNonce.len; +#endif +#endif +#ifdef WOLFSSL_EARLY_DATA + c32toa(sess->maxEarlyDataSz, data + idx); + idx += OPAQUE32_LEN; +#endif +#endif +#ifdef HAVE_SESSION_TICKET + c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN; + XMEMCPY(data + idx, sess->ticket, sess->ticketLen); + idx += sess->ticketLen; +#endif + } +#endif + + (void)sess; + (void)p; +#ifdef HAVE_EXT_CACHE + (void)idx; +#endif + + return size; +} + + +/* TODO: no function to free new session. + * + * Note: It is expected that the importing and exporting function have been + * built with the same settings. For example if session tickets was + * enabled with the wolfSSL library exporting a session then it is + * expected to be turned on with the wolfSSL library importing the session. + */ +WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, + const unsigned char** p, long i) +{ + WOLFSSL_SESSION* s = NULL; + int ret = 0; +#if defined(HAVE_EXT_CACHE) + int idx; + byte* data; +#ifdef SESSION_CERTS + int j; + word16 length; +#endif +#endif + + (void)p; + (void)i; + (void)ret; + + if (sess != NULL) + s = *sess; + +#ifdef HAVE_EXT_CACHE + if (p == NULL || *p == NULL) + return NULL; + + if (s == NULL) { + s = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), NULL, + DYNAMIC_TYPE_OPENSSL); + if (s == NULL) + return NULL; + XMEMSET(s, 0, sizeof(WOLFSSL_SESSION)); + s->isAlloced = 1; +#ifdef HAVE_SESSION_TICKET + s->isDynamic = 0; +#endif + } + + idx = 0; + data = (byte*)*p; + + /* bornOn | timeout | sessionID len */ + if (i < OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato32(data + idx, &s->bornOn); idx += OPAQUE32_LEN; + ato32(data + idx, &s->timeout); idx += OPAQUE32_LEN; + s->sessionIDSz = data[idx++]; + + /* sessionID | secret | haveEMS */ + if (i - idx < s->sessionIDSz + SECRET_LEN + OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->sessionID, data + idx, s->sessionIDSz); + idx += s->sessionIDSz; + XMEMCPY(s->masterSecret, data + idx, SECRET_LEN); idx += SECRET_LEN; + s->haveEMS = data[idx++]; + +#ifdef SESSION_CERTS + /* Certificate chain */ + if (i - idx == 0) { + ret = BUFFER_ERROR; + goto end; + } + s->chain.count = data[idx++]; + for (j = 0; j < s->chain.count; j++) { + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &length); idx += OPAQUE16_LEN; + s->chain.certs[j].length = length; + if (i - idx < length) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->chain.certs[j].buffer, data + idx, length); + idx += length; + } +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + /* Protocol Version */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->version.major = data[idx++]; + s->version.minor = data[idx++]; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + /* Cipher suite */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->cipherSuite0 = data[idx++]; + s->cipherSuite = data[idx++]; +#endif +#ifndef NO_CLIENT_CACHE + /* ServerID len */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &s->idLen); idx += OPAQUE16_LEN; + + /* ServerID */ + if (i - idx < s->idLen) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->serverID, data + idx, s->idLen); idx += s->idLen; +#endif +#ifdef OPENSSL_EXTRA + /* byte for length of session context ID */ + if (i - idx < OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->sessionCtxSz = data[idx++]; + + /* app session context ID */ + if (i - idx < s->sessionCtxSz) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz; +#endif +#ifdef WOLFSSL_TLS13 + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &s->namedGroup); + idx += OPAQUE16_LEN; +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13 + if (i - idx < (OPAQUE32_LEN * 2)) { + ret = BUFFER_ERROR; + goto end; + } + ato32(data + idx, &s->ticketSeen); + idx += OPAQUE32_LEN; + ato32(data + idx, &s->ticketAdd); + idx += OPAQUE32_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (i - idx < OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->ticketNonce.len = data[idx++]; + + if (i - idx < s->ticketNonce.len) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len); + idx += s->ticketNonce.len; +#endif +#endif +#ifdef WOLFSSL_EARLY_DATA + if (i - idx < OPAQUE32_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato32(data + idx, &s->maxEarlyDataSz); + idx += OPAQUE32_LEN; +#endif +#endif +#ifdef HAVE_SESSION_TICKET + /* ticket len */ + if (i - idx < OPAQUE16_LEN) { + ret = BUFFER_ERROR; + goto end; + } + ato16(data + idx, &s->ticketLen); idx += OPAQUE16_LEN; + + /* Dispose of ol dynamic ticket and ensure space for new ticket. */ + if (s->isDynamic) + XFREE(s->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); + if (s->ticketLen <= SESSION_TICKET_LEN) + s->ticket = s->staticTicket; + else { + s->ticket = (byte*)XMALLOC(s->ticketLen, NULL, + DYNAMIC_TYPE_SESSION_TICK); + if (s->ticket == NULL) { + ret = MEMORY_ERROR; + goto end; + } + s->isDynamic = 1; + } + + /* ticket */ + if (i - idx < s->ticketLen) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen; +#endif + (void)idx; + + if (sess != NULL) + *sess = s; + + *p += idx; + +end: + if (ret != 0 && (sess == NULL || *sess != s)) + wolfSSL_SESSION_free(s); +#endif + return s; +} + + +long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess) +{ + long timeout = 0; + WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout"); + if (sess) + timeout = sess->timeout; + return timeout; +} + + +long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess) +{ + long bornOn = 0; + WOLFSSL_ENTER("wolfSSL_SESSION_get_time"); + if (sess) + bornOn = sess->bornOn; + return bornOn; +} + + +#endif /* OPENSSL_EXTRA */ + + +#ifdef KEEP_PEER_CERT +char* wolfSSL_X509_get_subjectCN(WOLFSSL_X509* x509) +{ + if (x509 == NULL) + return NULL; + + return x509->subjectCN; +} +#endif /* KEEP_PEER_CERT */ + +#ifdef OPENSSL_EXTRA + +#if defined(FORTRESS) && !defined(NO_FILESYSTEM) +int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname) +{ + int ret = WOLFSSL_FATAL_ERROR; + + WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file"); + if (ssl != NULL && fname != NULL) + { + #ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ + #else + byte staticBuffer[FILE_BUFFER_SIZE]; + #endif + byte* myBuffer = staticBuffer; + int dynamic = 0; + XFILE file; + long sz = 0; + WOLFSSL_CTX* ctx = ssl->ctx; + WOLFSSL_X509* peer_cert = &ssl->peerCert; + DerBuffer* fileDer = NULL; + + file = XFOPEN(fname, "rb"); + if (file == XBADFILE) + return WOLFSSL_BAD_FILE; + + if (XFSEEK(file, 0, XSEEK_END) != 0) { + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + sz = XFTELL(file); + XREWIND(file); + + if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) { + WOLFSSL_MSG("cmp_peer_cert_to_file size error"); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + + if (sz > (long)sizeof(staticBuffer)) { + WOLFSSL_MSG("Getting dynamic buffer"); + myBuffer = (byte*)XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); + dynamic = 1; + } + + if ((myBuffer != NULL) && + (sz > 0) && + (XFREAD(myBuffer, 1, sz, file) == (size_t)sz) && + (PemToDer(myBuffer, (long)sz, CERT_TYPE, + &fileDer, ctx->heap, NULL, NULL) == 0) && + (fileDer->length != 0) && + (fileDer->length == peer_cert->derCert->length) && + (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer, + fileDer->length) == 0)) + { + ret = 0; + } + + FreeDer(&fileDer); + + if (dynamic) + XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); + + XFCLOSE(file); + } + + return ret; +} +#endif +#endif /* OPENSSL_EXTRA */ +#endif /* !WOLFCRYPT_ONLY */ +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +const WOLFSSL_ObjectInfo wolfssl_object_info[] = { +#ifndef NO_CERTS + /* oidCertExtType */ + { NID_basic_constraints, BASIC_CA_OID, oidCertExtType, "basicConstraints", + "X509v3 Basic Constraints"}, + { NID_subject_alt_name, ALT_NAMES_OID, oidCertExtType, "subjectAltName", + "X509v3 Subject Alternative Name"}, + { CRL_DIST_OID, CRL_DIST_OID, oidCertExtType, "crlDistributionPoints", + "X509v3 CRL Distribution Points"}, + { NID_info_access, AUTH_INFO_OID, oidCertExtType, "authorityInfoAccess", + "Authority Information Access"}, + { NID_authority_key_identifier, AUTH_KEY_OID, oidCertExtType, + "authorityKeyIdentifier", "X509v3 Authority Key Identifier"}, + { NID_subject_key_identifier, SUBJ_KEY_OID, oidCertExtType, + "subjectKeyIdentifier", "X509v3 Subject Key Identifier"}, + { NID_key_usage, KEY_USAGE_OID, oidCertExtType, "keyUsage", + "X509v3 Key Usage"}, + { NID_inhibit_any_policy, INHIBIT_ANY_OID, oidCertExtType, + "inhibitAnyPolicy", "X509v3 Inhibit Any Policy"}, + { NID_ext_key_usage, KEY_USAGE_OID, oidCertExtType, + "extendedKeyUsage", "X509v3 Extended Key Usage"}, + { NID_name_constraints, NAME_CONS_OID, oidCertExtType, + "nameConstraints", "X509v3 Name Constraints"}, + { NID_certificate_policies, CERT_POLICY_OID, oidCertExtType, + "certificatePolicies", "X509v3 Certificate Policies"}, + + /* oidCertAuthInfoType */ + { AIA_OCSP_OID, AIA_OCSP_OID, oidCertAuthInfoType, "authorityInfoAccess", + "Authority Information Access"}, + { AIA_CA_ISSUER_OID, AIA_CA_ISSUER_OID, oidCertAuthInfoType, + "caIssuers", "CA Issuers"}, + + /* oidCertPolicyType */ + { NID_any_policy, CP_ANY_OID, oidCertPolicyType, "anyPolicy", + "X509v3 Any Policy"}, + + /* oidCertAltNameType */ + { NID_hw_name_oid, HW_NAME_OID, oidCertAltNameType, "Hardware name",""}, + + /* oidCertKeyUseType */ + { NID_anyExtendedKeyUsage, EKU_ANY_OID, oidCertKeyUseType, + "anyExtendedKeyUsage", "Any Extended Key Usage"}, + { EKU_SERVER_AUTH_OID, EKU_SERVER_AUTH_OID, oidCertKeyUseType, + "serverAuth", "TLS Web Server Authentication"}, + { EKU_CLIENT_AUTH_OID, EKU_CLIENT_AUTH_OID, oidCertKeyUseType, + "clientAuth", "TLS Web Client Authentication"}, + { EKU_OCSP_SIGN_OID, EKU_OCSP_SIGN_OID, oidCertKeyUseType, + "OCSPSigning", "OCSP Signing"}, + + /* oidCertNameType */ + { NID_commonName, NID_commonName, oidCertNameType, "CN", "commonName"}, + { NID_surname, NID_surname, oidCertNameType, "SN", "surname"}, + { NID_serialNumber, NID_serialNumber, oidCertNameType, "serialNumber", + "serialNumber"}, + { NID_countryName, NID_countryName, oidCertNameType, "C", "countryName"}, + { NID_localityName, NID_localityName, oidCertNameType, "L", "localityName"}, + { NID_stateOrProvinceName, NID_stateOrProvinceName, oidCertNameType, "ST", + "stateOrProvinceName"}, + { NID_organizationName, NID_organizationName, oidCertNameType, "O", + "organizationName"}, + { NID_organizationalUnitName, NID_organizationalUnitName, oidCertNameType, + "OU", "organizationalUnitName"}, + { NID_emailAddress, NID_emailAddress, oidCertNameType, "emailAddress", + "emailAddress"}, + { NID_domainComponent, NID_domainComponent, oidCertNameType, "DC", + "domainComponent"}, + { NID_businessCategory, NID_businessCategory, oidCertNameType, "businessCategory", + "businessCategory"}, + { NID_jurisdictionCountryName, NID_jurisdictionCountryName, oidCertNameType, "jurisdictionC", + "jurisdictionCountryName"}, + { NID_jurisdictionStateOrProvinceName, NID_jurisdictionStateOrProvinceName, + oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"}, +#endif +#ifdef OPENSSL_EXTRA /* OPENSSL_EXTRA_X509_SMALL only needs the above */ + /* oidHashType */ + #ifdef WOLFSSL_MD2 + { NID_md2, MD2h, oidHashType, "MD2", "md2"}, + #endif + #ifdef WOLFSSL_MD5 + { NID_md5, MD5h, oidHashType, "MD5", "md5"}, + #endif + #ifndef NO_SHA + { NID_sha1, SHAh, oidHashType, "SHA1", "sha1"}, + #endif + #ifdef WOLFSSL_SHA224 + { NID_sha224, SHA224h, oidHashType, "SHA224", "sha224"}, + #endif + #ifndef NO_SHA256 + { NID_sha256, SHA256h, oidHashType, "SHA256", "sha256"}, + #endif + #ifdef WOLFSSL_SHA384 + { NID_sha384, SHA384h, oidHashType, "SHA384", "sha384"}, + #endif + #ifdef WOLFSSL_SHA512 + { NID_sha512, SHA512h, oidHashType, "SHA512", "sha512"}, + #endif + + /* oidSigType */ + #ifndef NO_DSA + #ifndef NO_SHA + { CTC_SHAwDSA, CTC_SHAwDSA, oidSigType, "DSA-SHA1", "dsaWithSHA1"}, + #endif + #endif /* NO_DSA */ + #ifndef NO_RSA + #ifdef WOLFSSL_MD2 + { CTC_MD2wRSA, CTC_MD2wRSA, oidSigType, "RSA-MD2", + "md2WithRSAEncryption"}, + #endif + #ifndef NO_MD5 + { CTC_MD5wRSA, CTC_MD5wRSA, oidSigType, "RSA-MD5", + "md5WithRSAEncryption"}, + #endif + #ifndef NO_SHA + { CTC_SHAwRSA, CTC_SHAwRSA, oidSigType, "RSA-SHA1", + "sha1WithRSAEncryption"}, + #endif + #ifdef WOLFSSL_SHA224 + { CTC_SHA224wRSA, CTC_SHA224wRSA, oidSigType, "RSA-SHA224", + "sha224WithRSAEncryption"}, + #endif + #ifndef NO_SHA256 + { CTC_SHA256wRSA, CTC_SHA256wRSA, oidSigType, "RSA-SHA256", + "sha256WithRSAEncryption"}, + #endif + #ifdef WOLFSSL_SHA384 + { CTC_SHA384wRSA, CTC_SHA384wRSA, oidSigType, "RSA-SHA384", + "sha384WithRSAEncryption"}, + #endif + #ifdef WOLFSSL_SHA512 + { CTC_SHA512wRSA, CTC_SHA512wRSA, oidSigType, "RSA-SHA512", + "sha512WithRSAEncryption"}, + #endif + #endif /* NO_RSA */ + #ifdef HAVE_ECC + #ifndef NO_SHA + { CTC_SHAwECDSA, CTC_SHAwECDSA, oidSigType, "ecdsa-with-SHA1", "shaWithECDSA"}, + #endif + #ifdef WOLFSSL_SHA224 + { CTC_SHA224wECDSA, CTC_SHA224wECDSA, oidSigType, "ecdsa-with-SHA224","sha224WithECDSA"}, + #endif + #ifndef NO_SHA256 + { CTC_SHA256wECDSA, CTC_SHA256wECDSA, oidSigType, "ecdsa-with-SHA256","sha256WithECDSA"}, + #endif + #ifdef WOLFSSL_SHA384 + { CTC_SHA384wECDSA, CTC_SHA384wECDSA, oidSigType, "ecdsa-with-SHA384","sha384WithECDSA"}, + #endif + #ifdef WOLFSSL_SHA512 + { CTC_SHA512wECDSA, CTC_SHA512wECDSA, oidSigType, "ecdsa-with-SHA512","sha512WithECDSA"}, + #endif + #endif /* HAVE_ECC */ + + /* oidKeyType */ + #ifndef NO_DSA + { DSAk, DSAk, oidKeyType, "DSA", "dsaEncryption"}, + { NID_dsa, DSAk, oidKeyType, "DSA", "dsaEncryption"}, + #endif /* NO_DSA */ + #ifndef NO_RSA + { RSAk, RSAk, oidKeyType, "RSA", "rsaEncryption"}, + { NID_rsaEncryption, RSAk, oidKeyType, "RSA", "rsaEncryption"}, + #endif /* NO_RSA */ + #ifdef HAVE_NTRU + { NTRUk, NTRUk, oidKeyType, "NTRU", "ntruEncryption"}, + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + { ECDSAk, ECDSAk, oidKeyType, "ECDSA", "ecdsaEncryption"}, + { NID_X9_62_id_ecPublicKey, ECDSAk, oidKeyType, "id-ecPublicKey", + "id-ecPublicKey"}, + #endif /* HAVE_ECC */ + #ifndef NO_DH + { NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", "dhKeyAgreement"}, + #endif + + /* oidCurveType */ + #ifdef HAVE_ECC + { NID_X9_62_prime192v1, ECC_SECP192R1_OID, oidCurveType, "prime192v1", "prime192v1"}, + { NID_X9_62_prime192v2, ECC_PRIME192V2_OID, oidCurveType, "prime192v2", "prime192v2"}, + { NID_X9_62_prime192v3, ECC_PRIME192V3_OID, oidCurveType, "prime192v3", "prime192v3"}, + + { NID_X9_62_prime239v1, ECC_PRIME239V1_OID, oidCurveType, "prime239v1", "prime239v1"}, + { NID_X9_62_prime239v2, ECC_PRIME239V2_OID, oidCurveType, "prime239v2", "prime239v2"}, + { NID_X9_62_prime239v3, ECC_PRIME239V3_OID, oidCurveType, "prime239v3", "prime239v3"}, + + { NID_X9_62_prime256v1, ECC_SECP256R1_OID, oidCurveType, "prime256v1", "prime256v1"}, + + { NID_secp112r1, ECC_SECP112R1_OID, oidCurveType, "secp112r1", "secp112r1"}, + { NID_secp112r2, ECC_SECP112R2_OID, oidCurveType, "secp112r2", "secp112r2"}, + + { NID_secp128r1, ECC_SECP128R1_OID, oidCurveType, "secp128r1", "secp128r1"}, + { NID_secp128r2, ECC_SECP128R2_OID, oidCurveType, "secp128r2", "secp128r2"}, + + { NID_secp160r1, ECC_SECP160R1_OID, oidCurveType, "secp160r1", "secp160r1"}, + { NID_secp160r2, ECC_SECP160R2_OID, oidCurveType, "secp160r2", "secp160r2"}, + + { NID_secp224r1, ECC_SECP224R1_OID, oidCurveType, "secp224r1", "secp224r1"}, + { NID_secp384r1, ECC_SECP384R1_OID, oidCurveType, "secp384r1", "secp384r1"}, + { NID_secp521r1, ECC_SECP521R1_OID, oidCurveType, "secp521r1", "secp521r1"}, + + { NID_secp160k1, ECC_SECP160K1_OID, oidCurveType, "secp160k1", "secp160k1"}, + { NID_secp192k1, ECC_SECP192K1_OID, oidCurveType, "secp192k1", "secp192k1"}, + { NID_secp224k1, ECC_SECP224K1_OID, oidCurveType, "secp224k1", "secp224k1"}, + { NID_secp256k1, ECC_SECP256K1_OID, oidCurveType, "secp256k1", "secp256k1"}, + + { NID_brainpoolP160r1, ECC_BRAINPOOLP160R1_OID, oidCurveType, "brainpoolP160r1", "brainpoolP160r1"}, + { NID_brainpoolP192r1, ECC_BRAINPOOLP192R1_OID, oidCurveType, "brainpoolP192r1", "brainpoolP192r1"}, + { NID_brainpoolP224r1, ECC_BRAINPOOLP224R1_OID, oidCurveType, "brainpoolP224r1", "brainpoolP224r1"}, + { NID_brainpoolP256r1, ECC_BRAINPOOLP256R1_OID, oidCurveType, "brainpoolP256r1", "brainpoolP256r1"}, + { NID_brainpoolP320r1, ECC_BRAINPOOLP320R1_OID, oidCurveType, "brainpoolP320r1", "brainpoolP320r1"}, + { NID_brainpoolP384r1, ECC_BRAINPOOLP384R1_OID, oidCurveType, "brainpoolP384r1", "brainpoolP384r1"}, + { NID_brainpoolP512r1, ECC_BRAINPOOLP512R1_OID, oidCurveType, "brainpoolP512r1", "brainpoolP512r1"}, + #endif /* HAVE_ECC */ + + /* oidBlkType */ + #ifdef WOLFSSL_AES_128 + { AES128CBCb, AES128CBCb, oidBlkType, "AES-128-CBC", "aes-128-cbc"}, + #endif + #ifdef WOLFSSL_AES_192 + { AES192CBCb, AES192CBCb, oidBlkType, "AES-192-CBC", "aes-192-cbc"}, + #endif + #ifdef WOLFSSL_AES_256 + { AES256CBCb, AES256CBCb, oidBlkType, "AES-256-CBC", "aes-256-cbc"}, + #endif + #ifndef NO_DES3 + { NID_des, DESb, oidBlkType, "DES-CBC", "des-cbc"}, + { NID_des3, DES3b, oidBlkType, "DES-EDE3-CBC", "des-ede3-cbc"}, + #endif /* !NO_DES3 */ + + /* oidOcspType */ + #ifdef HAVE_OCSP + { NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, "basicOCSPResponse", + "Basic OCSP Response"}, + { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "Nonce", + "OCSP Nonce"}, + #endif /* HAVE_OCSP */ + + #ifndef NO_PWDBASED + /* oidKdfType */ + { PBKDF2_OID, PBKDF2_OID, oidKdfType, "PBKDFv2", "PBKDF2"}, + + /* oidPBEType */ + { PBE_SHA1_RC4_128, PBE_SHA1_RC4_128, oidPBEType, + "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4"}, + { PBE_SHA1_DES, PBE_SHA1_DES, oidPBEType, "PBE-SHA1-DES", + "pbeWithSHA1AndDES-CBC"}, + { PBE_SHA1_DES3, PBE_SHA1_DES3, oidPBEType, "PBE-SHA1-3DES", + "pbeWithSHA1And3-KeyTripleDES-CBC"}, + #endif + + /* oidKeyWrapType */ + #ifdef WOLFSSL_AES_128 + { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap", "aes128-wrap"}, + #endif + #ifdef WOLFSSL_AES_192 + { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap", "aes192-wrap"}, + #endif + #ifdef WOLFSSL_AES_256 + { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap", "aes256-wrap"}, + #endif + + #ifndef NO_PKCS7 + #ifndef NO_DH + /* oidCmsKeyAgreeType */ + #ifndef NO_SHA + { dhSinglePass_stdDH_sha1kdf_scheme, dhSinglePass_stdDH_sha1kdf_scheme, + oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha1kdf-scheme", "dhSinglePass-stdDH-sha1kdf-scheme"}, + #endif + #ifdef WOLFSSL_SHA224 + { dhSinglePass_stdDH_sha224kdf_scheme, + dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha224kdf-scheme", "dhSinglePass-stdDH-sha224kdf-scheme"}, + #endif + #ifndef NO_SHA256 + { dhSinglePass_stdDH_sha256kdf_scheme, + dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha256kdf-scheme", "dhSinglePass-stdDH-sha256kdf-scheme"}, + #endif + #ifdef WOLFSSL_SHA384 + { dhSinglePass_stdDH_sha384kdf_scheme, + dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha384kdf-scheme", "dhSinglePass-stdDH-sha384kdf-scheme"}, + #endif + #ifdef WOLFSSL_SHA512 + { dhSinglePass_stdDH_sha512kdf_scheme, + dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha512kdf-scheme", "dhSinglePass-stdDH-sha512kdf-scheme"}, + #endif + #endif + #endif + #if defined(WOLFSSL_APACHE_HTTPD) + /* "1.3.6.1.5.5.7.8.7" */ + { NID_id_on_dnsSRV, NID_id_on_dnsSRV, oidCertNameType, + WOLFSSL_SN_DNS_SRV, WOLFSSL_LN_DNS_SRV }, + + /* "1.3.6.1.4.1.311.20.2.3" */ + { NID_ms_upn, WOLFSSL_MS_UPN_SUM, oidCertExtType, WOLFSSL_SN_MS_UPN, + WOLFSSL_LN_MS_UPN }, + + /* "1.3.6.1.5.5.7.1.24" */ + { NID_tlsfeature, WOLFSSL_TLS_FEATURE_SUM, oidTlsExtType, + WOLFSSL_SN_TLS_FEATURE, WOLFSSL_LN_TLS_FEATURE }, + #endif +#endif /* OPENSSL_EXTRA */ +}; + +#define WOLFSSL_OBJECT_INFO_SZ \ + (sizeof(wolfssl_object_info) / sizeof(*wolfssl_object_info)) +const size_t wolfssl_object_info_sz = WOLFSSL_OBJECT_INFO_SZ; +#endif +#if defined(OPENSSL_EXTRA) || \ + (defined(OPENSSL_EXTRA_X509_SMALL) && !defined(NO_RSA)) +static WC_RNG globalRNG; +static int initGlobalRNG = 0; +#endif +#if defined(OPENSSL_EXTRA) && \ + !defined(NO_RSA) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) +WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA *rsa, WC_RNG **tmpRNG, int *initTmpRng) +{ + WC_RNG* rng = NULL; + + if (!rsa || !initTmpRng) { + return NULL; + } + *initTmpRng = 0; + +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \ + !defined(HAVE_FAST_RSA) && defined(WC_RSA_BLINDING) + rng = ((RsaKey*)rsa->internal)->rng; +#endif + if (rng == NULL && tmpRNG) { + if (!*tmpRNG) { +#ifdef WOLFSSL_SMALL_STACK + *tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*tmpRNG == NULL) + return NULL; +#else + WOLFSSL_MSG("*tmpRNG is null"); + return NULL; +#endif + } + + if (wc_InitRng(*tmpRNG) == 0) { + rng = *tmpRNG; + *initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; +#ifdef WOLFSSL_SMALL_STACK + if (*tmpRNG) + XFREE(*tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *tmpRNG = NULL; +#endif + } + } + return rng; +} +#endif +#ifndef WOLFCRYPT_ONLY + +#ifdef OPENSSL_EXTRA + +/* Not thread safe! Can be called multiple times. + * Checks if the global RNG has been created. If not then one is created. + * + * Returns SSL_SUCCESS when no error is encountered. + */ +static int wolfSSL_RAND_Init(void) +{ + if (initGlobalRNG == 0) { + if (wc_InitRng(&globalRNG) < 0) { + WOLFSSL_MSG("wolfSSL Init Global RNG failed"); + return 0; + } + initGlobalRNG = 1; + } + + return SSL_SUCCESS; +} + + +/* SSL_SUCCESS on ok */ +int wolfSSL_RAND_seed(const void* seed, int len) +{ + + WOLFSSL_MSG("wolfSSL_RAND_seed"); + + (void)seed; + (void)len; + + return wolfSSL_RAND_Init(); +} + + +/* Returns the path for reading seed data from. + * Uses the env variable $RANDFILE first if set, if not then used $HOME/.rnd + * + * Note uses stdlib by default unless XGETENV macro is overwritten + * + * fname buffer to hold path + * len length of fname buffer + * + * Returns a pointer to fname on success and NULL on failure + */ +const char* wolfSSL_RAND_file_name(char* fname, unsigned long len) +{ +#ifndef NO_FILESYSTEM + char* rt; + char ap[] = "/.rnd"; + + WOLFSSL_ENTER("wolfSSL_RAND_file_name"); + + if (fname == NULL) { + return NULL; + } + + XMEMSET(fname, 0, len); + /* if access to stdlib.h */ + if ((rt = XGETENV("RANDFILE")) != NULL) { + if (len > XSTRLEN(rt)) { + XMEMCPY(fname, rt, XSTRLEN(rt)); + } + else { + WOLFSSL_MSG("RANDFILE too large for buffer"); + rt = NULL; + } + } + + /* $RANDFILE was not set or is too large, check $HOME */ + if (rt == NULL) { + WOLFSSL_MSG("Environment variable RANDFILE not set"); + if ((rt = XGETENV("HOME")) == NULL) { + WOLFSSL_MSG("Environment variable HOME not set"); + return NULL; + } + + if (len > XSTRLEN(rt) + XSTRLEN(ap)) { + fname[0] = '\0'; + XSTRNCAT(fname, rt, len); + XSTRNCAT(fname, ap, len - XSTRLEN(rt)); + return fname; + } + else { + WOLFSSL_MSG("HOME too large for buffer"); + return NULL; + } + } + + return fname; +#else + /* no filesystem defined */ + WOLFSSL_ENTER("wolfSSL_RAND_file_name"); + WOLFSSL_MSG("No filesystem feature enabled, not compiled in"); + (void)fname; + (void)len; + return NULL; +#endif +} + + +/* Writes 1024 bytes from the RNG to the given file name. + * + * fname name of file to write to + * + * Returns the number of bytes written + */ +int wolfSSL_RAND_write_file(const char* fname) +{ + int bytes = 0; + + WOLFSSL_ENTER("RAND_write_file"); + + if (fname == NULL) { + return SSL_FAILURE; + } + +#ifndef NO_FILESYSTEM + { + #ifndef WOLFSSL_SMALL_STACK + unsigned char buf[1024]; + #else + unsigned char* buf = (unsigned char *)XMALLOC(1024, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("malloc failed"); + return SSL_FAILURE; + } + #endif + bytes = 1024; /* default size of buf */ + + if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != SSL_SUCCESS) { + WOLFSSL_MSG("No RNG to use"); + #ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return 0; + } + + if (wc_RNG_GenerateBlock(&globalRNG, buf, bytes) != 0) { + WOLFSSL_MSG("Error generating random buffer"); + bytes = 0; + } + else { + XFILE f; + + f = XFOPEN(fname, "wb"); + if (f == XBADFILE) { + WOLFSSL_MSG("Error opening the file"); + bytes = 0; + } + else { + XFWRITE(buf, 1, bytes, f); + XFCLOSE(f); + } + } + ForceZero(buf, bytes); + #ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + } +#endif + + return bytes; +} + +#ifndef FREERTOS_TCP + +/* These constant values are protocol values made by egd */ +#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) + #define WOLFSSL_EGD_NBLOCK 0x01 + #include +#endif + +/* This collects entropy from the path nm and seeds the global PRNG with it. + * Makes a call to wolfSSL_RAND_Init which is not thread safe. + * + * nm is the file path to the egd server + * + * Returns the number of bytes read. + */ +int wolfSSL_RAND_egd(const char* nm) +{ +#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && !defined(HAVE_FIPS) && \ + defined(HAVE_HASHDRBG) + struct sockaddr_un rem; + int fd; + int ret = WOLFSSL_SUCCESS; + word32 bytes = 0; + word32 idx = 0; +#ifndef WOLFSSL_SMALL_STACK + unsigned char buf[256]; +#else + unsigned char* buf; + buf = (unsigned char*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("Not enough memory"); + return WOLFSSL_FATAL_ERROR; + } +#endif + + if (nm == NULL) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return WOLFSSL_FATAL_ERROR; + } + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + WOLFSSL_MSG("Error creating socket"); + #ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return WOLFSSL_FATAL_ERROR; + } + if (ret == WOLFSSL_SUCCESS) { + rem.sun_family = AF_UNIX; + XSTRNCPY(rem.sun_path, nm, sizeof(rem.sun_path) - 1); + rem.sun_path[sizeof(rem.sun_path)-1] = '\0'; + } + + /* connect to egd server */ + if (ret == WOLFSSL_SUCCESS) { + if (connect(fd, (struct sockaddr*)&rem, sizeof(struct sockaddr_un)) + == -1) { + WOLFSSL_MSG("error connecting to egd server"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + while (ret == WOLFSSL_SUCCESS && bytes < 255 && idx + 2 < 256) { + if (ret == WOLFSSL_SUCCESS) { + buf[idx] = WOLFSSL_EGD_NBLOCK; + buf[idx + 1] = 255 - bytes; /* request 255 bytes from server */ + ret = (int)write(fd, buf + idx, 2); + if (ret <= 0 || ret != 2) { + if (errno == EAGAIN) { + ret = WOLFSSL_SUCCESS; + continue; + } + WOLFSSL_MSG("error requesting entropy from egd server"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + } + + /* attempting to read */ + buf[idx] = 0; + ret = (int)read(fd, buf + idx, 256 - bytes); + if (ret == 0) { + WOLFSSL_MSG("error reading entropy from egd server"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + if (ret > 0 && buf[idx] > 0) { + bytes += buf[idx]; /* egd stores amount sent in first byte */ + if (bytes + idx > 255 || buf[idx] > ret) { + WOLFSSL_MSG("Buffer error"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + XMEMMOVE(buf + idx, buf + idx + 1, buf[idx]); + idx = bytes; + ret = WOLFSSL_SUCCESS; + if (bytes >= 255) { + break; + } + } + else { + if (errno == EAGAIN || errno == EINTR) { + WOLFSSL_MSG("EGD would read"); + ret = WOLFSSL_SUCCESS; /* try again */ + } + else if (buf[idx] == 0) { + /* if egd returned 0 then there is no more entropy to be had. + Do not try more reads. */ + ret = WOLFSSL_SUCCESS; + break; + } + else { + WOLFSSL_MSG("Error with read"); + ret = WOLFSSL_FATAL_ERROR; + } + } + } + + if (bytes > 0 && ret == WOLFSSL_SUCCESS) { + wolfSSL_RAND_Init(); /* call to check global RNG is created */ + if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes) + != 0) { + WOLFSSL_MSG("Error with reseeding DRBG structure"); + ret = WOLFSSL_FATAL_ERROR; + } + #ifdef SHOW_SECRETS + { /* print out entropy found */ + word32 i; + printf("EGD Entropy = "); + for (i = 0; i < bytes; i++) { + printf("%02X", buf[i]); + } + printf("\n"); + } + #endif + } + + ForceZero(buf, bytes); + #ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + close(fd); + + if (ret == WOLFSSL_SUCCESS) { + return bytes; + } + else { + return ret; + } +#else + WOLFSSL_MSG("Type of socket needed is not available"); + WOLFSSL_MSG("\tor using mode where DRBG API is not available"); + (void)nm; + + return WOLFSSL_FATAL_ERROR; +#endif /* USE_WOLFSSL_IO && !USE_WINDOWS_API && !HAVE_FIPS && HAVE_HASHDRBG */ +} + +#endif /* !FREERTOS_TCP */ + +void wolfSSL_RAND_Cleanup(void) +{ + WOLFSSL_ENTER("wolfSSL_RAND_Cleanup()"); + + if (initGlobalRNG != 0) { + wc_FreeRng(&globalRNG); + initGlobalRNG = 0; + } +} + + +int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) +{ + return wolfSSL_RAND_bytes(buf, num); +} + + +/* SSL_SUCCESS on ok */ +int wolfSSL_RAND_bytes(unsigned char* buf, int num) +{ + int ret = 0; + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_RAND_bytes"); + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return ret; +#endif + + if (initGlobalRNG) + rng = &globalRNG; + else if(wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + if (rng) { + if (wc_RNG_GenerateBlock(rng, buf, num) != 0) + WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); + else + ret = WOLFSSL_SUCCESS; + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +} + + +int wolfSSL_RAND_poll(void) +{ + byte entropy[16]; + int ret = 0; + word32 entropy_sz = 16; + + WOLFSSL_ENTER("wolfSSL_RAND_poll"); + if (initGlobalRNG == 0){ + WOLFSSL_MSG("Global RNG no Init"); + return WOLFSSL_FAILURE; + } + ret = wc_GenerateSeed(&globalRNG.seed, entropy, entropy_sz); + if (ret != 0){ + WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); + ret = WOLFSSL_FAILURE; + }else + ret = WOLFSSL_SUCCESS; + + return ret; +} +#endif /* OPENSSL_EXTRA */ + + + +#ifdef OPENSSL_EXTRA + +WOLFSSL_ASN1_INTEGER* wolfSSL_BN_to_ASN1_INTEGER(const WOLFSSL_BIGNUM *bn, WOLFSSL_ASN1_INTEGER *ai) +{ + WOLFSSL_ASN1_INTEGER* a; + int len; + WOLFSSL_ENTER("wolfSSL_BN_to_ASN1_INTEGER"); + + if (ai == NULL) { + a = wolfSSL_ASN1_INTEGER_new(); + + if (a == NULL) + return NULL; + + a->type = V_ASN1_INTEGER; + } + else { + a = ai; + } + if (a) { + if (wolfSSL_BN_is_negative(bn) && !wolfSSL_BN_is_zero(bn)) { + a->type |= V_ASN1_NEG_INTEGER; + a->negative = 1; + } + + len = wolfSSL_BN_num_bytes(bn); + if (len == 0) + len = 1; + + /* allocate buffer */ + if (len > (int)sizeof(a->intData)) { + /* create new data buffer and copy over */ + a->data = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (a->data == NULL) { + if (a != ai) + wolfSSL_ASN1_INTEGER_free(a); + return NULL; + } + a->isDynamic = 1; + } + else { + XMEMSET(a->intData, 0, sizeof(a->intData)); + a->data = a->intData; + } + a->length = len; + + /* populate data */ + if (wolfSSL_BN_is_zero(bn)) { + a->data[0] = 0; + } + else { + len = wolfSSL_BN_bn2bin(bn, a->data); + } + a->length = len; + } + + return a; +} + +#ifdef OPENSSL_ALL +void *wolfSSL_ASN1_item_new(const WOLFSSL_ASN1_ITEM *template) +{ + void *ret = NULL; + const WOLFSSL_ASN1_TEMPLATE *member = NULL; + size_t i; + WOLFSSL_ENTER("wolfSSL_ASN1_item_new"); + if (!template) { + return NULL; + } + if (!(ret = XMALLOC(template->size, NULL, DYNAMIC_TYPE_OPENSSL))) { + return NULL; + } + XMEMSET(ret, 0, template->size); + for (member = template->members, i = 0; i < template->mcount; + member++, i++) { + switch (member->type) { + case WOLFSSL_X509_ALGOR_ASN1: + { + WOLFSSL_X509_ALGOR* algor = wolfSSL_X509_ALGOR_new(); + if (!algor) { + goto error; + } + *(WOLFSSL_X509_ALGOR**)(((byte*)ret) + member->offset) = algor; + break; + } + case WOLFSSL_ASN1_BIT_STRING_ASN1: + { + WOLFSSL_ASN1_BIT_STRING* bit_str = wolfSSL_ASN1_BIT_STRING_new(); + if (!bit_str) { + goto error; + } + *(WOLFSSL_ASN1_BIT_STRING**)(((byte*)ret) + member->offset) = bit_str; + break; + } + default: + WOLFSSL_MSG("Type not supported in wolfSSL_ASN1_item_new"); + goto error; + } + } + return ret; +error: + wolfSSL_ASN1_item_free(ret, template); + return NULL; +} + +void wolfSSL_ASN1_item_free(void *val, const WOLFSSL_ASN1_ITEM *template) +{ + const WOLFSSL_ASN1_TEMPLATE *member = NULL; + size_t i; + WOLFSSL_ENTER("wolfSSL_ASN1_item_free"); + if (val) { + for (member = template->members, i = 0; i < template->mcount; + member++, i++) { + switch (member->type) { + case WOLFSSL_X509_ALGOR_ASN1: + { + WOLFSSL_X509_ALGOR* algor = *(WOLFSSL_X509_ALGOR**) + (((byte*)val) + member->offset); + if (algor) { + wolfSSL_X509_ALGOR_free(algor); + } + break; + } + case WOLFSSL_ASN1_BIT_STRING_ASN1: + { + WOLFSSL_ASN1_BIT_STRING* bit_str = *(WOLFSSL_ASN1_BIT_STRING**) + (((byte*)val) + member->offset); + if (bit_str) { + wolfSSL_ASN1_BIT_STRING_free(bit_str); + } + break; + } + default: + WOLFSSL_MSG("Type not supported in wolfSSL_ASN1_item_free"); + } + } + XFREE(val, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +#define bufLenOrNull(buf, len) (buf ? buf + len : NULL) + +static int i2dProcessMembers(const void *src, byte *buf, + const WOLFSSL_ASN1_TEMPLATE *members, size_t mcount) +{ + const WOLFSSL_ASN1_TEMPLATE *member = NULL; + int len = 0, ret; + size_t i; + WOLFSSL_ENTER("processMembers"); + for (member = members, i = 0; i < mcount; member++, i++) { + switch (member->type) { + case WOLFSSL_X509_ALGOR_ASN1: + { + word32 oid = 0; + word32 idx = 0; + const WOLFSSL_X509_ALGOR* algor = *(const WOLFSSL_X509_ALGOR**) + (((byte*)src) + member->offset); + if (!algor->algorithm) { + WOLFSSL_LEAVE("processMembers", WOLFSSL_FAILURE); + return WOLFSSL_FAILURE; + } + + if (GetObjectId(algor->algorithm->obj, &idx, &oid, + algor->algorithm->grp, algor->algorithm->objSz) < 0) { + WOLFSSL_MSG("Issue getting OID of object"); + return -1; + } + + ret = SetAlgoID(oid, bufLenOrNull(buf, len), + algor->algorithm->grp, 0); + if (!ret) { + return WOLFSSL_FAILURE; + } + len += ret; + break; + } + case WOLFSSL_ASN1_BIT_STRING_ASN1: + { + const WOLFSSL_ASN1_BIT_STRING* bit_str; + bit_str = *(const WOLFSSL_ASN1_BIT_STRING**) + (((byte*)src) + member->offset); + len += SetBitString(bit_str->length, 0, bufLenOrNull(buf, len)); + if (buf && bit_str->data) { + XMEMCPY(buf + len, bit_str->data, bit_str->length); + } + len += bit_str->length; + break; + } + default: + WOLFSSL_MSG("Type not support in processMembers"); + WOLFSSL_LEAVE("processMembers", WOLFSSL_FAILURE); + return WOLFSSL_FAILURE; + } + } + WOLFSSL_LEAVE("processMembers", len); + return len; +} + +int wolfSSL_ASN1_item_i2d(const void *src, byte **dest, + const WOLFSSL_ASN1_ITEM *template) +{ + int len = 0; + byte *buf = NULL; + + WOLFSSL_ENTER("wolfSSL_ASN1_item_i2d"); + + if (!src || !template) { + WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", WOLFSSL_FAILURE); + return WOLFSSL_FAILURE; + } + + if (dest && !*dest) { + len = wolfSSL_ASN1_item_i2d(src, NULL, template); + if (!len) { + goto error; + } + buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_ASN1); + if (!buf) { + goto error; + } + len = 0; + } + + switch (template->type) { + case ASN_SEQUENCE: + { + int seq_len = i2dProcessMembers(src, NULL, template->members, + template->mcount); + if (!seq_len) { + goto error; + } + len += SetSequence(seq_len, bufLenOrNull(buf, len)); + if (buf && + i2dProcessMembers(src, bufLenOrNull(buf, len), template->members, + template->mcount) != seq_len) { + WOLFSSL_MSG("Inconsistent sequence length"); + goto error; + } + len += seq_len; + break; + } + default: + WOLFSSL_MSG("Type not supported in wolfSSL_ASN1_item_i2d"); + goto error; + } + + if (dest && !*dest) { + *dest = buf; + } + else if (dest && *dest && buf) { + /* *dest length is not checked because the user is responsible + * for providing a long enough buffer */ + XMEMCPY(*dest, buf, len); + } + + WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", len); + return len; +error: + if (buf) { + XFREE(buf, NULL, DYNAMIC_TYPE_ASN1); + } + WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", WOLFSSL_FAILURE); + return WOLFSSL_FAILURE; +} +#endif /* OPENSSL_ALL */ + +#ifndef NO_DH + +static void InitwolfSSL_DH(WOLFSSL_DH* dh) +{ + if (dh) { + XMEMSET(dh, 0, sizeof(WOLFSSL_DH)); + } +} + + +WOLFSSL_DH* wolfSSL_DH_new(void) +{ + WOLFSSL_DH* external; + DhKey* key; + + WOLFSSL_MSG("wolfSSL_DH_new"); + + key = (DhKey*) XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_DH_new malloc DhKey failure"); + return NULL; + } + + external = (WOLFSSL_DH*) XMALLOC(sizeof(WOLFSSL_DH), NULL, + DYNAMIC_TYPE_DH); + if (external == NULL) { + WOLFSSL_MSG("wolfSSL_DH_new malloc WOLFSSL_DH failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DH); + return NULL; + } + + InitwolfSSL_DH(external); + if (wc_InitDhKey(key) != 0) { + WOLFSSL_MSG("wolfSSL_DH_new InitDhKey failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DH); + XFREE(external, NULL, DYNAMIC_TYPE_DH); + return NULL; + } + external->internal = key; + + return external; +} + + +void wolfSSL_DH_free(WOLFSSL_DH* dh) +{ + WOLFSSL_MSG("wolfSSL_DH_free"); + + if (dh) { + if (dh->internal) { + wc_FreeDhKey((DhKey*)dh->internal); + XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH); + dh->internal = NULL; + } + wolfSSL_BN_free(dh->priv_key); + wolfSSL_BN_free(dh->pub_key); + wolfSSL_BN_free(dh->g); + wolfSSL_BN_free(dh->p); + wolfSSL_BN_free(dh->q); + InitwolfSSL_DH(dh); /* set back to NULLs for safety */ + + XFREE(dh, NULL, DYNAMIC_TYPE_DH); + } +} + +int SetDhInternal(WOLFSSL_DH* dh) +{ + int ret = WOLFSSL_FATAL_ERROR; + int pSz = 1024; + int gSz = 1024; +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + int privSz = 256; /* Up to 2048-bit */ + int pubSz = 256; +#endif +#ifdef WOLFSSL_SMALL_STACK + unsigned char* p = NULL; + unsigned char* g = NULL; + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + unsigned char* priv_key = NULL; + unsigned char* pub_key = NULL; + #endif +#else + unsigned char p[1024]; + unsigned char g[1024]; + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + unsigned char priv_key[256]; + unsigned char pub_key[256]; + #endif +#endif + + WOLFSSL_ENTER("SetDhInternal"); + + if (dh == NULL || dh->p == NULL || dh->g == NULL) + WOLFSSL_MSG("Bad function arguments"); + else if (wolfSSL_BN_bn2bin(dh->p, NULL) > pSz) + WOLFSSL_MSG("Bad p internal size"); + else if (wolfSSL_BN_bn2bin(dh->g, NULL) > gSz) + WOLFSSL_MSG("Bad g internal size"); + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + else if (wolfSSL_BN_bn2bin(dh->priv_key, NULL) > privSz) + WOLFSSL_MSG("Bad private key internal size"); + else if (wolfSSL_BN_bn2bin(dh->pub_key, NULL) > privSz) + WOLFSSL_MSG("Bad public key internal size"); + #endif + else { + #ifdef WOLFSSL_SMALL_STACK + p = (unsigned char*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + g = (unsigned char*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + priv_key = (unsigned char*)XMALLOC(privSz,NULL,DYNAMIC_TYPE_PRIVATE_KEY); + pub_key = (unsigned char*)XMALLOC(pubSz,NULL,DYNAMIC_TYPE_PUBLIC_KEY); + #endif + + if (p == NULL || g == NULL) { + XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + return ret; + } + #endif /* WOLFSSL_SMALL_STACK */ + + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv_key); + pubSz = wolfSSL_BN_bn2bin(dh->pub_key, pub_key); + if (privSz <= 0) { + WOLFSSL_MSG("No private key size."); + } + if (pubSz <= 0) { + WOLFSSL_MSG("No public key size."); + } + if (privSz > 0 || pubSz > 0) { + ret = wc_DhSetFullKeys((DhKey*)dh->internal,priv_key,privSz, + pub_key,pubSz); + if (ret == WOLFSSL_FAILURE) { + WOLFSSL_MSG("Failed setting private or public key."); + } + } + #endif /* WOLFSSL_QT || OPENSSL_ALL */ + + pSz = wolfSSL_BN_bn2bin(dh->p, p); + gSz = wolfSSL_BN_bn2bin(dh->g, g); + + if (pSz <= 0 || gSz <= 0) + WOLFSSL_MSG("Bad BN2bin set"); + else if (wc_DhSetKey((DhKey*)dh->internal, p, pSz, g, gSz) < 0) + WOLFSSL_MSG("Bad DH SetKey"); + else { + dh->inSet = 1; + ret = WOLFSSL_SUCCESS; + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + XFREE(priv_key, NULL, DYNAMIC_TYPE_PRIVATE_KEY); + XFREE(pub_key, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + #endif + #endif + } + + + return ret; +} + +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)) +/* Set the members of DhKey into WOLFSSL_DH + * DhKey was populated from wc_DhKeyDecode + */ +int SetDhExternal(WOLFSSL_DH *dh) +{ + DhKey *key; + WOLFSSL_MSG("Entering SetDhExternal"); + + if (dh == NULL || dh->internal == NULL) { + WOLFSSL_MSG("dh key NULL error"); + } + + key = (DhKey*)dh->internal; + + if (SetIndividualExternal(&dh->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dh param p error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dh->g, &key->g) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dh param g error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dh->priv_key, &key->priv) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("No DH Private Key"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dh->pub_key, &key->pub) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("No DH Public Key"); + return WOLFSSL_FATAL_ERROR; + } + + dh->exSet = 1; + + return WOLFSSL_SUCCESS; +} +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + +/* return code compliant with OpenSSL : + * DH prime size in bytes if success, 0 if error + */ +int wolfSSL_DH_size(WOLFSSL_DH* dh) +{ + WOLFSSL_MSG("wolfSSL_DH_size"); + + if (dh == NULL) + return WOLFSSL_FATAL_ERROR; + + return wolfSSL_BN_num_bytes(dh->p); +} + +/* This sets a big number with the 768-bit prime from RFC 2409. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_768_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A63A3620FFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_768_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 768 prime to big number"); + return NULL; + } + + return bn; +} + +/* This sets a big number with the 1024-bit prime from RFC 2409. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_1024_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE65381FFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_1024_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 1024 prime to big number"); + return NULL; + } + + return bn; +} + +/* This sets a big number with the 1536-bit prime from RFC 3526. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_1536_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA237327FFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_1536_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 1536 prime to big number"); + return NULL; + } + + return bn; +} + +/* This sets a big number with the 2048-bit prime from RFC 3526. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_2048_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_2048_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 2048 prime to big number"); + return NULL; + } + + return bn; +} + +/* This sets a big number with the 3072-bit prime from RFC 3526. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_3072_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_3072_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 3072 prime to big number"); + return NULL; + } + + return bn; +} + +/* This sets a big number with the 4096-bit prime from RFC 3526. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_4096_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C" + "1A946834B6150BDA2583E9CA2AD44CE8" + "DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AF" + "B81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F" + "4DF435C934063199FFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_4096_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 4096 prime to big number"); + return NULL; + } + + return bn; +} + +/* This sets a big number with the 6144-bit prime from RFC 3526. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_6144_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C" + "1A946834B6150BDA2583E9CA2AD44CE8" + "DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AF" + "B81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F" + "4DF435C93402849236C3FAB4D27C7026" + "C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AE" + "B06A53ED9027D831179727B0865A8918" + "DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF42" + "6FB8F401378CD2BF5983CA01C64B92EC" + "F032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E" + "59E7C97FBEC7E8F323A97A7E36CC88BE" + "0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0" + "A79715EEF29BE32806A1D58BB7C5DA76" + "F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468" + "043E8F663F4860EE12BF2D5B0B7474D6" + "E694F91E6DCC4024FFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_6144_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 6144 prime to big number"); + return NULL; + } + + return bn; +} + + +/* This sets a big number with the 8192-bit prime from RFC 3526. + * + * bn if not NULL then the big number structure is used. If NULL then a new + * big number structure is created. + * + * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_8192_prime(WOLFSSL_BIGNUM* bn) +{ + const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C" + "1A946834B6150BDA2583E9CA2AD44CE8" + "DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AF" + "B81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F" + "4DF435C93402849236C3FAB4D27C7026" + "C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AE" + "B06A53ED9027D831179727B0865A8918" + "DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF42" + "6FB8F401378CD2BF5983CA01C64B92EC" + "F032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E" + "59E7C97FBEC7E8F323A97A7E36CC88BE" + "0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0" + "A79715EEF29BE32806A1D58BB7C5DA76" + "F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468" + "043E8F663F4860EE12BF2D5B0B7474D6" + "E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA" + "3BC832B68D9DD300741FA7BF8AFC47ED" + "2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652D" + "E3FDB8BEFC848AD922222E04A4037C07" + "13EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E8" + "79683303ED5BDD3A062B3CF5B3A278A6" + "6D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851D" + "F9AB48195DED7EA1B1D510BD7EE74D73" + "FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382B" + "C9190DA6FC026E479558E4475677E9AA" + "9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF" + }; + + WOLFSSL_ENTER("wolfSSL_DH_8192_prime"); + + if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting DH 8192 prime to big number"); + return NULL; + } + + return bn; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_DH_generate_key(WOLFSSL_DH* dh) +{ + int ret = WOLFSSL_FAILURE; + word32 pubSz = 0; + word32 privSz = 0; + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG; +#else + WC_RNG tmpRNG[1]; +#endif + unsigned char* pub = NULL; + unsigned char* priv = NULL; + + WOLFSSL_MSG("wolfSSL_DH_generate_key"); + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) { + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); + return ret; + } +#endif + + if (dh == NULL || dh->p == NULL || dh->g == NULL) + WOLFSSL_MSG("Bad function arguments"); + else if (dh->inSet == 0 && SetDhInternal(dh) != WOLFSSL_SUCCESS) + WOLFSSL_MSG("Bad DH set internal"); + else if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + pubSz = wolfSSL_BN_num_bytes(dh->p); + if (dh->length) { + privSz = dh->length/8; /* to bytes */ + } else { + privSz = pubSz; + } + pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY); + if (pub == NULL || priv == NULL) { + WOLFSSL_MSG("Unable to malloc memory"); + } + else if (wc_DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, &privSz, + pub, &pubSz) < 0) + WOLFSSL_MSG("Bad wc_DhGenerateKeyPair"); + else { + if (dh->pub_key) + wolfSSL_BN_free(dh->pub_key); + + dh->pub_key = wolfSSL_BN_new(); + if (dh->pub_key == NULL) { + WOLFSSL_MSG("Bad DH new pub"); + } + if (dh->priv_key) + wolfSSL_BN_free(dh->priv_key); + + dh->priv_key = wolfSSL_BN_new(); + + if (dh->priv_key == NULL) { + WOLFSSL_MSG("Bad DH new priv"); + } + + if (dh->pub_key && dh->priv_key) { + if (wolfSSL_BN_bin2bn(pub, pubSz, dh->pub_key) == NULL) + WOLFSSL_MSG("Bad DH bn2bin error pub"); + else if (wolfSSL_BN_bin2bn(priv, privSz, dh->priv_key) == NULL) + WOLFSSL_MSG("Bad DH bn2bin error priv"); + else + ret = WOLFSSL_SUCCESS; + } + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY); + + return ret; +} + + +/* return code compliant with OpenSSL : + * size of shared secret if success, -1 if error + */ +int wolfSSL_DH_compute_key(unsigned char* key, WOLFSSL_BIGNUM* otherPub, + WOLFSSL_DH* dh) +{ + int ret = WOLFSSL_FATAL_ERROR; + word32 keySz = 0; + int pubSz = 1024; + int privSz = 1024; +#ifdef WOLFSSL_SMALL_STACK + unsigned char* pub; + unsigned char* priv = NULL; +#else + unsigned char pub [1024]; + unsigned char priv[1024]; +#endif + + WOLFSSL_MSG("wolfSSL_DH_compute_key"); + +#ifdef WOLFSSL_SMALL_STACK + pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + if (pub == NULL) + return ret; + + priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY); + if (priv == NULL) { + XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + return ret; + } +#endif + + if (dh == NULL || dh->priv_key == NULL || otherPub == NULL) + WOLFSSL_MSG("Bad function arguments"); + else if ((keySz = (word32)DH_size(dh)) == 0) + WOLFSSL_MSG("Bad DH_size"); + else if (wolfSSL_BN_bn2bin(dh->priv_key, NULL) > (int)privSz) + WOLFSSL_MSG("Bad priv internal size"); + else if (wolfSSL_BN_bn2bin(otherPub, NULL) > (int)pubSz) + WOLFSSL_MSG("Bad otherPub size"); + else { + privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv); + pubSz = wolfSSL_BN_bn2bin(otherPub, pub); + if (dh->inSet == 0 && SetDhInternal(dh) != SSL_SUCCESS){ + WOLFSSL_MSG("Bad DH set internal"); + } + if (privSz <= 0 || pubSz <= 0) + WOLFSSL_MSG("Bad BN2bin set"); + else if (wc_DhAgree((DhKey*)dh->internal, key, &keySz, + priv, privSz, pub, pubSz) < 0) + WOLFSSL_MSG("wc_DhAgree failed"); + else + ret = (int)keySz; + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY); +#endif + + return ret; +} + + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L +/* ownership of p,q,and g get taken over by "dh" on success and should be free'd + * with a call to wolfSSL_DH_free -- not individually. + * + * returns WOLFSSL_SUCCESS on success + */ +int wolfSSL_DH_set0_pqg(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *p, + WOLFSSL_BIGNUM *q, WOLFSSL_BIGNUM *g) +{ + int ret; + WOLFSSL_ENTER("wolfSSL_DH_set0_pqg"); + + /* q can be NULL */ + if (dh == NULL || p == NULL || g == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + /* free existing internal DH structure and recreate with new p / g */ + if (dh->inSet) { + ret = wc_FreeDhKey((DhKey*)dh->internal); + if (ret != 0) { + WOLFSSL_MSG("Unable to free internal DH key"); + return WOLFSSL_FAILURE; + } + } + + wolfSSL_BN_free(dh->p); + wolfSSL_BN_free(dh->q); + wolfSSL_BN_free(dh->g); + wolfSSL_BN_free(dh->pub_key); + wolfSSL_BN_free(dh->priv_key); + + dh->p = p; + dh->q = q; + dh->g = g; + + ret = SetDhInternal(dh); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Unable to set internal DH key"); + dh->p = NULL; + dh->q = NULL; + dh->g = NULL; + dh->inSet = 0; + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* v1.1.0 or later */ + +#endif /* NO_DH */ + + +#ifndef NO_DSA +static void InitwolfSSL_DSA(WOLFSSL_DSA* dsa) +{ + if (dsa) { + dsa->p = NULL; + dsa->q = NULL; + dsa->g = NULL; + dsa->pub_key = NULL; + dsa->priv_key = NULL; + dsa->internal = NULL; + dsa->inSet = 0; + dsa->exSet = 0; + } +} + + +WOLFSSL_DSA* wolfSSL_DSA_new(void) +{ + WOLFSSL_DSA* external; + DsaKey* key; + + WOLFSSL_MSG("wolfSSL_DSA_new"); + + key = (DsaKey*) XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_new malloc DsaKey failure"); + return NULL; + } + + external = (WOLFSSL_DSA*) XMALLOC(sizeof(WOLFSSL_DSA), NULL, + DYNAMIC_TYPE_DSA); + if (external == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_new malloc WOLFSSL_DSA failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DSA); + return NULL; + } + + InitwolfSSL_DSA(external); + if (wc_InitDsaKey(key) != 0) { + WOLFSSL_MSG("wolfSSL_DSA_new InitDsaKey failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DSA); + wolfSSL_DSA_free(external); + return NULL; + } + external->internal = key; + + return external; +} + + +void wolfSSL_DSA_free(WOLFSSL_DSA* dsa) +{ + WOLFSSL_MSG("wolfSSL_DSA_free"); + + if (dsa) { + if (dsa->internal) { + FreeDsaKey((DsaKey*)dsa->internal); + XFREE(dsa->internal, NULL, DYNAMIC_TYPE_DSA); + dsa->internal = NULL; + } + wolfSSL_BN_free(dsa->priv_key); + wolfSSL_BN_free(dsa->pub_key); + wolfSSL_BN_free(dsa->g); + wolfSSL_BN_free(dsa->q); + wolfSSL_BN_free(dsa->p); + InitwolfSSL_DSA(dsa); /* set back to NULLs for safety */ + + XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); + + /* dsa = NULL, don't try to access or double free it */ + } +} + +#endif /* NO_DSA */ +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_EXTRA + +#ifndef NO_DSA +/* wolfSSL -> OpenSSL */ +int SetDsaExternal(WOLFSSL_DSA* dsa) +{ + DsaKey* key; + WOLFSSL_MSG("Entering SetDsaExternal"); + + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("dsa key NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + key = (DsaKey*)dsa->internal; + + if (SetIndividualExternal(&dsa->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa p key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dsa->q, &key->q) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa q key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dsa->g, &key->g) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa g key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dsa->pub_key, &key->y) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa y key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&dsa->priv_key, &key->x) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa x key error"); + return WOLFSSL_FATAL_ERROR; + } + + dsa->exSet = 1; + + return WOLFSSL_SUCCESS; +} + +/* Openssl -> WolfSSL */ +int SetDsaInternal(WOLFSSL_DSA* dsa) +{ + DsaKey* key; + WOLFSSL_MSG("Entering SetDsaInternal"); + + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("dsa key NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + key = (DsaKey*)dsa->internal; + + if (dsa->p != NULL && + SetIndividualInternal(dsa->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa p key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (dsa->q != NULL && + SetIndividualInternal(dsa->q, &key->q) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa q key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (dsa->g != NULL && + SetIndividualInternal(dsa->g, &key->g) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa g key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (dsa->pub_key != NULL) { + if (SetIndividualInternal(dsa->pub_key, &key->y) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa pub_key error"); + return WOLFSSL_FATAL_ERROR; + } + + /* public key */ + key->type = DSA_PUBLIC; + } + + if (dsa->priv_key != NULL) { + if (SetIndividualInternal(dsa->priv_key, &key->x) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa priv_key error"); + return WOLFSSL_FATAL_ERROR; + } + + /* private key */ + key->type = DSA_PRIVATE; + } + + dsa->inSet = 1; + + return WOLFSSL_SUCCESS; +} +#endif /* NO_DSA */ +#endif /* OPENSSL_EXTRA */ + + +#ifdef OPENSSL_EXTRA +#if !defined(NO_RSA) +/* Generates a RSA key of length len + * + * len length of RSA key i.e. 2048 + * e e to use when generating RSA key + * f callback function for generation details + * data user callback argument + * + * Note: Because of wc_MakeRsaKey an RSA key size generated can be slightly + * rounded down. For example generating a key of size 2999 with e = + * 65537 will make a key of size 374 instead of 375. + * Returns a new RSA key on success and NULL on failure + */ +WOLFSSL_RSA* wolfSSL_RSA_generate_key(int len, unsigned long e, + void(*f)(int, int, void*), void* data) +{ + WOLFSSL_RSA* rsa = NULL; + WOLFSSL_BIGNUM* bn = NULL; + + WOLFSSL_ENTER("wolfSSL_RSA_generate_key"); + + (void)f; + (void)data; + + if (len < 0) { + WOLFSSL_MSG("Bad argument: length was less than 0"); + return NULL; + } + + bn = wolfSSL_BN_new(); + if (bn == NULL) { + WOLFSSL_MSG("Error creating big number"); + return NULL; + } + + if (wolfSSL_BN_set_word(bn, (WOLFSSL_BN_ULONG)e) != SSL_SUCCESS) { + WOLFSSL_MSG("Error using e value"); + wolfSSL_BN_free(bn); + return NULL; + } + + rsa = wolfSSL_RSA_new(); + if (rsa == NULL) { + WOLFSSL_MSG("memory error"); + } + else { + if (wolfSSL_RSA_generate_key_ex(rsa, len, bn, NULL) != SSL_SUCCESS){ + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + } + wolfSSL_BN_free(bn); + + return rsa; +} + + +/* return compliant with OpenSSL + * 1 if success, 0 if error + */ +int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* bn, + void* cb) +{ + int ret = WOLFSSL_FAILURE; + + (void)cb; + (void)bn; + (void)bits; + + WOLFSSL_ENTER("wolfSSL_RSA_generate_key_ex"); + + if (rsa == NULL || rsa->internal == NULL) { + /* bit size checked during make key call */ + WOLFSSL_MSG("bad arguments"); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_KEY_GEN + { + #ifdef WOLFSSL_SMALL_STACK + WC_RNG* rng; + #else + WC_RNG rng[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (rng == NULL) + return WOLFSSL_FAILURE; + #endif + + if (wc_InitRng(rng) < 0) + WOLFSSL_MSG("RNG init failed"); + else if (wc_MakeRsaKey((RsaKey*)rsa->internal, bits, + wolfSSL_BN_get_word(bn), rng) != MP_OKAY) + WOLFSSL_MSG("wc_MakeRsaKey failed"); + else if (SetRsaExternal(rsa) != WOLFSSL_SUCCESS) + WOLFSSL_MSG("SetRsaExternal failed"); + else { + rsa->inSet = 1; + ret = WOLFSSL_SUCCESS; + } + + wc_FreeRng(rng); + #ifdef WOLFSSL_SMALL_STACK + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + #endif + } +#else + WOLFSSL_MSG("No Key Gen built in"); +#endif + return ret; +} +#endif /* NO_RSA */ + +#ifndef NO_DSA +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_DSA_generate_key(WOLFSSL_DSA* dsa) +{ + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_DSA_generate_key"); + + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + if (dsa->inSet == 0) { + WOLFSSL_MSG("No DSA internal set, do it"); + + if (SetDsaInternal(dsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDsaInternal failed"); + return ret; + } + } + +#ifdef WOLFSSL_KEY_GEN + { + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRNG; +#else + WC_RNG tmpRNG[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FATAL_ERROR; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + if (wc_MakeDsaKey(rng, (DsaKey*)dsa->internal) != MP_OKAY) + WOLFSSL_MSG("wc_MakeDsaKey failed"); + else if (SetDsaExternal(dsa) != WOLFSSL_SUCCESS) + WOLFSSL_MSG("SetDsaExternal failed"); + else + ret = WOLFSSL_SUCCESS; + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + } +#else /* WOLFSSL_KEY_GEN */ + WOLFSSL_MSG("No Key Gen built in"); +#endif + return ret; +} + + +/* Returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail + */ +WOLFSSL_DSA* wolfSSL_DSA_generate_parameters(int bits, unsigned char* seed, + int seedLen, int* counterRet, unsigned long* hRet, + WOLFSSL_BN_CB cb, void* CBArg) +{ + WOLFSSL_DSA* dsa; + + WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters()"); + + (void)cb; + (void)CBArg; + dsa = wolfSSL_DSA_new(); + if (dsa == NULL) { + return NULL; + } + + if (wolfSSL_DSA_generate_parameters_ex(dsa, bits, seed, seedLen, + counterRet, hRet, NULL) != SSL_SUCCESS) { + wolfSSL_DSA_free(dsa); + return NULL; + } + + return dsa; +} + + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_DSA_generate_parameters_ex(WOLFSSL_DSA* dsa, int bits, + unsigned char* seed, int seedLen, + int* counterRet, + unsigned long* hRet, void* cb) +{ + int ret = WOLFSSL_FAILURE; + + (void)bits; + (void)seed; + (void)seedLen; + (void)counterRet; + (void)hRet; + (void)cb; + + WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters_ex"); + + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_KEY_GEN + { + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRNG; +#else + WC_RNG tmpRNG[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FATAL_ERROR; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + if (wc_MakeDsaParameters(rng, bits, + (DsaKey*)dsa->internal) != MP_OKAY) + WOLFSSL_MSG("wc_MakeDsaParameters failed"); + else if (SetDsaExternal(dsa) != WOLFSSL_SUCCESS) + WOLFSSL_MSG("SetDsaExternal failed"); + else + ret = WOLFSSL_SUCCESS; + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + } +#else /* WOLFSSL_KEY_GEN */ + WOLFSSL_MSG("No Key Gen built in"); +#endif + + return ret; +} + +WOLFSSL_DSA_SIG* wolfSSL_DSA_SIG_new(void) +{ + WOLFSSL_DSA_SIG* sig; + WOLFSSL_ENTER("wolfSSL_DSA_SIG_new"); + sig = (WOLFSSL_DSA_SIG*)XMALLOC(sizeof(WOLFSSL_DSA_SIG), NULL, DYNAMIC_TYPE_OPENSSL); + if (sig) + XMEMSET(sig, 0, sizeof(WOLFSSL_DSA_SIG)); + return sig; +} + +void wolfSSL_DSA_SIG_free(WOLFSSL_DSA_SIG *sig) +{ + WOLFSSL_ENTER("wolfSSL_DSA_SIG_free"); + if (sig) { + if (sig->r) { + wolfSSL_BN_free(sig->r); + } + if (sig->s) { + wolfSSL_BN_free(sig->s); + } + XFREE(sig, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +/* return WOLFSSL_SUCCESS on success, < 0 otherwise */ +int wolfSSL_DSA_do_sign(const unsigned char* d, unsigned char* sigRet, + WOLFSSL_DSA* dsa) +{ + int ret = WOLFSSL_FATAL_ERROR; + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_DSA_do_sign"); + + if (d == NULL || sigRet == NULL || dsa == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return ret; + } + + if (dsa->inSet == 0) + { + WOLFSSL_MSG("No DSA internal set, do it"); + + if (SetDsaInternal(dsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDsaInternal failed"); + return ret; + } + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FATAL_ERROR; +#endif + + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + if (DsaSign(d, sigRet, (DsaKey*)dsa->internal, rng) < 0) + WOLFSSL_MSG("DsaSign failed"); + else + ret = WOLFSSL_SUCCESS; + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +} + +#if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) +WOLFSSL_DSA_SIG* wolfSSL_DSA_do_sign_ex(const unsigned char* digest, + int outLen, WOLFSSL_DSA* dsa) +{ + WOLFSSL_DSA_SIG* sig = NULL; + byte sigBin[DSA_SIG_SIZE]; + + WOLFSSL_ENTER("wolfSSL_DSA_do_sign_ex"); + + if (!digest || !dsa || outLen != WC_SHA_DIGEST_SIZE) { + WOLFSSL_MSG("Bad function arguments"); + return NULL; + } + + if (wolfSSL_DSA_do_sign(digest, sigBin, dsa) != WOLFSSL_SUCCESS) { + return NULL; + } + + if (!(sig = wolfSSL_DSA_SIG_new())) { + goto error; + } + + if (!(sig->r = wolfSSL_BN_bin2bn(sigBin, DSA_HALF_SIZE, NULL))) { + goto error; + } + + if (!(sig->s = wolfSSL_BN_bin2bn(sigBin + DSA_HALF_SIZE, DSA_HALF_SIZE, NULL))) { + goto error; + } + + return sig; +error: + if (sig) { + wolfSSL_DSA_SIG_free(sig); + } + return NULL; +} +#endif /* !HAVE_SELFTEST && !HAVE_FIPS */ + +int wolfSSL_DSA_do_verify(const unsigned char* d, unsigned char* sig, + WOLFSSL_DSA* dsa, int *dsacheck) +{ + int ret = WOLFSSL_FATAL_ERROR; + + WOLFSSL_ENTER("wolfSSL_DSA_do_verify"); + + if (d == NULL || sig == NULL || dsa == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + if (dsa->inSet == 0) + { + WOLFSSL_MSG("No DSA internal set, do it"); + + if (SetDsaInternal(dsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDsaInternal failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + ret = DsaVerify(d, sig, (DsaKey*)dsa->internal, dsacheck); + if (ret != 0 || *dsacheck != 1) { + WOLFSSL_MSG("DsaVerify failed"); + return ret; + } + + return WOLFSSL_SUCCESS; +} + +#if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) +int wolfSSL_DSA_do_verify_ex(const unsigned char* digest, int digest_len, + WOLFSSL_DSA_SIG* sig, WOLFSSL_DSA* dsa) +{ + int dsacheck, sz; + byte sigBin[DSA_SIG_SIZE]; + byte* sigBinPtr = sigBin; + + WOLFSSL_ENTER("wolfSSL_DSA_do_verify_ex"); + + if (!digest || !sig || !dsa || digest_len != WC_SHA_DIGEST_SIZE) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + if (!sig->r || !sig->s) { + WOLFSSL_MSG("No signature found in DSA_SIG"); + return WOLFSSL_FAILURE; + } + + /* front pad with zeros */ + if (!(sz = wolfSSL_BN_num_bytes(sig->r))) { + return WOLFSSL_FAILURE; + } + while (sz++ < DSA_HALF_SIZE) { + *sigBinPtr++ = 0; + } + + if (wolfSSL_BN_bn2bin(sig->r, sigBinPtr) == WOLFSSL_FATAL_ERROR) { + return WOLFSSL_FAILURE; + } + + /* Move to s */ + sigBinPtr = sigBin + DSA_HALF_SIZE; + + /* front pad with zeros */ + if (!(sz = wolfSSL_BN_num_bytes(sig->s))) { + return WOLFSSL_FAILURE; + } + while (sz++ < DSA_HALF_SIZE) { + *sigBinPtr++ = 0; + } + + if (wolfSSL_BN_bn2bin(sig->s, sigBinPtr) == WOLFSSL_FATAL_ERROR) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_DSA_do_verify(digest, sigBin, dsa, &dsacheck) != WOLFSSL_SUCCESS || + dsacheck != 1) { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* !HAVE_SELFTEST && !HAVE_FIPS */ +#endif /* NO_DSA */ + + +#if !defined(NO_RSA) && !defined(HAVE_USER_RSA) + +#ifdef DEBUG_SIGN +static void show(const char *title, const unsigned char *out, unsigned int outlen) +{ + const unsigned char *pt; + printf("%s[%d] = \n", title, (int)outlen); + outlen = outlen>100?100:outlen; + for (pt = out; pt < out + outlen; + printf("%c", ((*pt)&0x6f)>='A'?((*pt)&0x6f):'.'), pt++); + printf("\n"); +} +#else +#define show(a,b,c) +#endif + +/* return SSL_SUCCESS on ok, 0 otherwise */ +int wolfSSL_RSA_sign(int type, const unsigned char* m, + unsigned int mLen, unsigned char* sigRet, + unsigned int* sigLen, WOLFSSL_RSA* rsa) +{ + return wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, sigLen, rsa, 1); +} + +int wolfSSL_RSA_sign_ex(int type, const unsigned char* m, + unsigned int mLen, unsigned char* sigRet, + unsigned int* sigLen, WOLFSSL_RSA* rsa, int flag) +{ + word32 outLen; + word32 signSz; + int initTmpRng = 0; + WC_RNG* rng = NULL; + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; + byte* encodedSig = NULL; +#else + WC_RNG tmpRNG[1]; + byte encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_sign"); + + if (m == NULL || sigRet == NULL || sigLen == NULL || rsa == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return 0; + } + show("Message to Sign", m, mLen); + + switch (type) { + #ifdef WOLFSSL_MD2 + case NID_md2: type = MD2h; break; + #endif + #ifndef NO_MD5 + case NID_md5: type = MD5h; break; + #endif + #ifndef NO_SHA + case NID_sha1: type = SHAh; break; + #endif + #ifndef NO_SHA256 + case NID_sha256: type = SHA256h; break; + #endif + #ifdef WOLFSSL_SHA384 + case NID_sha384: type = SHA384h; break; + #endif + #ifdef WOLFSSL_SHA512 + case NID_sha512: type = SHA512h; break; + #endif + #ifndef WOLFSSL_NOSHA3_224 + case NID_sha3_224: type = SHA3_224h; break; + #endif + #ifndef WOLFSSL_NOSHA3_256 + case NID_sha3_256: type = SHA3_256h; break; + #endif + #ifndef WOLFSSL_NOSHA3_384 + case NID_sha3_384: type = SHA3_384h; break; + #endif + #ifndef WOLFSSL_NOSHA3_512 + case NID_sha3_512: type = SHA3_512h; break; + #endif + default: + WOLFSSL_MSG("This NID (md type) not configured or not implemented"); + return 0; + } + + if (rsa->inSet == 0) + { + WOLFSSL_MSG("No RSA internal set, do it"); + + if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return 0; + } + } + + outLen = (word32)wolfSSL_BN_num_bytes(rsa->n); + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return 0; + + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); + return 0; + } +#endif + + if (outLen == 0) + WOLFSSL_MSG("Bad RSA size"); + else if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + + signSz = wc_EncodeSignature(encodedSig, m, mLen, type); + if (signSz == 0) { + WOLFSSL_MSG("Bad Encode Signature"); + } + else { + show("Encoded Message", encodedSig, signSz); + if (flag != 0) { + ret = wc_RsaSSL_Sign(encodedSig, signSz, sigRet, outLen, + (RsaKey*)rsa->internal, rng); + if (ret <= 0) { + WOLFSSL_MSG("Bad Rsa Sign"); + ret = 0; + } + else { + *sigLen = (unsigned int)ret; + ret = SSL_SUCCESS; + show("Signature", sigRet, *sigLen); + } + } else { + ret = SSL_SUCCESS; + XMEMCPY(sigRet, encodedSig, signSz); + *sigLen = signSz; + } + } + + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); + XFREE(encodedSig, NULL, DYNAMIC_TYPE_SIGNATURE); +#endif + + if (ret == WOLFSSL_SUCCESS) + WOLFSSL_MSG("wolfSSL_RSA_sign success"); + else { + WOLFSSL_MSG("wolfSSL_RSA_sign failed"); + } + return ret; +} + + +/* returns WOLFSSL_SUCCESS on successful verify and WOLFSSL_FAILURE on fail */ +int wolfSSL_RSA_verify(int type, const unsigned char* m, + unsigned int mLen, const unsigned char* sig, + unsigned int sigLen, WOLFSSL_RSA* rsa) +{ + int ret; + unsigned char *sigRet ; + unsigned char *sigDec ; + unsigned int len; + + WOLFSSL_ENTER("wolfSSL_RSA_verify"); + if ((m == NULL) || (sig == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + sigRet = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sigRet == NULL) { + WOLFSSL_MSG("Memory failure"); + return WOLFSSL_FAILURE; + } + sigDec = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sigDec == NULL) { + WOLFSSL_MSG("Memory failure"); + XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + /* get non-encrypted signature to be compared with decrypted signature */ + ret = wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, &len, rsa, 0); + if (ret <= 0) { + WOLFSSL_MSG("Message Digest Error"); + XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + show("Encoded Message", sigRet, len); + /* decrypt signature */ + ret = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen, + (RsaKey*)rsa->internal); + if (ret <= 0) { + WOLFSSL_MSG("RSA Decrypt error"); + XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + show("Decrypted Signature", sigDec, ret); + + if ((int)len == ret && XMEMCMP(sigRet, sigDec, ret) == 0) { + WOLFSSL_MSG("wolfSSL_RSA_verify success"); + XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } + else { + WOLFSSL_MSG("wolfSSL_RSA_verify failed"); + XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } +} + +void wolfSSL_RSA_get0_key(const WOLFSSL_RSA *r, const WOLFSSL_BIGNUM **n, + const WOLFSSL_BIGNUM **e, const WOLFSSL_BIGNUM **d) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_key"); + + if (r != NULL) { + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; + } else { + if (n != NULL) + *n = NULL; + if (e != NULL) + *e = NULL; + if (d != NULL) + *d = NULL; + } +} + +/* generate p-1 and q-1, WOLFSSL_SUCCESS on ok */ +int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa) +{ + int err; + mp_int tmp; + + WOLFSSL_MSG("wolfSSL_RsaGenAdd"); + + if (rsa == NULL || rsa->p == NULL || rsa->q == NULL || rsa->d == NULL || + rsa->dmp1 == NULL || rsa->dmq1 == NULL) { + WOLFSSL_MSG("rsa no init error"); + return WOLFSSL_FATAL_ERROR; + } + + if (mp_init(&tmp) != MP_OKAY) { + WOLFSSL_MSG("mp_init error"); + return WOLFSSL_FATAL_ERROR; + } + + err = mp_sub_d((mp_int*)rsa->p->internal, 1, &tmp); + if (err != MP_OKAY) { + WOLFSSL_MSG("mp_sub_d error"); + } + else + err = mp_mod((mp_int*)rsa->d->internal, &tmp, + (mp_int*)rsa->dmp1->internal); + + if (err != MP_OKAY) { + WOLFSSL_MSG("mp_mod error"); + } + else + err = mp_sub_d((mp_int*)rsa->q->internal, 1, &tmp); + if (err != MP_OKAY) { + WOLFSSL_MSG("mp_sub_d error"); + } + else + err = mp_mod((mp_int*)rsa->d->internal, &tmp, + (mp_int*)rsa->dmq1->internal); + + mp_clear(&tmp); + + if (err == MP_OKAY) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FATAL_ERROR; +} +#endif /* !NO_RSA && !HAVE_USER_RSA */ + +WOLFSSL_HMAC_CTX* wolfSSL_HMAC_CTX_new(void) +{ + return (WOLFSSL_HMAC_CTX*)XMALLOC(sizeof(WOLFSSL_HMAC_CTX), NULL, + DYNAMIC_TYPE_OPENSSL); +} + +int wolfSSL_HMAC_CTX_Init(WOLFSSL_HMAC_CTX* ctx) +{ + WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init"); + + if (ctx != NULL) { + /* wc_HmacSetKey sets up ctx->hmac */ + XMEMSET(ctx, 0, sizeof(WOLFSSL_HMAC_CTX)); + } + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_HMAC_Init_ex(WOLFSSL_HMAC_CTX* ctx, const void* key, + int keylen, const EVP_MD* type, WOLFSSL_ENGINE* e) +{ + WOLFSSL_ENTER("wolfSSL_HMAC_Init_ex"); + + /* WOLFSSL_ENGINE not used, call wolfSSL_HMAC_Init */ + (void)e; + return wolfSSL_HMAC_Init(ctx, key, keylen, type); +} + + +/* helper function for Deep copy of internal wolfSSL hmac structure + * returns WOLFSSL_SUCCESS on success */ +int wolfSSL_HmacCopy(Hmac* des, Hmac* src) +{ + void* heap; + +#ifndef HAVE_FIPS + heap = src->heap; +#else + heap = NULL; +#endif + if (wc_HmacInit(des, heap, 0) != 0) { + return WOLFSSL_FAILURE; + } + + /* requires that hash structures have no dynamic parts to them */ + switch (src->macType) { + #ifndef NO_MD5 + case WC_MD5: + wc_Md5Copy(&src->hash.md5, &des->hash.md5); + break; + #endif /* !NO_MD5 */ + + #ifndef NO_SHA + case WC_SHA: + wc_ShaCopy(&src->hash.sha, &des->hash.sha); + break; + #endif /* !NO_SHA */ + + #ifdef WOLFSSL_SHA224 + case WC_SHA224: + wc_Sha224Copy(&src->hash.sha224, &des->hash.sha224); + break; + #endif /* WOLFSSL_SHA224 */ + + #ifndef NO_SHA256 + case WC_SHA256: + wc_Sha256Copy(&src->hash.sha256, &des->hash.sha256); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + wc_Sha384Copy(&src->hash.sha384, &des->hash.sha384); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + wc_Sha512Copy(&src->hash.sha512, &des->hash.sha512); + break; + #endif /* WOLFSSL_SHA512 */ + + default: + return WOLFSSL_FAILURE; + } + + XMEMCPY((byte*)des->ipad, (byte*)src->ipad, WC_HMAC_BLOCK_SIZE); + XMEMCPY((byte*)des->opad, (byte*)src->opad, WC_HMAC_BLOCK_SIZE); + XMEMCPY((byte*)des->innerHash, (byte*)src->innerHash, WC_MAX_DIGEST_SIZE); +#ifndef HAVE_FIPS + des->heap = heap; +#endif + des->macType = src->macType; + des->innerHashKeyed = src->innerHashKeyed; + +#ifdef WOLFSSL_ASYNC_CRYPT + XMEMCPY(&des->asyncDev, &src->asyncDev, sizeof(WC_ASYNC_DEV)); + des->keyLen = src->keyLen; + #ifdef HAVE_CAVIUM + des->data = (byte*)XMALLOC(src->dataLen, des->heap, + DYNAMIC_TYPE_HMAC); + if (des->data == NULL) { + return BUFFER_E; + } + XMEMCPY(des->data, src->data, src->dataLen); + des->dataLen = src->dataLen; + #endif /* HAVE_CAVIUM */ +#endif /* WOLFSSL_ASYNC_CRYPT */ + return WOLFSSL_SUCCESS; +} + + +/* Deep copy of information from src to des structure + * + * des destination to copy information to + * src structure to get information from + * + * Returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error + */ +int wolfSSL_HMAC_CTX_copy(WOLFSSL_HMAC_CTX* des, WOLFSSL_HMAC_CTX* src) +{ + WOLFSSL_ENTER("wolfSSL_HMAC_CTX_copy"); + + if (des == NULL || src == NULL) { + return WOLFSSL_FAILURE; + } + + des->type = src->type; + XMEMCPY((byte *)&des->save_ipad, (byte *)&src->hmac.ipad, + WC_HMAC_BLOCK_SIZE); + XMEMCPY((byte *)&des->save_opad, (byte *)&src->hmac.opad, + WC_HMAC_BLOCK_SIZE); + + return wolfSSL_HmacCopy(&des->hmac, &src->hmac); +} + + +#if defined(HAVE_FIPS) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)) + +static int _HMAC_Init(Hmac* hmac, int type, void* heap) +{ + int ret = 0; + + switch (type) { + #ifndef NO_MD5 + case WC_MD5: + ret = wc_InitMd5(&hmac->hash.md5); + break; + #endif /* !NO_MD5 */ + + #ifndef NO_SHA + case WC_SHA: + ret = wc_InitSha(&hmac->hash.sha); + break; + #endif /* !NO_SHA */ + + #ifdef WOLFSSL_SHA224 + case WC_SHA224: + ret = wc_InitSha224(&hmac->hash.sha224); + break; + #endif /* WOLFSSL_SHA224 */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_InitSha256(&hmac->hash.sha256); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_InitSha384(&hmac->hash.sha384); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_InitSha512(&hmac->hash.sha512); + break; + #endif /* WOLFSSL_SHA512 */ + + #ifdef WOLFSSL_SHA3 + case WC_SHA3_224: + ret = wc_InitSha3_224(&hmac->hash.sha3, heap, INVALID_DEVID); + break; + case WC_SHA3_256: + ret = wc_InitSha3_256(&hmac->hash.sha3, heap, INVALID_DEVID); + break; + case WC_SHA3_384: + ret = wc_InitSha3_384(&hmac->hash.sha3, heap, INVALID_DEVID); + break; + case WC_SHA3_512: + ret = wc_InitSha3_512(&hmac->hash.sha3, heap, INVALID_DEVID); + break; + #endif + + default: + ret = BAD_FUNC_ARG; + break; + } + + (void)heap; + + return ret; +} + +#else + #define _HMAC_Init _InitHmac +#endif + + +int wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key, int keylen, + const EVP_MD* type) +{ + int hmac_error = 0; + void* heap = NULL; + + WOLFSSL_MSG("wolfSSL_HMAC_Init"); + + if (ctx == NULL) { + WOLFSSL_MSG("no ctx on init"); + return WOLFSSL_FAILURE; + } + +#ifndef HAVE_FIPS + heap = ctx->hmac.heap; +#endif + + if (type) { + WOLFSSL_MSG("init has type"); + +#ifndef NO_MD5 + if (XSTRNCMP(type, "MD5", 3) == 0) { + WOLFSSL_MSG("md5 hmac"); + ctx->type = WC_MD5; + } + else +#endif +#ifdef WOLFSSL_SHA224 + if (XSTRNCMP(type, "SHA224", 6) == 0) { + WOLFSSL_MSG("sha224 hmac"); + ctx->type = WC_SHA224; + } + else +#endif +#ifndef NO_SHA256 + if (XSTRNCMP(type, "SHA256", 6) == 0) { + WOLFSSL_MSG("sha256 hmac"); + ctx->type = WC_SHA256; + } + else +#endif +#ifdef WOLFSSL_SHA384 + if (XSTRNCMP(type, "SHA384", 6) == 0) { + WOLFSSL_MSG("sha384 hmac"); + ctx->type = WC_SHA384; + } + else +#endif +#ifdef WOLFSSL_SHA512 + if (XSTRNCMP(type, "SHA512", 6) == 0) { + WOLFSSL_MSG("sha512 hmac"); + ctx->type = WC_SHA512; + } + else +#endif + +#ifndef NO_SHA + /* has to be last since would pick or 256, 384, or 512 too */ + if (XSTRNCMP(type, "SHA", 3) == 0) { + WOLFSSL_MSG("sha hmac"); + ctx->type = WC_SHA; + } + else +#endif + { + WOLFSSL_MSG("bad init type"); + return WOLFSSL_FAILURE; + } + } + + if (key && keylen) { + WOLFSSL_MSG("keying hmac"); + + if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) { + hmac_error = wc_HmacSetKey(&ctx->hmac, ctx->type, (const byte*)key, + (word32)keylen); + if (hmac_error < 0){ + wc_HmacFree(&ctx->hmac); + return WOLFSSL_FAILURE; + } + XMEMCPY((byte *)&ctx->save_ipad, (byte *)&ctx->hmac.ipad, + WC_HMAC_BLOCK_SIZE); + XMEMCPY((byte *)&ctx->save_opad, (byte *)&ctx->hmac.opad, + WC_HMAC_BLOCK_SIZE); + } + /* OpenSSL compat, no error */ + } else if(ctx->type >= 0) { /* MD5 == 0 */ + WOLFSSL_MSG("recover hmac"); + wc_HmacFree(&ctx->hmac); + if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) { + ctx->hmac.macType = (byte)ctx->type; + ctx->hmac.innerHashKeyed = 0; + XMEMCPY((byte *)&ctx->hmac.ipad, (byte *)&ctx->save_ipad, + WC_HMAC_BLOCK_SIZE); + XMEMCPY((byte *)&ctx->hmac.opad, (byte *)&ctx->save_opad, + WC_HMAC_BLOCK_SIZE); + if ((hmac_error = _HMAC_Init(&ctx->hmac, ctx->hmac.macType, heap)) + !=0) { + return hmac_error; + } + } + } + + (void)hmac_error; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx, const unsigned char* data, + int len) +{ + int hmac_error = 0; + + WOLFSSL_MSG("wolfSSL_HMAC_Update"); + + if (ctx == NULL) { + WOLFSSL_MSG("no ctx"); + return WOLFSSL_FAILURE; + } + + if (data) { + WOLFSSL_MSG("updating hmac"); + hmac_error = wc_HmacUpdate(&ctx->hmac, data, (word32)len); + if (hmac_error < 0){ + WOLFSSL_MSG("hmac update error"); + return WOLFSSL_FAILURE; + } + } + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_HMAC_Final(WOLFSSL_HMAC_CTX* ctx, unsigned char* hash, + unsigned int* len) +{ + int hmac_error; + + WOLFSSL_MSG("wolfSSL_HMAC_Final"); + + /* "len" parameter is optional. */ + if (ctx == NULL || hash == NULL) { + WOLFSSL_MSG("invalid parameter"); + return WOLFSSL_FAILURE; + } + + WOLFSSL_MSG("final hmac"); + hmac_error = wc_HmacFinal(&ctx->hmac, hash); + if (hmac_error < 0){ + WOLFSSL_MSG("final hmac error"); + return WOLFSSL_FAILURE; + } + + if (len) { + WOLFSSL_MSG("setting output len"); + switch (ctx->type) { + #ifndef NO_MD5 + case WC_MD5: + *len = WC_MD5_DIGEST_SIZE; + break; + #endif + + #ifndef NO_SHA + case WC_SHA: + *len = WC_SHA_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA224 + case WC_SHA224: + *len = WC_SHA224_DIGEST_SIZE; + break; + #endif + + #ifndef NO_SHA256 + case WC_SHA256: + *len = WC_SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + *len = WC_SHA384_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + *len = WC_SHA512_DIGEST_SIZE; + break; + #endif + + default: + WOLFSSL_MSG("bad hmac type"); + return WOLFSSL_FAILURE; + } + } + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx) +{ + WOLFSSL_MSG("wolfSSL_HMAC_cleanup"); + + if (ctx) + wc_HmacFree(&ctx->hmac); + + return SSL_SUCCESS; +} + + +void wolfSSL_HMAC_CTX_free(WOLFSSL_HMAC_CTX* ctx) +{ + if (!ctx) { + return; + } + wolfSSL_HMAC_cleanup(ctx); + XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL); +} + +size_t wolfSSL_HMAC_size(const WOLFSSL_HMAC_CTX *ctx) +{ + if (!ctx) { + return 0; + } + + return (size_t)wc_HashGetDigestSize((enum wc_HashType)ctx->hmac.macType); +} + +#ifndef NO_DES3 + +void wolfSSL_3des_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset, + unsigned char* iv, int len) +{ + (void)len; + + WOLFSSL_MSG("wolfSSL_3des_iv"); + + if (ctx == NULL || iv == NULL) { + WOLFSSL_MSG("Bad function argument"); + return; + } + + if (doset) + wc_Des3_SetIV(&ctx->cipher.des3, iv); /* OpenSSL compat, no ret */ + else + XMEMCPY(iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE); +} + +#endif /* NO_DES3 */ + + +#ifndef NO_AES + +void wolfSSL_aes_ctr_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset, + unsigned char* iv, int len) +{ + (void)len; + + WOLFSSL_MSG("wolfSSL_aes_ctr_iv"); + + if (ctx == NULL || iv == NULL) { + WOLFSSL_MSG("Bad function argument"); + return; + } + + if (doset) + (void)wc_AesSetIV(&ctx->cipher.aes, iv); /* OpenSSL compat, no ret */ + else + XMEMCPY(iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); +} + +#endif /* NO_AES */ + + +/* Free the dynamically allocated data. + * + * p Pointer to dynamically allocated memory. + */ +void wolfSSL_OPENSSL_free(void* p) +{ + WOLFSSL_MSG("wolfSSL_OPENSSL_free"); + + XFREE(p, NULL, DYNAMIC_TYPE_OPENSSL); +} + +void *wolfSSL_OPENSSL_malloc(size_t a) +{ + return XMALLOC(a, NULL, DYNAMIC_TYPE_OPENSSL); +} + +#if defined(WOLFSSL_KEY_GEN) && defined(WOLFSSL_PEM_TO_DER) + +static int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher, + unsigned char* passwd, int passwdSz, byte **cipherInfo) +{ + int ret, paddingSz; + word32 idx, cipherInfoSz; +#ifdef WOLFSSL_SMALL_STACK + EncryptedInfo* info = NULL; +#else + EncryptedInfo info[1]; +#endif + + WOLFSSL_ENTER("EncryptDerKey"); + + if (der == NULL || derSz == NULL || cipher == NULL || + passwd == NULL || cipherInfo == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, + DYNAMIC_TYPE_ENCRYPTEDINFO); + if (info == NULL) { + WOLFSSL_MSG("malloc failed"); + return WOLFSSL_FAILURE; + } +#endif + + XMEMSET(info, 0, sizeof(EncryptedInfo)); + + /* set the cipher name on info */ + XSTRNCPY(info->name, cipher, NAME_SZ-1); + info->name[NAME_SZ-1] = '\0'; /* null term */ + + ret = wc_EncryptedInfoGet(info, info->name); + if (ret != 0) { + WOLFSSL_MSG("unsupported cipher"); + #ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); + #endif + return WOLFSSL_FAILURE; + } + + /* Generate a random salt */ + if (wolfSSL_RAND_bytes(info->iv, info->ivSz) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("generate iv failed"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); +#endif + return WOLFSSL_FAILURE; + } + + /* add the padding before encryption */ + paddingSz = ((*derSz)/info->ivSz + 1) * info->ivSz - (*derSz); + if (paddingSz == 0) + paddingSz = info->ivSz; + XMEMSET(der+(*derSz), (byte)paddingSz, paddingSz); + (*derSz) += paddingSz; + + /* encrypt buffer */ + if (wc_BufferKeyEncrypt(info, der, *derSz, passwd, passwdSz, WC_MD5) != 0) { + WOLFSSL_MSG("encrypt key failed"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); +#endif + return WOLFSSL_FAILURE; + } + + /* create cipher info : 'cipher_name,Salt(hex)' */ + cipherInfoSz = (word32)(2*info->ivSz + XSTRLEN(info->name) + 2); + *cipherInfo = (byte*)XMALLOC(cipherInfoSz, NULL, + DYNAMIC_TYPE_STRING); + if (*cipherInfo == NULL) { + WOLFSSL_MSG("malloc failed"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); +#endif + return WOLFSSL_FAILURE; + } + XSTRNCPY((char*)*cipherInfo, info->name, cipherInfoSz); + XSTRNCAT((char*)*cipherInfo, ",", 2); + + idx = (word32)XSTRLEN((char*)*cipherInfo); + cipherInfoSz -= idx; + ret = Base16_Encode(info->iv, info->ivSz, *cipherInfo+idx, &cipherInfoSz); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); +#endif + if (ret != 0) { + WOLFSSL_MSG("Base16_Encode failed"); + XFREE(*cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_KEY_GEN || WOLFSSL_PEM_TO_DER */ + +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA) +static int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey) +{ + int derSz = 0; + int ret; + byte* derBuf; + + WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); + + if (!rsa || (publicKey != 0 && publicKey != 1)) { + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + if (rsa->inSet == 0) { + if ((ret = SetRsaInternal(rsa)) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal() Failed"); + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); + return ret; + } + } + + if (publicKey) { + if ((derSz = wc_RsaPublicKeyDerSize((RsaKey *)rsa->internal, 1)) < 0) { + WOLFSSL_MSG("wc_RsaPublicKeyDerSize failed"); + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", derSz); + return derSz; + } + } + else { + if ((derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, NULL, 0)) < 0) { + WOLFSSL_MSG("wc_RsaKeyToDer failed"); + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", derSz); + return derSz; + } + } + + if (outBuf) { + if (!(derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER))) { + WOLFSSL_MSG("malloc failed"); + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", MEMORY_ERROR); + return MEMORY_ERROR; + } + + /* Key to DER */ + if (publicKey) { + derSz = wc_RsaKeyToPublicDer((RsaKey*)rsa->internal, derBuf, derSz); + } + else { + derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, derBuf, derSz); + } + + if (derSz < 0) { + WOLFSSL_MSG("wc_RsaKeyToPublicDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + else { + if (*outBuf) { + XMEMCPY(*outBuf, derBuf, derSz); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + else { + *outBuf = derBuf; + } + } + } + + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", derSz); + return derSz; +} +#endif + +#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && !defined(NO_RSA) + +/* Takes a WOLFSSL_RSA key and writes it out to a WOLFSSL_BIO + * + * bio the WOLFSSL_BIO to write to + * key the WOLFSSL_RSA key to write out + * cipher cipher used + * passwd password string if used + * len length of password string + * cb password callback to use + * arg null terminated string for passphrase + */ +int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* key, + const WOLFSSL_EVP_CIPHER* cipher, + unsigned char* passwd, int len, + pem_password_cb* cb, void* arg) +{ + int ret; + WOLFSSL_EVP_PKEY* pkey; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey"); + + if (bio == NULL || key == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return WOLFSSL_FAILURE; + } + + pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); + return WOLFSSL_FAILURE; + } + + pkey->type = EVP_PKEY_RSA; + pkey->rsa = key; + pkey->ownRsa = 0; +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA) + /* similar to how wolfSSL_PEM_write_mem_RSAPrivateKey finds DER of key */ + { + int derSz; + byte* derBuf = NULL; + + if ((derSz = wolfSSL_RSA_To_Der(key, &derBuf, 0)) < 0) { + WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); + return WOLFSSL_FAILURE; + } + + pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (pkey->pkey.ptr == NULL) { + WOLFSSL_MSG("key malloc failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + pkey->pkey_sz = derSz; + XMEMCPY(pkey->pkey.ptr, derBuf, derSz); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + + ret = wolfSSL_PEM_write_bio_PrivateKey(bio, pkey, cipher, passwd, len, + cb, arg); + + wolfSSL_EVP_PKEY_free(pkey); + + return ret; +} + +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA) +/* Takes an RSA public key and writes it out to a WOLFSSL_BIO + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa) +{ + int ret = 0, derSz = 0; + byte *derBuf = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSA_PUBKEY"); + + if (bio == NULL || rsa == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return WOLFSSL_FAILURE; + } + + /* Initialize pkey structure */ + pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); + return WOLFSSL_FAILURE; + } + + pkey->type = EVP_PKEY_RSA; + pkey->rsa = rsa; + pkey->ownRsa = 0; + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1)) < 0) { + WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); + return WOLFSSL_FAILURE; + } + + pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (pkey->pkey.ptr == NULL) { + WOLFSSL_MSG("key malloc failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + pkey->pkey_sz = derSz; + XMEMCPY(pkey->pkey.ptr, derBuf, derSz); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + ret = wolfSSL_PEM_write_bio_PUBKEY(bio, pkey); + wolfSSL_EVP_PKEY_free(pkey); + + return ret; +} +#endif + + +/* Reads an RSA public key from a WOLFSSL_BIO into a WOLFSSL_RSA + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +WOLFSSL_RSA *wolfSSL_PEM_read_bio_RSA_PUBKEY(WOLFSSL_BIO* bio,WOLFSSL_RSA** rsa, + pem_password_cb* cb, void *pass) +{ + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_RSA* local; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSA_PUBKEY"); + + pkey = wolfSSL_PEM_read_bio_PUBKEY(bio, NULL, cb, pass); + if (pkey == NULL) { + return NULL; + } + + /* Since the WOLFSSL_RSA structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_RSA structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownRsa = 0; + local = pkey->rsa; + if (rsa != NULL){ + *rsa = local; + } + + wolfSSL_EVP_PKEY_free(pkey); + return local; +} + +#endif /* defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) && !defined(NO_RSA) */ + +/* Takes a public key and writes it out to a WOLFSSL_BIO + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_PEM_write_bio_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) +{ + byte* keyDer; + int pemSz; + int ret; + byte* tmp; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PUBKEY"); + + if (bio == NULL || key == NULL) { + return WOLFSSL_FAILURE; + } + + keyDer = (byte*)key->pkey.ptr; + + pemSz = wc_DerToPem(keyDer, key->pkey_sz, NULL, 0, PUBLICKEY_TYPE); + if (pemSz < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PUBKEY", pemSz); + return WOLFSSL_FAILURE; + } + tmp = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (tmp == NULL) { + return MEMORY_E; + } + + ret = wc_DerToPemEx(keyDer, key->pkey_sz, tmp, pemSz, + NULL, PUBLICKEY_TYPE); + if (ret < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PUBKEY", ret); + XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); + return WOLFSSL_FAILURE; + } + + 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 WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* Takes a private key and writes it out to a WOLFSSL_BIO + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, + const WOLFSSL_EVP_CIPHER* cipher, + unsigned char* passwd, int len, + pem_password_cb* cb, void* arg) +{ + byte* keyDer; + int pemSz; + int type; + int ret; + byte* tmp; + + (void)cipher; + (void)passwd; + (void)len; + (void)cb; + (void)arg; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PrivateKey"); + + if (bio == NULL || key == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return WOLFSSL_FAILURE; + } + + keyDer = (byte*)key->pkey.ptr; + + switch (key->type) { +#ifndef NO_RSA + case EVP_PKEY_RSA: + type = PRIVATEKEY_TYPE; + break; +#endif + +#ifndef NO_DSA + case EVP_PKEY_DSA: + type = DSA_PRIVATEKEY_TYPE; + break; +#endif + +#ifdef HAVE_ECC + case EVP_PKEY_EC: + type = ECC_PRIVATEKEY_TYPE; + break; +#endif + +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) + case EVP_PKEY_DH: + type = DH_PRIVATEKEY_TYPE; + break; +#endif + + default: + WOLFSSL_MSG("Unknown Key type!"); + type = PRIVATEKEY_TYPE; + } + + pemSz = wc_DerToPem(keyDer, key->pkey_sz, NULL, 0, type); + if (pemSz < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", pemSz); + return WOLFSSL_FAILURE; + } + tmp = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (tmp == NULL) { + return MEMORY_E; + } + + ret = wc_DerToPemEx(keyDer, key->pkey_sz, tmp, pemSz, + NULL, type); + if (ret < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", ret); + XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); + return WOLFSSL_FAILURE; + } + + 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 WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) */ + +#if (defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA)) && \ + (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher, + unsigned char* passwd, int passwdSz, + unsigned char **pem, int *plen) +{ + byte *derBuf = NULL, *tmp, *cipherInfo = NULL; + int derSz = 0; + const int type = PRIVATEKEY_TYPE; + const char* header = NULL; + const char* footer = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey"); + + if (pem == NULL || plen == NULL || rsa == NULL || rsa->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + if (wc_PemGetHeaderFooter(type, &header, &footer) != 0) + return WOLFSSL_FAILURE; + + if (rsa->inSet == 0) { + WOLFSSL_MSG("No RSA internal set, do it"); + + if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return WOLFSSL_FAILURE; + } + } + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 0)) < 0) { + WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); + return WOLFSSL_FAILURE; + } + + /* encrypt DER buffer if required */ + if (passwd != NULL && passwdSz > 0 && cipher != NULL) { + int ret; + + ret = EncryptDerKey(derBuf, &derSz, cipher, + passwd, passwdSz, &cipherInfo); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("EncryptDerKey failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return ret; + } + + /* tmp buffer with a max size */ + *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE; + } + else { + /* tmp buffer with a max size */ + *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1; + } + + tmp = (byte*)XMALLOC(*plen, NULL, DYNAMIC_TYPE_PEM); + if (tmp == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + + /* DER to PEM */ + *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, type); + if (*plen <= 0) { + WOLFSSL_MSG("wc_DerToPemEx failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + + *pem = (byte*)XMALLOC((*plen)+1, NULL, DYNAMIC_TYPE_KEY); + if (*pem == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return WOLFSSL_FAILURE; + } + XMEMSET(*pem, 0, (*plen)+1); + + if (XMEMCPY(*pem, tmp, *plen) == NULL) { + WOLFSSL_MSG("XMEMCPY failed"); + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return WOLFSSL_FAILURE; + } + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa, + const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + byte *pem; + int plen, ret; + + (void)cb; + (void)u; + + WOLFSSL_MSG("wolfSSL_PEM_write_RSAPrivateKey"); + + if (fp == XBADFILE || rsa == NULL || rsa->internal == NULL) + { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, enc, kstr, klen, &pem, &plen); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); + return WOLFSSL_FAILURE; + } + + ret = (int)XFWRITE(pem, plen, 1, fp); + if (ret != 1) { + WOLFSSL_MSG("RSA private key file write failed"); + return WOLFSSL_FAILURE; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return WOLFSSL_SUCCESS; +} +#endif /* NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN && !NO_RSA && !HAVE_USER_RSA && WOLFSSL_PEM_TO_DER */ + + +#ifdef HAVE_ECC + +#ifdef ALT_ECC_SIZE +static int SetIndividualInternalEcc(WOLFSSL_BIGNUM* bn, mp_int* mpi) +{ + WOLFSSL_MSG("Entering SetIndividualInternal"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + if (mpi == NULL) { + WOLFSSL_MSG("mpi NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + if (mp_copy((mp_int*)bn->internal, mpi) != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + return WOLFSSL_FATAL_ERROR; + } + + return WOLFSSL_SUCCESS; +} +#endif /* ALT_ECC_SIZE */ + +/* EC_POINT Openssl -> WolfSSL */ +static int SetECPointInternal(WOLFSSL_EC_POINT *p) +{ + ecc_point* point; + WOLFSSL_ENTER("SetECPointInternal"); + + if (p == NULL || p->internal == NULL) { + WOLFSSL_MSG("ECPoint NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + point = (ecc_point*)p->internal; + +#ifndef ALT_ECC_SIZE + if (p->X != NULL && SetIndividualInternal(p->X, point->x) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point X error"); + return WOLFSSL_FATAL_ERROR; + } + + if (p->Y != NULL && SetIndividualInternal(p->Y, point->y) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point Y error"); + return WOLFSSL_FATAL_ERROR; + } + + if (p->Z != NULL && SetIndividualInternal(p->Z, point->z) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point Z error"); + return WOLFSSL_FATAL_ERROR; + } +#else + if (p->X != NULL && SetIndividualInternalEcc(p->X, point->x) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point X error"); + return WOLFSSL_FATAL_ERROR; + } + + if (p->Y != NULL && SetIndividualInternalEcc(p->Y, point->y) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point Y error"); + return WOLFSSL_FATAL_ERROR; + } + + if (p->Z != NULL && SetIndividualInternalEcc(p->Z, point->z) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point Z error"); + return WOLFSSL_FATAL_ERROR; + } +#endif + + p->inSet = 1; + + return WOLFSSL_SUCCESS; +} + +/* EC_POINT WolfSSL -> OpenSSL */ +static int SetECPointExternal(WOLFSSL_EC_POINT *p) +{ + ecc_point* point; + + WOLFSSL_ENTER("SetECPointExternal"); + + if (p == NULL || p->internal == NULL) { + WOLFSSL_MSG("ECPoint NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + point = (ecc_point*)p->internal; + + if (SetIndividualExternal(&p->X, point->x) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point X error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&p->Y, point->y) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point Y error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&p->Z, point->z) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ecc point Z error"); + return WOLFSSL_FATAL_ERROR; + } + + p->exSet = 1; + + return WOLFSSL_SUCCESS; +} + + +/* EC_KEY wolfSSL -> OpenSSL */ +int SetECKeyExternal(WOLFSSL_EC_KEY* eckey) +{ + ecc_key* key; + + WOLFSSL_ENTER("SetECKeyExternal"); + + if (eckey == NULL || eckey->internal == NULL) { + WOLFSSL_MSG("ec key NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + key = (ecc_key*)eckey->internal; + + /* set group (OID, nid and idx) */ + eckey->group->curve_oid = ecc_sets[key->idx].oidSum; + eckey->group->curve_nid = ecc_sets[key->idx].id; + eckey->group->curve_idx = key->idx; + + if (eckey->pub_key->internal != NULL) { + /* set the internal public key */ + if (wc_ecc_copy_point(&key->pubkey, + (ecc_point*)eckey->pub_key->internal) != MP_OKAY) { + WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed"); + return WOLFSSL_FATAL_ERROR; + } + + /* set the external pubkey (point) */ + if (SetECPointExternal(eckey->pub_key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyExternal SetECPointExternal failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + /* set the external privkey */ + if (key->type == ECC_PRIVATEKEY) { + if (SetIndividualExternal(&eckey->priv_key, &key->k) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ec priv key error"); + return WOLFSSL_FATAL_ERROR; + } + } + + eckey->exSet = 1; + + return WOLFSSL_SUCCESS; +} + +/* EC_KEY Openssl -> WolfSSL */ +int SetECKeyInternal(WOLFSSL_EC_KEY* eckey) +{ + ecc_key* key; + + WOLFSSL_ENTER("SetECKeyInternal"); + + if (eckey == NULL || eckey->internal == NULL || eckey->group == NULL) { + WOLFSSL_MSG("ec key NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + key = (ecc_key*)eckey->internal; + + /* validate group */ + if ((eckey->group->curve_idx < 0) || + (wc_ecc_is_valid_idx(eckey->group->curve_idx) == 0)) { + WOLFSSL_MSG("invalid curve idx"); + return WOLFSSL_FATAL_ERROR; + } + + /* set group (idx of curve and corresponding domain parameters) */ + key->idx = eckey->group->curve_idx; + key->dp = &ecc_sets[key->idx]; + + /* set pubkey (point) */ + if (eckey->pub_key != NULL) { + if (SetECPointInternal(eckey->pub_key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ec key pub error"); + return WOLFSSL_FATAL_ERROR; + } + + /* copy over the public point to key */ + if (wc_ecc_copy_point((ecc_point*)eckey->pub_key->internal, &key->pubkey) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + return WOLFSSL_FATAL_ERROR; + } + + /* public key */ + key->type = ECC_PUBLICKEY; + } + + /* set privkey */ + if (eckey->priv_key != NULL) { + if (SetIndividualInternal(eckey->priv_key, &key->k) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("ec key priv error"); + return WOLFSSL_FATAL_ERROR; + } + + /* private key */ + key->type = ECC_PRIVATEKEY; + } + + eckey->inSet = 1; + + return WOLFSSL_SUCCESS; +} + +WOLFSSL_EC_POINT *wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_public_key"); + + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_get0_public_key Bad arguments"); + return NULL; + } + + return key->pub_key; +} + +const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_group"); + + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_get0_group Bad arguments"); + return NULL; + } + + return key->group; +} + + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_EC_KEY_set_private_key(WOLFSSL_EC_KEY *key, + const WOLFSSL_BIGNUM *priv_key) +{ + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_private_key"); + + if (key == NULL || priv_key == NULL) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* free key if previously set */ + if (key->priv_key != NULL) + wolfSSL_BN_free(key->priv_key); + + key->priv_key = wolfSSL_BN_dup(priv_key); + if (key->priv_key == NULL) { + WOLFSSL_MSG("key ecc priv key NULL"); + return WOLFSSL_FAILURE; + } + + if (SetECKeyInternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + wolfSSL_BN_free(key->priv_key); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + + +WOLFSSL_BIGNUM *wolfSSL_EC_KEY_get0_private_key(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_private_key"); + + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_get0_private_key Bad arguments"); + return NULL; + } + + if (wolfSSL_BN_is_zero(key->priv_key)) { + /* return NULL if not set */ + return NULL; + } + + return key->priv_key; +} + +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_by_curve_name(int nid) +{ + WOLFSSL_EC_KEY *key; + int x; + int eccEnum; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name"); + + /* If NID passed in is OpenSSL type, convert it to ecc_curve_id enum */ + eccEnum = NIDToEccEnum(nid); + if (eccEnum == -1) + eccEnum = nid; + + key = wolfSSL_EC_KEY_new(); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new failure"); + return NULL; + } + + /* set the nid of the curve */ + key->group->curve_nid = eccEnum; + + /* search and set the corresponding internal curve idx */ + for (x = 0; ecc_sets[x].size != 0; x++) + if (ecc_sets[x].id == key->group->curve_nid) { + key->group->curve_idx = x; + key->group->curve_oid = ecc_sets[x].oidSum; + break; + } + + return key; +} + +const char* wolfSSL_EC_curve_nid2nist(int nid) +{ + const WOLF_EC_NIST_NAME* nist_name; + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (nist_name->nid == nid) { + return kNistCurves->name; + } + } + return NULL; +} + +#ifdef WOLFSSL_TLS13 +static int populate_groups(int* groups, int max_count, char *list) +{ + char *end; + int len; + int count = 0; + const WOLF_EC_NIST_NAME* nist_name; + + if (!groups || !list) { + return -1; + } + + for (end = list; ; list = ++end) { + if (count > max_count) { + WOLFSSL_MSG("Too many curves in list"); + return -1; + } + while (*end != ':' && *end != '\0') end++; + len = (int)(end - list); /* end points to char after end + * of curve name so no need for -1 */ + if ((len < kNistCurves_MIN_NAME_LEN) || + (len > kNistCurves_MAX_NAME_LEN)) { + WOLFSSL_MSG("Unrecognized curve name in list"); + return -1; + } + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (len == nist_name->name_len && + XSTRNCMP(list, nist_name->name, nist_name->name_len) == 0) { + break; + } + } + if (!nist_name->name) { + WOLFSSL_MSG("Unrecognized curve name in list"); + return -1; + } + groups[count++] = nist_name->nid; + if (*end == '\0') break; + } + + return count; +} + +int wolfSSL_CTX_set1_groups_list(WOLFSSL_CTX *ctx, char *list) +{ + int groups[WOLFSSL_MAX_GROUP_COUNT]; + int count; + + if (!ctx || !list) { + return WOLFSSL_FAILURE; + } + + if ((count = populate_groups(groups, + WOLFSSL_MAX_GROUP_COUNT, list)) == -1) { + return WOLFSSL_FAILURE; + } + + return wolfSSL_CTX_set_groups(ctx, groups, count) == WOLFSSL_SUCCESS ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +} + +int wolfSSL_set1_groups_list(WOLFSSL *ssl, char *list) +{ + int groups[WOLFSSL_MAX_GROUP_COUNT]; + int count; + + if (!ssl || !list) { + return WOLFSSL_FAILURE; + } + + if ((count = populate_groups(groups, + WOLFSSL_MAX_GROUP_COUNT, list)) == -1) { + return WOLFSSL_FAILURE; + } + + return wolfSSL_set_groups(ssl, groups, count) == WOLFSSL_SUCCESS ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +} +#endif /* WOLFSSL_TLS13 */ + +static void InitwolfSSL_ECKey(WOLFSSL_EC_KEY* key) +{ + if (key) { + key->group = NULL; + key->pub_key = NULL; + key->priv_key = NULL; + key->internal = NULL; + key->inSet = 0; + key->exSet = 0; + } +} + +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void) +{ + WOLFSSL_EC_KEY *external; + WOLFSSL_ENTER("wolfSSL_EC_KEY_new"); + + external = (WOLFSSL_EC_KEY*)XMALLOC(sizeof(WOLFSSL_EC_KEY), NULL, + DYNAMIC_TYPE_ECC); + if (external == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure"); + return NULL; + } + XMEMSET(external, 0, sizeof(WOLFSSL_EC_KEY)); + + InitwolfSSL_ECKey(external); + + external->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, + DYNAMIC_TYPE_ECC); + if (external->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc ecc key failure"); + goto error; + } + XMEMSET(external->internal, 0, sizeof(ecc_key)); + + if (wc_ecc_init((ecc_key*)external->internal) != 0) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new init ecc key failure"); + goto error; + } + + /* curve group */ + external->group = wolfSSL_EC_GROUP_new_by_curve_name(ECC_CURVE_DEF); + if (external->group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_GROUP failure"); + goto error; + } + + /* public key */ + external->pub_key = wolfSSL_EC_POINT_new(external->group); + if (external->pub_key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new failure"); + goto error; + } + + /* private key */ + external->priv_key = wolfSSL_BN_new(); + if (external->priv_key == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new failure"); + goto error; + } + + return external; +error: + wolfSSL_EC_KEY_free(external); + return NULL; +} + +void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) +{ + WOLFSSL_ENTER("wolfSSL_EC_KEY_free"); + + if (key != NULL) { + if (key->internal != NULL) { + wc_ecc_free((ecc_key*)key->internal); + XFREE(key->internal, NULL, DYNAMIC_TYPE_ECC); + } + wolfSSL_BN_free(key->priv_key); + wolfSSL_EC_POINT_free(key->pub_key); + wolfSSL_EC_GROUP_free(key->group); + InitwolfSSL_ECKey(key); /* set back to NULLs for safety */ + + XFREE(key, NULL, DYNAMIC_TYPE_ECC); + /* key = NULL, don't try to access or double free it */ + } +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group) +{ + (void)key; + (void)group; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group"); + WOLFSSL_STUB("EC_KEY_set_group"); + + return -1; +} +#endif + +int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key) +{ + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_EC_KEY_generate_key"); + + if (key == NULL || key->internal == NULL || + key->group == NULL || key->group->curve_idx < 0) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key Bad arguments"); + return 0; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return 0; +#endif + + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to set RNG"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + return 0; + } + + if (wc_ecc_make_key_ex(rng, 0, (ecc_key*)key->internal, + key->group->curve_nid) != MP_OKAY) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + return 0; + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + if (SetECKeyExternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key SetECKeyExternal failed"); + return 0; + } + + return 1; +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag) +{ + (void)key; + (void)asn1_flag; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag"); + WOLFSSL_STUB("EC_KEY_set_asn1_flag"); +} +#endif + +static int setupPoint(const WOLFSSL_EC_POINT *p) { + if (!p) { + return WOLFSSL_FAILURE; + } + if (p->inSet == 0) { + WOLFSSL_MSG("No ECPoint internal set, do it"); + + if (SetECPointInternal((WOLFSSL_EC_POINT *)p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECPointInternal SetECPointInternal failed"); + return WOLFSSL_FAILURE; + } + } + return WOLFSSL_SUCCESS; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_EC_KEY_set_public_key(WOLFSSL_EC_KEY *key, + const WOLFSSL_EC_POINT *pub) +{ + ecc_point *pub_p, *key_p; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_public_key"); + + if (key == NULL || key->internal == NULL || + pub == NULL || pub->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad arguments"); + return WOLFSSL_FAILURE; + } + + if (key->inSet == 0) { + if (SetECKeyInternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + return WOLFSSL_FAILURE; + } + } + + if (setupPoint(pub) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + pub_p = (ecc_point*)pub->internal; + key_p = (ecc_point*)key->pub_key->internal; + + /* create new point if required */ + if (key_p == NULL) + key_p = wc_ecc_new_point(); + + if (key_p == NULL) { + WOLFSSL_MSG("key ecc point NULL"); + return WOLFSSL_FAILURE; + } + + if (wc_ecc_copy_point(pub_p, key_p) != MP_OKAY) { + WOLFSSL_MSG("ecc_copy_point failure"); + return WOLFSSL_FAILURE; + } + + if (SetECPointExternal(key->pub_key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + return WOLFSSL_FAILURE; + } + + if (SetECKeyInternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + return WOLFSSL_FAILURE; + } + + wolfSSL_EC_POINT_dump("pub", pub); + wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key); + + return WOLFSSL_SUCCESS; +} +/* End EC_KEY */ + +int wolfSSL_ECDSA_size(const WOLFSSL_EC_KEY *key) +{ + const EC_GROUP *group; + int bits, bytes; + word32 headerSz = 4; /* 2*ASN_TAG + 2*LEN(ENUM) */ + + if (!key) { + return WOLFSSL_FAILURE; + } + + if (!(group = wolfSSL_EC_KEY_get0_group(key))) { + return WOLFSSL_FAILURE; + } + if ((bits = wolfSSL_EC_GROUP_order_bits(group)) == 0) { + return WOLFSSL_FAILURE; + } + bytes = (bits + 7) / 8; /* bytes needed to hold bits */ + return headerSz + + 2 + /* possible leading zeroes in r and s */ + bytes + bytes + /* r and s */ + 2; +} + +int wolfSSL_ECDSA_sign(int type, const unsigned char *digest, + int digestSz, unsigned char *sig, + unsigned int *sigSz, WOLFSSL_EC_KEY *key) +{ + int ret = WOLFSSL_SUCCESS; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + int initTmpRng = 0; + + WOLFSSL_ENTER("wolfSSL_ECDSA_sign"); + + if (!key) { + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FAILURE; +#endif + + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) { + WOLFSSL_MSG("Global RNG no Init"); + } + else { + rng = &globalRNG; + } + } + if (rng) { + if (wc_ecc_sign_hash(digest, digestSz, sig, sigSz, rng, (ecc_key*)key->internal) != MP_OKAY) { + ret = WOLFSSL_FAILURE; + } + if (initTmpRng) { + wc_FreeRng(tmpRNG); + } + } else { + ret = WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + if (tmpRNG) + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + (void)type; + return ret; +} + +#ifndef HAVE_SELFTEST +/* ECC point compression types were not included in selftest ecc.h */ + +char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, int form, + WOLFSSL_BN_CTX* ctx) +{ + static const char* hexDigit = "0123456789ABCDEF"; + char* hex = NULL; + int id; + int i, sz, len; + + (void)ctx; + + if (group == NULL || point == NULL) + return NULL; + + id = wc_ecc_get_curve_id(group->curve_idx); + + if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0) + return NULL; + + len = sz + 1; + if (form == POINT_CONVERSION_UNCOMPRESSED) + len += sz; + + hex = (char*)XMALLOC(2 * len + 1, NULL, DYNAMIC_TYPE_ECC); + if (hex == NULL) + return NULL; + XMEMSET(hex, 0, 2 * len + 1); + + /* Put in x-ordinate after format byte. */ + i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1; + if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) < 0) { + XFREE(hex, NULL, DYNAMIC_TYPE_ECC); + return NULL; + } + + if (form == POINT_CONVERSION_COMPRESSED) { + hex[0] = mp_isodd((mp_int*)point->Y->internal) ? ECC_POINT_COMP_ODD : + ECC_POINT_COMP_EVEN; + } + else { + hex[0] = ECC_POINT_UNCOMP; + /* Put in y-ordinate after x-ordinate */ + i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal); + if (mp_to_unsigned_bin((mp_int*)point->Y->internal, + (byte*)(hex + i)) < 0) { + XFREE(hex, NULL, DYNAMIC_TYPE_ECC); + return NULL; + } + } + + for (i = len-1; i >= 0; i--) { + byte b = hex[i]; + hex[i * 2 + 1] = hexDigit[b & 0xf]; + hex[i * 2 ] = hexDigit[b >> 4]; + } + + return hex; +} + +#endif /* HAVE_SELFTEST */ + +void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *p) +{ +#if defined(DEBUG_WOLFSSL) + char *num; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_dump"); + + if (!WOLFSSL_IS_DEBUG_ON() || wolfSSL_GetLoggingCb()) { + return; + } + + if (p == NULL) { + printf("%s = NULL", msg); + return; + } + + printf("%s:\n\tinSet=%d, exSet=%d\n", msg, p->inSet, p->exSet); + num = wolfSSL_BN_bn2hex(p->X); + printf("\tX = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_ECC); + num = wolfSSL_BN_bn2hex(p->Y); + printf("\tY = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_ECC); + num = wolfSSL_BN_bn2hex(p->Z); + printf("\tZ = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_ECC); +#else + (void)msg; + (void)p; +#endif +} + +/* Start EC_GROUP */ + +/* return code compliant with OpenSSL : + * 0 if equal, 1 if not and -1 in case of error + */ +int wolfSSL_EC_GROUP_cmp(const WOLFSSL_EC_GROUP *a, const WOLFSSL_EC_GROUP *b, + WOLFSSL_BN_CTX *ctx) +{ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_cmp"); + + if (a == NULL || b == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_cmp Bad arguments"); + return WOLFSSL_FATAL_ERROR; + } + + /* ok */ + if ((a->curve_idx == b->curve_idx) && (a->curve_nid == b->curve_nid)) + return 0; + + /* ko */ + return 1; +} + +#endif /* HAVE_ECC */ +#endif /* OPENSSL_EXTRA */ + +#if defined(HAVE_ECC) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +const WOLFSSL_EC_METHOD* wolfSSL_EC_GROUP_method_of( + const WOLFSSL_EC_GROUP *group) +{ + return group; +} + +int wolfSSL_EC_METHOD_get_field_type(const WOLFSSL_EC_METHOD *meth) +{ + if (meth) { + return NID_X9_62_prime_field; + } + return WOLFSSL_FAILURE; +} + +void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group) +{ + WOLFSSL_ENTER("wolfSSL_EC_GROUP_free"); + + XFREE(group, NULL, DYNAMIC_TYPE_ECC); + /* group = NULL, don't try to access or double free it */ +} +#endif + +#ifdef OPENSSL_EXTRA +#ifdef HAVE_ECC +#ifndef NO_WOLFSSL_STUB +void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag) +{ + (void)group; + (void)flag; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag"); + WOLFSSL_STUB("EC_GROUP_set_asn1_flag"); +} +#endif + +WOLFSSL_EC_GROUP *wolfSSL_EC_GROUP_new_by_curve_name(int nid) +{ + WOLFSSL_EC_GROUP *g; + int x; + int eccEnum; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_new_by_curve_name"); + + /* If NID passed in is OpenSSL type, convert it to ecc_curve_id enum */ + eccEnum = NIDToEccEnum(nid); + if (eccEnum == -1) + eccEnum = nid; + + + /* curve group */ + g = (WOLFSSL_EC_GROUP*) XMALLOC(sizeof(WOLFSSL_EC_GROUP), NULL, + DYNAMIC_TYPE_ECC); + if (g == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_new_by_curve_name malloc failure"); + return NULL; + } + XMEMSET(g, 0, sizeof(WOLFSSL_EC_GROUP)); + + /* set the nid of the curve */ + g->curve_nid = eccEnum; + + if (eccEnum > ECC_CURVE_DEF) { + /* search and set the corresponding internal curve idx */ + for (x = 0; ecc_sets[x].size != 0; x++) + if (ecc_sets[x].id == g->curve_nid) { + g->curve_idx = x; + g->curve_oid = ecc_sets[x].oidSum; + break; + } + } + + return g; +} + +/* return code compliant with OpenSSL : + * the curve nid if success, 0 if error + */ +int wolfSSL_EC_GROUP_get_curve_name(const WOLFSSL_EC_GROUP *group) +{ + int nid; + WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_curve_name"); + + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* If curve_nid is ECC Enum type, return corresponding OpenSSL nid */ + if ((nid = EccEnumToNID(group->curve_nid)) != -1) + return nid; + + return group->curve_nid; +} + +/* return code compliant with OpenSSL : + * the degree of the curve if success, 0 if error + */ +int wolfSSL_EC_GROUP_get_degree(const WOLFSSL_EC_GROUP *group) +{ + int nid; + int tmp; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_degree"); + + if (group == NULL || group->curve_idx < 0) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_degree Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* If curve_nid passed in is an ecc_curve_id enum, convert it to the + corresponding OpenSSL NID */ + tmp = EccEnumToNID(group->curve_nid); + if (tmp != -1){ + nid = tmp; + } + else{ + nid = group->curve_nid; + } + + switch(nid) { + case NID_secp112r1: + case NID_secp112r2: + return 112; + case NID_secp128r1: + case NID_secp128r2: + return 128; + case NID_secp160k1: + case NID_secp160r1: + case NID_secp160r2: + case NID_brainpoolP160r1: + return 160; + case NID_secp192k1: + case NID_brainpoolP192r1: + case NID_X9_62_prime192v1: + return 192; + case NID_secp224k1: + case NID_secp224r1: + case NID_brainpoolP224r1: + return 224; + case NID_secp256k1: + case NID_brainpoolP256r1: + case NID_X9_62_prime256v1: + return 256; + case NID_brainpoolP320r1: + return 320; + case NID_secp384r1: + case NID_brainpoolP384r1: + return 384; + case NID_secp521r1: + return 521; + case NID_brainpoolP512r1: + return 512; + default: + return WOLFSSL_FAILURE; + } +} + +/* Converts OpenSSL NID value of ECC curves to the associated enum values in + ecc_curve_id, used by ecc_sets[].*/ +int NIDToEccEnum(int n) +{ + WOLFSSL_ENTER("NIDToEccEnum()"); + + switch(n) { + case NID_X9_62_prime192v1: + return ECC_SECP192R1; + case NID_X9_62_prime192v2: + return ECC_PRIME192V2; + case NID_X9_62_prime192v3: + return ECC_PRIME192V3; + case NID_X9_62_prime239v1: + return ECC_PRIME239V1; + case NID_X9_62_prime239v2: + return ECC_PRIME239V2; + case NID_X9_62_prime239v3: + return ECC_PRIME239V3; + case NID_X9_62_prime256v1: + return ECC_SECP256R1; + case NID_secp112r1: + return ECC_SECP112R1; + case NID_secp112r2: + return ECC_SECP112R2; + case NID_secp128r1: + return ECC_SECP128R1; + case NID_secp128r2: + return ECC_SECP128R2; + case NID_secp160r1: + return ECC_SECP160R1; + case NID_secp160r2: + return ECC_SECP160R2; + case NID_secp224r1: + return ECC_SECP224R1; + case NID_secp384r1: + return ECC_SECP384R1; + case NID_secp521r1: + return ECC_SECP521R1; + case NID_secp160k1: + return ECC_SECP160K1; + case NID_secp192k1: + return ECC_SECP192K1; + case NID_secp224k1: + return ECC_SECP224K1; + case NID_secp256k1: + return ECC_SECP256K1; + case NID_brainpoolP160r1: + return ECC_BRAINPOOLP160R1; + case NID_brainpoolP192r1: + return ECC_BRAINPOOLP192R1; + case NID_brainpoolP224r1: + return ECC_BRAINPOOLP224R1; + case NID_brainpoolP256r1: + return ECC_BRAINPOOLP256R1; + case NID_brainpoolP320r1: + return ECC_BRAINPOOLP320R1; + case NID_brainpoolP384r1: + return ECC_BRAINPOOLP384R1; + case NID_brainpoolP512r1: + return ECC_BRAINPOOLP512R1; + default: + WOLFSSL_MSG("NID not found"); + return -1; + } +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_EC_GROUP_get_order(const WOLFSSL_EC_GROUP *group, + WOLFSSL_BIGNUM *order, WOLFSSL_BN_CTX *ctx) +{ + (void)ctx; + + if (group == NULL || order == NULL || order->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_init((mp_int*)order->internal) != MP_OKAY) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_init failure"); + return WOLFSSL_FAILURE; + } + + if (mp_read_radix((mp_int*)order->internal, + ecc_sets[group->curve_idx].order, MP_RADIX_HEX) != MP_OKAY) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure"); + mp_clear((mp_int*)order->internal); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_EC_GROUP_order_bits(const WOLFSSL_EC_GROUP *group) +{ + int ret; + mp_int order; + + if (group == NULL || group->curve_idx < 0) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_order_bits NULL error"); + return 0; + } + + ret = mp_init(&order); + if (ret == 0) { + ret = mp_read_radix(&order, ecc_sets[group->curve_idx].order, + MP_RADIX_HEX); + if (ret == 0) + ret = mp_count_bits(&order); + mp_clear(&order); + } + + return ret; +} + +/* End EC_GROUP */ + +/* Start EC_POINT */ + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *p, + unsigned char *out, unsigned int *len) +{ + int err; + + WOLFSSL_ENTER("wolfSSL_ECPoint_i2d"); + + if (group == NULL || p == NULL || len == NULL) { + WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error"); + return WOLFSSL_FAILURE; + } + + if (setupPoint(p) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + if (out != NULL) { + wolfSSL_EC_POINT_dump("i2d p", p); + } + + err = wc_ecc_export_point_der(group->curve_idx, (ecc_point*)p->internal, + out, len); + if (err != MP_OKAY && !(out == NULL && err == LENGTH_ONLY_E)) { + WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_ECPoint_d2i(unsigned char *in, unsigned int len, + const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *p) +{ + WOLFSSL_ENTER("wolfSSL_ECPoint_d2i"); + + if (group == NULL || p == NULL || p->internal == NULL || in == NULL) { + WOLFSSL_MSG("wolfSSL_ECPoint_d2i NULL error"); + return WOLFSSL_FAILURE; + } + +#ifndef HAVE_SELFTEST + if (wc_ecc_import_point_der_ex(in, len, group->curve_idx, + (ecc_point*)p->internal, 0) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_import_point_der_ex failed"); + return WOLFSSL_FAILURE; + } +#else + /* ECC_POINT_UNCOMP is not defined CAVP self test so use magic number */ + if (in[0] == 0x04) { + if (wc_ecc_import_point_der(in, len, group->curve_idx, + (ecc_point*)p->internal) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_import_point_der failed"); + return WOLFSSL_FAILURE; + } + } + else { + WOLFSSL_MSG("Only uncompressed points supported with HAVE_SELFTEST"); + return WOLFSSL_FAILURE; + } +#endif + + /* Set new external point */ + if (SetECPointExternal(p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECPointExternal failed"); + return WOLFSSL_FAILURE; + } + + wolfSSL_EC_POINT_dump("d2i p", p); + + return WOLFSSL_SUCCESS; +} + +size_t wolfSSL_EC_POINT_point2oct(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *p, + char form, + byte *buf, size_t len, WOLFSSL_BN_CTX *ctx) +{ + word32 min_len = (word32)len; +#ifndef HAVE_SELFTEST + int compressed = form == POINT_CONVERSION_COMPRESSED ? 1 : 0; +#endif /* !HAVE_SELFTEST */ + + WOLFSSL_ENTER("EC_POINT_point2oct"); + + if (!group || !p) { + return WOLFSSL_FAILURE; + } + + if (setupPoint(p) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_EC_POINT_is_at_infinity(group, p)) { + /* encodes to a single 0 octet */ + if (buf != NULL) { + if (len < 1) { + ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); + return WOLFSSL_FAILURE; + } + buf[0] = 0; + } + return 1; + } + + if (form != POINT_CONVERSION_UNCOMPRESSED +#ifndef HAVE_SELFTEST + && form != POINT_CONVERSION_COMPRESSED +#endif /* !HAVE_SELFTEST */ + ) { + WOLFSSL_MSG("Unsupported curve form"); + return WOLFSSL_FAILURE; + } + +#ifndef HAVE_SELFTEST + if (wc_ecc_export_point_der_ex(group->curve_idx, (ecc_point*)p->internal, + buf, &min_len, compressed) != (buf ? MP_OKAY : LENGTH_ONLY_E)) { + return WOLFSSL_FAILURE; + } +#else + if (wc_ecc_export_point_der(group->curve_idx, (ecc_point*)p->internal, + buf, &min_len) != (buf ? MP_OKAY : LENGTH_ONLY_E)) { + return WOLFSSL_FAILURE; + } +#endif /* !HAVE_SELFTEST */ + + (void)ctx; + + return (size_t)min_len; +} + +int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *p, const unsigned char *buf, + size_t len, WOLFSSL_BN_CTX *ctx) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); + + if (!group || !p) { + return WOLFSSL_FAILURE; + } + + (void)ctx; + + return wolfSSL_ECPoint_d2i((unsigned char*)buf, (unsigned int)len, group, p); +} + +int wolfSSL_i2o_ECPublicKey(const WOLFSSL_EC_KEY *in, unsigned char **out) +{ + size_t len; + unsigned char *tmp = NULL; + char form; + WOLFSSL_ENTER("wolfSSL_i2o_ECPublicKey"); + + if (!in) { + WOLFSSL_MSG("wolfSSL_i2o_ECPublicKey Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* Default to compressed form if not set */ + form = in->form == POINT_CONVERSION_UNCOMPRESSED ? + POINT_CONVERSION_UNCOMPRESSED: + POINT_CONVERSION_COMPRESSED; + + len = wolfSSL_EC_POINT_point2oct(in->group, in->pub_key, form, + NULL, 0, NULL); + + if (len != WOLFSSL_FAILURE && out) { + if (!*out) { + if (!(tmp = (unsigned char*)XMALLOC(len, NULL, + DYNAMIC_TYPE_OPENSSL))) { + WOLFSSL_MSG("malloc failed"); + return WOLFSSL_FAILURE; + } + *out = tmp; + } + + if (wolfSSL_EC_POINT_point2oct(in->group, in->pub_key, form, *out, + len, NULL) == WOLFSSL_FAILURE) { + if (tmp) { + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + *out = NULL; + } + return WOLFSSL_FAILURE; + } + + if (!tmp) { + /* Move buffer forward if it was not alloced in this function */ + *out += len; + } + } + + return (int)len; +} + +void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *eckey, char form) +{ + if (eckey && (form == POINT_CONVERSION_COMPRESSED || + form == POINT_CONVERSION_UNCOMPRESSED)) { + eckey->form = form; + } +} + + +/* wolfSSL_EC_POINT_point2bn should return "in" if not null */ +WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *p, + char form, + WOLFSSL_BIGNUM *in, WOLFSSL_BN_CTX *ctx) +{ + size_t len; + byte *buf; + WOLFSSL_BIGNUM *ret = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); + + if (!group || !p) { + return NULL; + } + + if ((len = wolfSSL_EC_POINT_point2oct(group, p, form, + NULL, 0, ctx)) == WOLFSSL_FAILURE) { + return NULL; + } + + if (!(buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER))) { + WOLFSSL_MSG("malloc failed"); + return NULL; + } + + if (wolfSSL_EC_POINT_point2oct(group, p, form, + buf, len, ctx) == len) { + ret = wolfSSL_BN_bin2bn(buf, (int)len, in); + } + + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +WOLFSSL_EC_POINT *wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP *group) +{ + WOLFSSL_EC_POINT *p; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_new"); + + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new NULL error"); + return NULL; + } + + p = (WOLFSSL_EC_POINT *)XMALLOC(sizeof(WOLFSSL_EC_POINT), NULL, + DYNAMIC_TYPE_ECC); + if (p == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new malloc ecc point failure"); + return NULL; + } + XMEMSET(p, 0, sizeof(WOLFSSL_EC_POINT)); + + p->internal = wc_ecc_new_point(); + if (p->internal == NULL) { + WOLFSSL_MSG("ecc_new_point failure"); + XFREE(p, NULL, DYNAMIC_TYPE_ECC); + return NULL; + } + + return p; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_EC_POINT_get_affine_coordinates_GFp(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, + WOLFSSL_BIGNUM *x, + WOLFSSL_BIGNUM *y, + WOLFSSL_BN_CTX *ctx) +{ + mp_digit mp; + mp_int modulus; + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_get_affine_coordinates_GFp"); + + if (group == NULL || point == NULL || point->internal == NULL || + x == NULL || y == NULL || wolfSSL_EC_POINT_is_at_infinity(group, point)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp NULL error"); + return WOLFSSL_FAILURE; + } + + if (setupPoint(point) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + if (!wolfSSL_BN_is_one(point->Z)) { + if (mp_init(&modulus) != MP_OKAY) { + WOLFSSL_MSG("mp_init failed"); + return WOLFSSL_FAILURE; + } + /* Map the Jacobian point back to affine space */ + if (mp_read_radix(&modulus, ecc_sets[group->curve_idx].prime, MP_RADIX_HEX) != MP_OKAY) { + WOLFSSL_MSG("mp_read_radix failed"); + mp_clear(&modulus); + return WOLFSSL_FAILURE; + } + if (mp_montgomery_setup(&modulus, &mp) != MP_OKAY) { + WOLFSSL_MSG("mp_montgomery_setup failed"); + mp_clear(&modulus); + return WOLFSSL_FAILURE; + } + if (ecc_map((ecc_point*)point->internal, &modulus, mp) != MP_OKAY) { + WOLFSSL_MSG("ecc_map failed"); + mp_clear(&modulus); + return WOLFSSL_FAILURE; + } + if (SetECPointExternal((WOLFSSL_EC_POINT *)point) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECPointExternal failed"); + mp_clear(&modulus); + return WOLFSSL_FAILURE; + } + } + + BN_copy(x, point->X); + BN_copy(y, point->Y); + mp_clear(&modulus); + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point, + const WOLFSSL_BIGNUM *x, + const WOLFSSL_BIGNUM *y, + WOLFSSL_BN_CTX *ctx) +{ + (void)ctx; + WOLFSSL_ENTER("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); + + if (group == NULL || point == NULL || point->internal == NULL || + x == NULL || y == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp NULL error"); + return WOLFSSL_FAILURE; + } + + if (!point->X) { + point->X = wolfSSL_BN_new(); + } + if (!point->Y) { + point->Y = wolfSSL_BN_new(); + } + if (!point->Z) { + point->Z = wolfSSL_BN_new(); + } + if (!point->X || !point->Y || !point->Z) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + return WOLFSSL_FAILURE; + } + + BN_copy(point->X, x); + BN_copy(point->Y, y); + BN_copy(point->Z, wolfSSL_BN_value_one()); + + if (SetECPointInternal((WOLFSSL_EC_POINT *)point) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECPointInternal failed"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +#if !defined(WOLFSSL_ATECC508A) && !defined(HAVE_SELFTEST) +/* Calculate the value: generator * n + q * m + * return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_EC_POINT_mul(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r, + const WOLFSSL_BIGNUM *n, const WOLFSSL_EC_POINT *q, + const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx) +{ + mp_int a, prime; + int ret = WOLFSSL_FAILURE; + ecc_point* result = NULL; + ecc_point* tmp = NULL; + + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_mul"); + + if (!group || !r) { + WOLFSSL_MSG("wolfSSL_EC_POINT_mul NULL error"); + return WOLFSSL_FAILURE; + } + + if (!(result = wc_ecc_new_point())) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new error"); + return WOLFSSL_FAILURE; + } + + /* read the curve prime and a */ + if (mp_init_multi(&prime, &a, NULL, NULL, NULL, NULL) != MP_OKAY) { + WOLFSSL_MSG("mp_init_multi error"); + goto cleanup; + } + + if (q && setupPoint(q) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("setupPoint error"); + goto cleanup; + } + + if (mp_read_radix(&prime, ecc_sets[group->curve_idx].prime, MP_RADIX_HEX) + != MP_OKAY) { + WOLFSSL_MSG("mp_read_radix prime error"); + goto cleanup; + } + + if (mp_read_radix(&a, ecc_sets[group->curve_idx].Af, MP_RADIX_HEX) + != MP_OKAY) { + WOLFSSL_MSG("mp_read_radix a error"); + goto cleanup; + } + + if (n) { + /* load generator */ + if (wc_ecc_get_generator(result, group->curve_idx) + != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_get_generator error"); + goto cleanup; + } + } + + if (n && q && m) { + /* r = generator * n + q * m */ +#ifdef ECC_SHAMIR + if (ecc_mul2add(result, (mp_int*)n->internal, + (ecc_point*)q->internal, (mp_int*)m->internal, + result, &a, &prime, NULL) + != MP_OKAY) { + WOLFSSL_MSG("ecc_mul2add error"); + goto cleanup; + } +#else + mp_digit mp = 0; + if (mp_montgomery_setup(&prime, &mp) != MP_OKAY) { + WOLFSSL_MSG("mp_montgomery_setup nqm error"); + goto cleanup; + } + if (!(tmp = wc_ecc_new_point())) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new nqm error"); + goto cleanup; + } + /* r = generator * n */ + if (wc_ecc_mulmod((mp_int*)n->internal, result, result, &a, &prime, 1) + != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + goto cleanup; + } + /* tmp = q * m */ + if (wc_ecc_mulmod((mp_int*)m->internal, (ecc_point*)q->internal, + tmp, &a, &prime, 1) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + goto cleanup; + } + /* result = result + tmp */ + if (ecc_projective_add_point(tmp, result, result, &a, &prime, mp) + != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + goto cleanup; + } + if (ecc_map(result, &prime, mp) != MP_OKAY) { + WOLFSSL_MSG("ecc_map nqm error"); + goto cleanup; + } +#endif + } + else if (n) { + /* r = generator * n */ + if (wc_ecc_mulmod((mp_int*)n->internal, result, result, &a, &prime, 1) + != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod gn error"); + goto cleanup; + } + } + else if (q && m) { + /* r = q * m */ + if (wc_ecc_mulmod((mp_int*)m->internal, (ecc_point*)q->internal, + result, &a, &prime, 1) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod qm error"); + goto cleanup; + } + } + + /* copy to destination */ + if (wc_ecc_copy_point(result, (ecc_point*)r->internal)) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + goto cleanup; + } + r->inSet = 1; + if (SetECPointExternal(r) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECPointExternal error"); + goto cleanup; + } + + ret = WOLFSSL_SUCCESS; +cleanup: + mp_clear(&a); + mp_clear(&prime); + wc_ecc_del_point(result); + wc_ecc_del_point(tmp); + return ret; +} +#endif /* !defined(WOLFSSL_ATECC508A) && defined(ECC_SHAMIR) && + * !defined(HAVE_SELFTEST) */ + +void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *p) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_clear_free"); + + wolfSSL_EC_POINT_free(p); +} + +/* return code compliant with OpenSSL : + * 0 if equal, 1 if not and -1 in case of error + */ +int wolfSSL_EC_POINT_cmp(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, + WOLFSSL_BN_CTX *ctx) +{ + int ret; + + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp"); + + if (group == NULL || a == NULL || a->internal == NULL || b == NULL || + b->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_cmp Bad arguments"); + return WOLFSSL_FATAL_ERROR; + } + + ret = wc_ecc_cmp_point((ecc_point*)a->internal, (ecc_point*)b->internal); + if (ret == MP_EQ) + return 0; + else if (ret == MP_LT || ret == MP_GT) + return 1; + + return WOLFSSL_FATAL_ERROR; +} + +int wolfSSL_EC_POINT_copy(WOLFSSL_EC_POINT *dest, const WOLFSSL_EC_POINT *src) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_copy"); + + if (!dest || !src) { + return WOLFSSL_FAILURE; + } + + if (setupPoint(src) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + if (wc_ecc_copy_point((ecc_point*) dest->internal, + (ecc_point*) src->internal) != MP_OKAY) { + return WOLFSSL_FAILURE; + } + + dest->inSet = 1; + + if (SetECPointExternal(dest) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_ECC */ +#endif /* OPENSSL_EXTRA */ + +#if defined(HAVE_ECC) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *p) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_free"); + + if (p != NULL) { + if (p->internal != NULL) { + wc_ecc_del_point((ecc_point*)p->internal); + p->internal = NULL; + } + + wolfSSL_BN_free(p->X); + wolfSSL_BN_free(p->Y); + wolfSSL_BN_free(p->Z); + p->X = NULL; + p->Y = NULL; + p->Z = NULL; + p->inSet = p->exSet = 0; + + XFREE(p, NULL, DYNAMIC_TYPE_ECC); + /* p = NULL, don't try to access or double free it */ + } +} +#endif + +#ifdef OPENSSL_EXTRA +#ifdef HAVE_ECC +/* return code compliant with OpenSSL : + * 1 if point at infinity, 0 else + */ +int wolfSSL_EC_POINT_is_at_infinity(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_is_at_infinity"); + + if (group == NULL || point == NULL || point->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_is_at_infinity NULL error"); + return WOLFSSL_FAILURE; + } + + if (setupPoint(point) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + ret = wc_ecc_point_is_at_infinity((ecc_point*)point->internal); + if (ret < 0) { + WOLFSSL_MSG("ecc_point_is_at_infinity failure"); + return WOLFSSL_FAILURE; + } + + return ret; +} + +/* End EC_POINT */ + +size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *r, size_t nitems) +{ + size_t i, min_nitems; +#ifdef HAVE_SELFTEST + size_t ecc_sets_count; + for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++); + ecc_sets_count = i; +#endif + + if (r == NULL || nitems == 0) + return ecc_sets_count; + + min_nitems = nitems < ecc_sets_count ? nitems : ecc_sets_count; + + for (i = 0; i < min_nitems; i++) { + r[i].nid = EccEnumToNID(ecc_sets[i].id); + r[i].comment = wolfSSL_OBJ_nid2sn(r[i].nid); + } + + return ecc_sets_count; +} + +/* Start ECDSA_SIG */ +void wolfSSL_ECDSA_SIG_free(WOLFSSL_ECDSA_SIG *sig) +{ + WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_free"); + + if (sig) { + wolfSSL_BN_free(sig->r); + wolfSSL_BN_free(sig->s); + + XFREE(sig, NULL, DYNAMIC_TYPE_ECC); + } +} + +WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void) +{ + WOLFSSL_ECDSA_SIG *sig; + + WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_new"); + + sig = (WOLFSSL_ECDSA_SIG*) XMALLOC(sizeof(WOLFSSL_ECDSA_SIG), NULL, + DYNAMIC_TYPE_ECC); + if (sig == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA signature failure"); + return NULL; + } + + sig->s = NULL; + sig->r = wolfSSL_BN_new(); + if (sig->r == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA r failure"); + wolfSSL_ECDSA_SIG_free(sig); + return NULL; + } + + sig->s = wolfSSL_BN_new(); + if (sig->s == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA s failure"); + wolfSSL_ECDSA_SIG_free(sig); + return NULL; + } + + return sig; +} + +/* return signature structure on success, NULL otherwise */ +WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_do_sign(const unsigned char *d, int dlen, + WOLFSSL_EC_KEY *key) +{ + WOLFSSL_ECDSA_SIG *sig = NULL; + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_ECDSA_do_sign"); + + if (d == NULL || key == NULL || key->internal == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad arguments"); + return NULL; + } + + /* set internal key if not done */ + if (key->inSet == 0) + { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign No EC key internal set, do it"); + + if (SetECKeyInternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed"); + return NULL; + } + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return NULL; +#endif + + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + mp_int sig_r, sig_s; + + if (mp_init_multi(&sig_r, &sig_s, NULL, NULL, NULL, NULL) == MP_OKAY) { + if (wc_ecc_sign_hash_ex(d, dlen, rng, (ecc_key*)key->internal, + &sig_r, &sig_s) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_sign_hash_ex failed"); + } + else { + /* put signature blob in ECDSA structure */ + sig = wolfSSL_ECDSA_SIG_new(); + if (sig == NULL) + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new failed"); + else if (SetIndividualExternal(&(sig->r), &sig_r)!=WOLFSSL_SUCCESS){ + WOLFSSL_MSG("ecdsa r key error"); + wolfSSL_ECDSA_SIG_free(sig); + sig = NULL; + } + else if (SetIndividualExternal(&(sig->s), &sig_s)!=WOLFSSL_SUCCESS){ + WOLFSSL_MSG("ecdsa s key error"); + wolfSSL_ECDSA_SIG_free(sig); + sig = NULL; + } + + } + mp_free(&sig_r); + mp_free(&sig_s); + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return sig; +} + +/* return code compliant with OpenSSL : + * 1 for a valid signature, 0 for an invalid signature and -1 on error + */ +int wolfSSL_ECDSA_do_verify(const unsigned char *d, int dlen, + const WOLFSSL_ECDSA_SIG *sig, WOLFSSL_EC_KEY *key) +{ + int check_sign = 0; + + WOLFSSL_ENTER("wolfSSL_ECDSA_do_verify"); + + if (d == NULL || sig == NULL || key == NULL || key->internal == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad arguments"); + return WOLFSSL_FATAL_ERROR; + } + + /* set internal key if not done */ + if (key->inSet == 0) + { + WOLFSSL_MSG("No EC key internal set, do it"); + + if (SetECKeyInternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal, + (mp_int*)sig->s->internal, d, dlen, &check_sign, + (ecc_key *)key->internal) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_verify_hash failed"); + return WOLFSSL_FATAL_ERROR; + } + else if (check_sign == 0) { + WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +WOLFSSL_ECDSA_SIG *wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG **sig, + const unsigned char **pp, long len) +{ + WOLFSSL_ECDSA_SIG *s = NULL; + + if (pp == NULL) + return NULL; + + if (sig != NULL) + s = *sig; + if (s == NULL) { + s = wolfSSL_ECDSA_SIG_new(); + if (s == NULL) + return NULL; + } + + /* DecodeECC_DSA_Sig calls mp_init, so free these */ + mp_free((mp_int*)s->r->internal); + mp_free((mp_int*)s->s->internal); + + if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal, + (mp_int*)s->s->internal) != MP_OKAY) { + if (sig == NULL || *sig == NULL) + wolfSSL_ECDSA_SIG_free(s); + return NULL; + } + + *pp += len; + if (sig != NULL) + *sig = s; + return s; +} + +int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp) +{ + word32 len; + + if (sig == NULL) + return 0; + + /* ASN.1: SEQ + INT + INT + * ASN.1 Integer must be a positive value - prepend zero if number has + * top bit set. + */ + len = 2 + mp_leading_bit((mp_int*)sig->r->internal) + + mp_unsigned_bin_size((mp_int*)sig->r->internal) + + 2 + mp_leading_bit((mp_int*)sig->s->internal) + + mp_unsigned_bin_size((mp_int*)sig->s->internal); + /* Two bytes required for length if ASN.1 SEQ data greater than 127 bytes + * and less than 256 bytes. + */ + len = 1 + ((len > 127) ? 2 : 1) + len; + if (pp != NULL && *pp != NULL) { + if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal, + (mp_int*)sig->s->internal) != MP_OKAY) { + len = 0; + } + else + *pp += len; + } + + return (int)len; +} +/* End ECDSA_SIG */ + +/* Start ECDH */ +/* return code compliant with OpenSSL : + * length of computed key if success, -1 if error + */ +int wolfSSL_ECDH_compute_key(void *out, size_t outlen, + const WOLFSSL_EC_POINT *pub_key, + WOLFSSL_EC_KEY *ecdh, + void *(*KDF) (const void *in, size_t inlen, + void *out, size_t *outlen)) +{ + word32 len; + (void)KDF; + + (void)KDF; + + WOLFSSL_ENTER("wolfSSL_ECDH_compute_key"); + + if (out == NULL || pub_key == NULL || pub_key->internal == NULL || + ecdh == NULL || ecdh->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + + /* set internal key if not done */ + if (ecdh->inSet == 0) + { + WOLFSSL_MSG("No EC key internal set, do it"); + + if (SetECKeyInternal(ecdh) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + len = (word32)outlen; + + if (wc_ecc_shared_secret_ssh((ecc_key*)ecdh->internal, + (ecc_point*)pub_key->internal, + (byte *)out, &len) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_shared_secret failed"); + return WOLFSSL_FATAL_ERROR; + } + + return len; +} +/* End ECDH */ + +#if !defined(NO_FILESYSTEM) +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY *x) +{ + (void)fp; + (void)x; + WOLFSSL_STUB("PEM_write_EC_PUBKEY"); + WOLFSSL_MSG("wolfSSL_PEM_write_EC_PUBKEY not implemented"); + + return WOLFSSL_FAILURE; +} +#endif + +/* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects + * the results to be an EC key. + * + * bio structure to read EC private key from + * ec if not null is then set to the result + * cb password callback for reading PEM + * pass password string + * + * returns a pointer to a new WOLFSSL_EC_KEY struct on success and NULL on fail + */ + +WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_EC_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_EC_KEY** ec, + pem_password_cb* cb, void *pass) +{ + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_EC_KEY* local; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_EC_PUBKEY"); + + pkey = wolfSSL_PEM_read_bio_PUBKEY(bio, NULL, cb, pass); + if (pkey == NULL) { + return NULL; + } + + /* Since the WOLFSSL_EC_KEY structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_EC_KEY structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownEcc = 0; + local = pkey->ecc; + if (ec != NULL) { + *ec = local; + } + + wolfSSL_EVP_PKEY_free(pkey); + return local; +} + +/* Reads a private EC key from a WOLFSSL_BIO into a WOLFSSL_EC_KEY. + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EC_KEY** ec, + pem_password_cb* cb, + void *pass) +{ + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_EC_KEY* local; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_ECPrivateKey"); + + pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass); + if (pkey == NULL) { + return NULL; + } + + /* Since the WOLFSSL_EC_KEY structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_EC_KEY structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownEcc = 0; + local = pkey->ecc; + if (ec != NULL) { + *ec = local; + } + + wolfSSL_EVP_PKEY_free(pkey); + return local; +} +#endif /* NO_FILESYSTEM */ + +#if defined(WOLFSSL_KEY_GEN) +/* Takes a public WOLFSSL_EC_KEY and writes it out to WOLFSSL_BIO + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec) +{ + int ret = 0, der_max_len = 0, derSz = 0; + byte *derBuf; + WOLFSSL_EVP_PKEY* pkey; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_EC_PUBKEY"); + + if (bio == NULL || ec == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return WOLFSSL_FAILURE; + } + + /* Initialize pkey structure */ + pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); + return WOLFSSL_FAILURE; + } + + /* Set pkey info */ + pkey->ecc = ec; + pkey->ownEcc = 0; /* pkey does not own ECC */ + pkey->type = EVP_PKEY_EC; + + /* 4 > size of pub, priv + ASN.1 additional information */ + der_max_len = 4 * wc_ecc_size((ecc_key*)ec->internal) + AES_BLOCK_SIZE; + + derBuf = (byte*)XMALLOC(der_max_len, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("Malloc failed"); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* convert key to der format */ + derSz = wc_EccPublicKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len, 1); + if (derSz < 0) { + WOLFSSL_MSG("wc_EccPublicKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (pkey->pkey.ptr == NULL) { + WOLFSSL_MSG("key malloc failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* add der info to the evp key */ + pkey->pkey_sz = derSz; + XMEMCPY(pkey->pkey.ptr, derBuf, derSz); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + + if((ret = wolfSSL_PEM_write_bio_PUBKEY(bio, pkey)) != WOLFSSL_SUCCESS){ + WOLFSSL_MSG("wolfSSL_PEM_write_bio_PUBKEY failed"); + } + wolfSSL_EVP_PKEY_free(pkey); + + return ret; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec, + const EVP_CIPHER* cipher, + unsigned char* passwd, int len, + pem_password_cb* cb, void* arg) +{ + int ret = 0, der_max_len = 0, derSz = 0; + byte *derBuf; + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_ENTER("WOLFSSL_PEM_write_bio_ECPrivateKey"); + + if (bio == NULL || ec == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return WOLFSSL_FAILURE; + } + + /* Initialize pkey structure */ + pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); + return WOLFSSL_FAILURE; + } + + /* Set pkey info */ + pkey->ecc = ec; + pkey->ownEcc = 0; /* pkey does not own ECC */ + pkey->type = EVP_PKEY_EC; + + /* 4 > size of pub, priv + ASN.1 additional informations + */ + der_max_len = 4 * wc_ecc_size((ecc_key*)ec->internal) + AES_BLOCK_SIZE; + + derBuf = (byte*)XMALLOC(der_max_len, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("Malloc failed"); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* convert key to der format */ + derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_EccKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (pkey->pkey.ptr == NULL) { + WOLFSSL_MSG("key malloc failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* add der info to the evp key */ + pkey->pkey_sz = derSz; + XMEMCPY(pkey->pkey.ptr, derBuf, derSz); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + + ret = wolfSSL_PEM_write_bio_PrivateKey(bio, pkey, cipher, passwd, len, + cb, arg); + wolfSSL_EVP_PKEY_free(pkey); + + return ret; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ecc, + const EVP_CIPHER* cipher, + unsigned char* passwd, int passwdSz, + unsigned char **pem, int *plen) +{ +#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) + byte *derBuf, *tmp, *cipherInfo = NULL; + int der_max_len = 0, derSz = 0; + const int type = ECC_PRIVATEKEY_TYPE; + const char* header = NULL; + const char* footer = NULL; + + WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey"); + + if (pem == NULL || plen == NULL || ecc == NULL || ecc->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + if (wc_PemGetHeaderFooter(type, &header, &footer) != 0) + return WOLFSSL_FAILURE; + + if (ecc->inSet == 0) { + WOLFSSL_MSG("No ECC internal set, do it"); + + if (SetECKeyInternal(ecc) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyInternal failed"); + return WOLFSSL_FAILURE; + } + } + + /* 4 > size of pub, priv + ASN.1 additional information */ + der_max_len = 4 * wc_ecc_size((ecc_key*)ecc->internal) + AES_BLOCK_SIZE; + + derBuf = (byte*)XMALLOC(der_max_len, NULL, DYNAMIC_TYPE_DER); + if (derBuf == NULL) { + WOLFSSL_MSG("malloc failed"); + return WOLFSSL_FAILURE; + } + + /* Key to DER */ + derSz = wc_EccKeyToDer((ecc_key*)ecc->internal, derBuf, der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_EccKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return WOLFSSL_FAILURE; + } + + /* encrypt DER buffer if required */ + if (passwd != NULL && passwdSz > 0 && cipher != NULL) { + int ret; + + ret = EncryptDerKey(derBuf, &derSz, cipher, + passwd, passwdSz, &cipherInfo); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("EncryptDerKey failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return ret; + } + + /* tmp buffer with a max size */ + *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE; + } + else { /* tmp buffer with a max size */ + *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1; + } + + tmp = (byte*)XMALLOC(*plen, NULL, DYNAMIC_TYPE_PEM); + if (tmp == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + + /* DER to PEM */ + *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, type); + if (*plen <= 0) { + WOLFSSL_MSG("wc_DerToPemEx failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + + *pem = (byte*)XMALLOC((*plen)+1, NULL, DYNAMIC_TYPE_KEY); + if (*pem == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return WOLFSSL_FAILURE; + } + XMEMSET(*pem, 0, (*plen)+1); + + if (XMEMCPY(*pem, tmp, *plen) == NULL) { + WOLFSSL_MSG("XMEMCPY failed"); + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return WOLFSSL_FAILURE; + } + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + + return WOLFSSL_SUCCESS; +#else + (void)ecc; + (void)cipher; + (void)passwd; + (void)passwdSz; + (void)pem; + (void)plen; + return WOLFSSL_FAILURE; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ecc, + const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + byte *pem; + int plen, ret; + + (void)cb; + (void)u; + + WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey"); + + if (fp == XBADFILE || ecc == NULL || ecc->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_PEM_write_mem_ECPrivateKey(ecc, enc, kstr, klen, &pem, &plen); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey failed"); + return WOLFSSL_FAILURE; + } + + ret = (int)XFWRITE(pem, plen, 1, fp); + if (ret != 1) { + WOLFSSL_MSG("ECC private key file write failed"); + return WOLFSSL_FAILURE; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return WOLFSSL_SUCCESS; +} + +#endif /* NO_FILESYSTEM */ +#endif /* defined(WOLFSSL_KEY_GEN) */ + +#endif /* HAVE_ECC */ + + +#ifndef NO_DSA + +#if defined(WOLFSSL_KEY_GEN) + +/* Takes a DSA Privatekey and writes it out to a WOLFSSL_BIO + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_PEM_write_bio_DSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa, + const EVP_CIPHER* cipher, + unsigned char* passwd, int len, + pem_password_cb* cb, void* arg) +{ + int ret = 0, der_max_len = 0, derSz = 0; + byte *derBuf; + WOLFSSL_EVP_PKEY* pkey; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSAPrivateKey"); + + if (bio == NULL || dsa == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return WOLFSSL_FAILURE; + } + + pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); + return WOLFSSL_FAILURE; + } + + pkey->type = EVP_PKEY_DSA; + pkey->dsa = dsa; + pkey->ownDsa = 0; + + /* 4 > size of pub, priv, p, q, g + ASN.1 additional information */ + der_max_len = 4 * wolfSSL_BN_num_bytes(dsa->g) + AES_BLOCK_SIZE; + + derBuf = (byte*)XMALLOC(der_max_len, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("Malloc failed"); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* convert key to der format */ + derSz = wc_DsaKeyToDer((DsaKey*)dsa->internal, derBuf, der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_DsaKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (pkey->pkey.ptr == NULL) { + WOLFSSL_MSG("key malloc failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* add der info to the evp key */ + pkey->pkey_sz = derSz; + XMEMCPY(pkey->pkey.ptr, derBuf, derSz); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + + ret = wolfSSL_PEM_write_bio_PrivateKey(bio, pkey, cipher, passwd, len, + cb, arg); + wolfSSL_EVP_PKEY_free(pkey); + + return ret; +} + +#ifndef HAVE_SELFTEST +/* Takes a DSA public key and writes it out to a WOLFSSL_BIO + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_PEM_write_bio_DSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa) +{ + int ret = 0, derMax = 0, derSz = 0; + byte *derBuf; + WOLFSSL_EVP_PKEY* pkey; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSA_PUBKEY"); + + if (bio == NULL || dsa == NULL) { + WOLFSSL_MSG("Bad function arguements"); + return WOLFSSL_FAILURE; + } + + pkey = wolfSSL_EVP_PKEY_new_ex(bio->heap); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new_ex failed"); + return WOLFSSL_FAILURE; + } + + pkey->type = EVP_PKEY_DSA; + pkey->dsa = dsa; + pkey->ownDsa = 0; + + /* 4 > size of pub, priv, p, q, g + ASN.1 additional information */ + derMax = 4 * wolfSSL_BN_num_bytes(dsa->g) + AES_BLOCK_SIZE; + + derBuf = (byte*)XMALLOC(derMax, bio->heap, DYNAMIC_TYPE_DER); + if (derBuf == NULL) { + WOLFSSL_MSG("malloc failed"); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + /* Key to DER */ + derSz = wc_DsaKeyToPublicDer((DsaKey*)dsa->internal, derBuf, derMax); + if (derSz < 0) { + WOLFSSL_MSG("wc_DsaKeyToDer failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + + pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap, DYNAMIC_TYPE_DER); + + if (pkey->pkey.ptr == NULL) { + WOLFSSL_MSG("key malloc failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + pkey->pkey_sz = derSz; + XMEMSET(pkey->pkey.ptr, 0, derSz); + + if (XMEMCPY(pkey->pkey.ptr, derBuf, derSz) == NULL) { + WOLFSSL_MSG("XMEMCPY failed"); + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); + XFREE(pkey->pkey.ptr, bio->heap, DYNAMIC_TYPE_DER); + wolfSSL_EVP_PKEY_free(pkey); + return WOLFSSL_FAILURE; + } + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); + ret = wolfSSL_PEM_write_bio_PUBKEY(bio, pkey); + wolfSSL_EVP_PKEY_free(pkey); + return ret; +} +#endif /* HAVE_SELFTEST */ + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, + const EVP_CIPHER* cipher, + unsigned char* passwd, int passwdSz, + unsigned char **pem, int *plen) +{ +#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) + byte *derBuf, *tmp, *cipherInfo = NULL; + int der_max_len = 0, derSz = 0; + const int type = DSA_PRIVATEKEY_TYPE; + const char* header = NULL; + const char* footer = NULL; + + WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey"); + + if (pem == NULL || plen == NULL || dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + if (wc_PemGetHeaderFooter(type, &header, &footer) != 0) + return WOLFSSL_FAILURE; + + if (dsa->inSet == 0) { + WOLFSSL_MSG("No DSA internal set, do it"); + + if (SetDsaInternal(dsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDsaInternal failed"); + return WOLFSSL_FAILURE; + } + } + + /* 4 > size of pub, priv, p, q, g + ASN.1 additional information */ + der_max_len = 4 * wolfSSL_BN_num_bytes(dsa->g) + AES_BLOCK_SIZE; + + derBuf = (byte*)XMALLOC(der_max_len, NULL, DYNAMIC_TYPE_DER); + if (derBuf == NULL) { + WOLFSSL_MSG("malloc failed"); + return WOLFSSL_FAILURE; + } + + /* Key to DER */ + derSz = wc_DsaKeyToDer((DsaKey*)dsa->internal, derBuf, der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_DsaKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return WOLFSSL_FAILURE; + } + + /* encrypt DER buffer if required */ + if (passwd != NULL && passwdSz > 0 && cipher != NULL) { + int ret; + + ret = EncryptDerKey(derBuf, &derSz, cipher, + passwd, passwdSz, &cipherInfo); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("EncryptDerKey failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return ret; + } + + /* tmp buffer with a max size */ + *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE; + } + else { /* tmp buffer with a max size */ + *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1; + } + + tmp = (byte*)XMALLOC(*plen, NULL, DYNAMIC_TYPE_PEM); + if (tmp == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + + /* DER to PEM */ + *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, type); + if (*plen <= 0) { + WOLFSSL_MSG("wc_DerToPemEx failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return WOLFSSL_FAILURE; + } + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + if (cipherInfo != NULL) + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + + *pem = (byte*)XMALLOC((*plen)+1, NULL, DYNAMIC_TYPE_KEY); + if (*pem == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return WOLFSSL_FAILURE; + } + XMEMSET(*pem, 0, (*plen)+1); + + if (XMEMCPY(*pem, tmp, *plen) == NULL) { + WOLFSSL_MSG("XMEMCPY failed"); + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return WOLFSSL_FAILURE; + } + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + + return WOLFSSL_SUCCESS; +#else + (void)dsa; + (void)cipher; + (void)passwd; + (void)passwdSz; + (void)pem; + (void)plen; + return WOLFSSL_FAILURE; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_PEM_write_DSAPrivateKey(XFILE fp, WOLFSSL_DSA *dsa, + const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + byte *pem; + int plen, ret; + + (void)cb; + (void)u; + + WOLFSSL_MSG("wolfSSL_PEM_write_DSAPrivateKey"); + + if (fp == XBADFILE || dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_PEM_write_mem_DSAPrivateKey(dsa, enc, kstr, klen, &pem, &plen); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey failed"); + return WOLFSSL_FAILURE; + } + + ret = (int)XFWRITE(pem, plen, 1, fp); + if (ret != 1) { + WOLFSSL_MSG("DSA private key file write failed"); + return WOLFSSL_FAILURE; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return WOLFSSL_SUCCESS; +} + +#endif /* NO_FILESYSTEM */ +#endif /* defined(WOLFSSL_KEY_GEN) */ + +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_PEM_write_DSA_PUBKEY(XFILE fp, WOLFSSL_DSA *x) +{ + (void)fp; + (void)x; + WOLFSSL_STUB("PEM_write_DSA_PUBKEY"); + WOLFSSL_MSG("wolfSSL_PEM_write_DSA_PUBKEY not implemented"); + + return WOLFSSL_FAILURE; +} +#endif +#endif /* NO_FILESYSTEM */ + +#endif /* #ifndef NO_DSA */ + +static int pem_read_bio_key(WOLFSSL_BIO* bio, pem_password_cb* cb, void* pass, + int keyType, int* eccFlag, DerBuffer** der) +{ +#ifdef WOLFSSL_SMALL_STACK + EncryptedInfo* info = NULL; +#else + EncryptedInfo info[1]; +#endif /* WOLFSSL_SMALL_STACK */ + pem_password_cb* localCb = NULL; + char* mem = NULL; + int memSz = 0; + int ret; + + if(cb) { + localCb = cb; + } else { + if(pass) { + localCb = wolfSSL_PEM_def_callback; + } + } + + 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"); + ret = MEMORY_E; + } + if (ret >= 0) { + if ((ret = wolfSSL_BIO_read(bio, mem, memSz)) <= 0) { + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + mem = NULL; + ret = MEMORY_E; + } + } + } + else if (bio->type == WOLFSSL_BIO_FILE) { + int sz = 100; /* read from file by 100 byte chunks */ + int idx = 0; + char* tmp = (char*)XMALLOC(sz, bio->heap, DYNAMIC_TYPE_OPENSSL); + memSz = 0; + if (tmp == NULL) { + WOLFSSL_MSG("Memory error"); + ret = MEMORY_E; + } + + while (ret >= 0 && (sz = wolfSSL_BIO_read(bio, tmp, sz)) > 0) { + char* newMem; + if (memSz + sz < 0) { + /* sanity check */ + break; + } + newMem = (char*)XREALLOC(mem, memSz + sz, bio->heap, + DYNAMIC_TYPE_OPENSSL); + if (newMem == NULL) { + WOLFSSL_MSG("Memory error"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + mem = NULL; + XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); + tmp = NULL; + ret = MEMORY_E; + break; + } + mem = newMem; + XMEMCPY(mem + idx, tmp, sz); + memSz += sz; + idx += sz; + sz = 100; /* read another 100 byte chunk from file */ + } + XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); + tmp = NULL; + if (memSz <= 0) { + WOLFSSL_MSG("No data to read from bio"); + if (mem != NULL) { + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + mem = NULL; + } + ret = BUFFER_E; + } + } + else { + WOLFSSL_MSG("No data to read from bio"); + ret = NOT_COMPILED_IN; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret >= 0) { + 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); + mem = NULL; + ret = MEMORY_E; + } + } +#endif + + if (ret >= 0) { + XMEMSET(info, 0, sizeof(EncryptedInfo)); + info->passwd_cb = localCb; + info->passwd_userdata = pass; + ret = PemToDer((const unsigned char*)mem, memSz, keyType, der, + NULL, info, eccFlag); + + if (ret < 0) { + WOLFSSL_MSG("Bad Pem To Der"); + } + else { + /* write left over data back to bio */ + if ((memSz - (int)info->consumed) > 0 && + bio->type != WOLFSSL_BIO_FILE) { + if (wolfSSL_BIO_write(bio, mem + (int)info->consumed, + memSz - (int)info->consumed) <= 0) { + WOLFSSL_MSG("Unable to advance bio read pointer"); + } + } + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + + return ret; +} + +WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** key, + pem_password_cb* cb, + void* pass) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + int type = -1; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PrivateKey"); + + if (bio == NULL) + return pkey; + + if (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, &keyFormat, + &der) >= 0) { + const unsigned char* ptr = der->buffer; + + if (keyFormat) { + /* keyFormat is Key_Sum enum */ + if (keyFormat == RSAk) + type = EVP_PKEY_RSA; + else if (keyFormat == ECDSAk) + type = EVP_PKEY_EC; + else if (keyFormat == DSAk) + type = EVP_PKEY_DSA; + else if (keyFormat == DHk) + type = EVP_PKEY_DH; + } + else { + /* Default to RSA if format is not set */ + type = EVP_PKEY_RSA; + } + + /* handle case where reuse is attempted */ + if (key != NULL && *key != NULL) + pkey = *key; + + wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length); + if (pkey == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + } + } + + FreeDer(&der); + + if (key != NULL && pkey != NULL) + *key = pkey; + + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", 0); + + return pkey; +} + +WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_bio_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY **key, + pem_password_cb *cb, void *pass) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PUBKEY"); + + if (bio == NULL) + return pkey; + + if (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, &keyFormat, &der) >= 0) { + const unsigned char* ptr = der->buffer; + + /* handle case where reuse is attempted */ + if (key != NULL && *key != NULL) + pkey = *key; + + wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length); + if (pkey == NULL) { + WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); + } + } + + FreeDer(&der); + + if (key != NULL && pkey != NULL) + *key = pkey; + + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PUBKEY", 0); + + return pkey; +} + + +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && !defined(NO_RSA) +/* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects + * the results to be an RSA key. + * + * bio structure to read RSA private key from + * rsa if not null is then set to the result + * cb password callback for reading PEM + * pass password string + * + * returns a pointer to a new WOLFSSL_RSA structure on success and NULL on fail + */ +WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_RSA** rsa, pem_password_cb* cb, void* pass) +{ + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_RSA* local; + + WOLFSSL_ENTER("PEM_read_bio_RSAPrivateKey"); + + pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass); + if (pkey == NULL) { + return NULL; + } + + /* Since the WOLFSSL_RSA structure is being taken from WOLFSSL_EVP_PEKY the + * flag indicating that the WOLFSSL_RSA structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownRsa = 0; + local = pkey->rsa; + if (rsa != NULL) { + *rsa = local; + } + + wolfSSL_EVP_PKEY_free(pkey); + return local; +} +#endif /* OPENSSL_EXTRA || OPENSSL_ALL || !NO_RSA */ + +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && (!defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) && !defined(NO_DSA) && defined(WOLFSSL_KEY_GEN)) +/* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects + * the results to be an DSA key. + * + * bio structure to read DSA private key from + * dsa if not null is then set to the result + * cb password callback for reading PEM + * pass password string + * + * returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail + */ +WOLFSSL_DSA* wolfSSL_PEM_read_bio_DSAPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_DSA** dsa, + pem_password_cb* cb,void *pass) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + WOLFSSL_DSA* local; + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSAPrivateKey"); + + + pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass); + if (pkey == NULL) { + WOLFSSL_MSG("Error in PEM_read_bio_PrivateKey"); + return NULL; + } + /* Since the WOLFSSL_DSA structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_DSA structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownDsa = 0; + local = pkey->dsa; + if (dsa != NULL) { + *dsa = local; + } + wolfSSL_EVP_PKEY_free(pkey); + return local; +} + +/* Reads an DSA public key from a WOLFSSL_BIO into a WOLFSSL_DSA. + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSA_PUBKEY(WOLFSSL_BIO* bio,WOLFSSL_DSA** dsa, + pem_password_cb* cb, void *pass) +{ + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_DSA* local; + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSA_PUBKEY"); + + pkey = wolfSSL_PEM_read_bio_PUBKEY(bio, NULL, cb, pass); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_PEM_read_bio_PUBKEY failed"); + return NULL; + } + + /* Since the WOLFSSL_DSA structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_DSA structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownDsa = 0; + local = pkey->dsa; + if (dsa != NULL) { + *dsa = local; + } + + wolfSSL_EVP_PKEY_free(pkey); + return local; +} +#endif + +#ifdef HAVE_ECC +/* returns a new WOLFSSL_EC_GROUP structure on success and NULL on fail */ +WOLFSSL_EC_GROUP* wolfSSL_PEM_read_bio_ECPKParameters(WOLFSSL_BIO* bio, + WOLFSSL_EC_GROUP** group, pem_password_cb* cb, void* pass) +{ + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_EC_GROUP* ret = NULL; + + /* check on if bio is null is done in wolfSSL_PEM_read_bio_PrivateKey */ + pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass); + if (pkey != NULL) { + if (pkey->type != EVP_PKEY_EC) { + WOLFSSL_MSG("Unexpected key type"); + } + else { + ret = (WOLFSSL_EC_GROUP*)wolfSSL_EC_KEY_get0_group(pkey->ecc); + + /* set ecc group to null so it is not free'd when pkey is free'd */ + pkey->ecc->group = NULL; + } + } + + (void)group; + wolfSSL_EVP_PKEY_free(pkey); + return ret; +} +#endif /* HAVE_ECC */ + +#if !defined(NO_FILESYSTEM) +WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, EVP_PKEY **x, + pem_password_cb *cb, void *u) +{ + (void)fp; + (void)x; + (void)cb; + (void)u; + + WOLFSSL_MSG("wolfSSL_PEM_read_PUBKEY not implemented"); + + return NULL; +} +#endif /* NO_FILESYSTEM */ + +#ifndef NO_RSA + +#if defined(XSNPRINTF) && !defined(HAVE_FAST_RSA) +/* snprintf() must be available */ + +/****************************************************************************** +* wolfSSL_RSA_print - writes the human readable form of RSA to bio +* +* RETURNS: +* returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE +*/ +int wolfSSL_RSA_print(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, int offset) +{ + char tmp[100] = {0}; + word32 idx = 0; + int sz = 0; + byte lbit = 0; + int rawLen = 0; + byte* rawKey = NULL; + RsaKey* iRsa = NULL; + int i = 0; + mp_int *rsaElem = NULL; + char rsaStr[][20] = { "Modulus:", + "PublicExponent:", + "PrivateExponent:", + "Prime1:", + "Prime2:", + "Exponent1:", + "Exponent2:", + "Coefficient:" + }; + + WOLFSSL_ENTER("wolfSSL_RSA_print"); + (void)offset; + + if (bio == NULL || rsa == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + if ((sz = wolfSSL_RSA_size(rsa)) < 0) { + WOLFSSL_MSG("Error getting RSA key size"); + return WOLFSSL_FAILURE; + } + iRsa = (RsaKey*)rsa->internal; + + XSNPRINTF(tmp, sizeof(tmp) - 1, "\n%s: (%d bit)", + "RSA Private-Key", 8 * sz); + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + + for (i=0; in; + break; + case 1: + rsaElem = &iRsa->e; + break; + case 2: + rsaElem = &iRsa->d; + break; + case 3: + rsaElem = &iRsa->p; + break; + case 4: + rsaElem = &iRsa->q; + break; + case 5: + rsaElem = &iRsa->dP; + break; + case 6: + rsaElem = &iRsa->dQ; + break; + case 7: + rsaElem = &iRsa->u; + break; + default: + WOLFSSL_MSG("Bad index value"); + } + + if (i == 1) { + /* Print out exponent values */ + rawLen = mp_unsigned_bin_size(rsaElem); + if (rawLen < 0) { + WOLFSSL_MSG("Error getting exponent size"); + return WOLFSSL_FAILURE; + } + + if ((word32)rawLen < sizeof(word32)) { + rawLen = sizeof(word32); + } + rawKey = (byte*)XMALLOC(rawLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (rawKey == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(rawKey, 0, rawLen); + mp_to_unsigned_bin(rsaElem, rawKey); + if ((word32)rawLen <= sizeof(word32)) { + idx = *(word32*)rawKey; + #ifdef BIG_ENDIAN_ORDER + idx = ByteReverseWord32(idx); + #endif + } + XSNPRINTF(tmp, sizeof(tmp) - 1, "\nExponent: %d (0x%x)", idx, idx); + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + else { + XSNPRINTF(tmp, sizeof(tmp) - 1, "\n%s\n ", rsaStr[i]); + tmp[sizeof(tmp) - 1] = '\0'; + if (mp_leading_bit(rsaElem)) { + lbit = 1; + XSTRNCAT(tmp, "00", 3); + } + + rawLen = mp_unsigned_bin_size(rsaElem); + rawKey = (byte*)XMALLOC(rawLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (rawKey == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + mp_to_unsigned_bin(rsaElem, rawKey); + for (idx = 0; idx < (word32)rawLen; idx++) { + char val[5]; + int valSz = 5; + + if ((idx == 0) && !lbit) { + XSNPRINTF(val, valSz - 1, "%02x", rawKey[idx]); + } + else if ((idx != 0) && (((idx + lbit) % 15) == 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + XSNPRINTF(tmp, sizeof(tmp) - 1, + ":\n "); + XSNPRINTF(val, valSz - 1, "%02x", rawKey[idx]); + } + else { + XSNPRINTF(val, valSz - 1, ":%02x", rawKey[idx]); + } + XSTRNCAT(tmp, val, valSz); + } + XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + /* print out remaining values */ + if ((idx > 0) && (((idx - 1 + lbit) % 15) != 0)) { + tmp[sizeof(tmp) - 1] = '\0'; + if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) { + return WOLFSSL_FAILURE; + } + } + lbit = 0; + } + + } + /* done with print out */ + if (wolfSSL_BIO_write(bio, "\n\0", (int)XSTRLEN("\n\0")) <= 0) { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +#endif /* XSNPRINTF */ + +#if !defined(NO_FILESYSTEM) +#ifndef NO_WOLFSSL_STUB +WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA **x, + pem_password_cb *cb, void *u) +{ + (void)fp; + (void)x; + (void)cb; + (void)u; + WOLFSSL_STUB("PEM_read_RSAPublicKey"); + WOLFSSL_MSG("wolfSSL_PEM_read_RSAPublicKey not implemented"); + + return NULL; +} +#endif +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA *x) +{ + (void)fp; + (void)x; + WOLFSSL_STUB("PEM_write_RSAPublicKey"); + WOLFSSL_MSG("wolfSSL_PEM_write_RSAPublicKey not implemented"); + + return WOLFSSL_FAILURE; +} +#endif + +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA *x) +{ + (void)fp; + (void)x; + WOLFSSL_STUB("PEM_write_RSA_PUBKEY"); + WOLFSSL_MSG("wolfSSL_PEM_write_RSA_PUBKEY not implemented"); + + return WOLFSSL_FAILURE; +} +#endif + +#endif /* NO_FILESYSTEM */ + +WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **r, const unsigned char **pp, + long len) +{ + WOLFSSL_RSA *rsa = NULL; + + WOLFSSL_ENTER("d2i_RSAPublicKey"); + + if (pp == NULL) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + if ((rsa = wolfSSL_RSA_new()) == NULL) { + WOLFSSL_MSG("RSA_new failed"); + return NULL; + } + + if (wolfSSL_RSA_LoadDer_ex(rsa, *pp, (int)len, WOLFSSL_RSA_LOAD_PUBLIC) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("RSA_LoadDer failed"); + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + if (r != NULL) + *r = rsa; + + return rsa; +} + +/* Converts an RSA private key from DER format to an RSA structure. +Returns pointer to the RSA structure on success and NULL if error. */ +WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **r, + const unsigned char **derBuf, long derSz) +{ + WOLFSSL_RSA *rsa = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey"); + + /* check for bad functions arguments */ + if (derBuf == NULL) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + if ((rsa = wolfSSL_RSA_new()) == NULL) { + WOLFSSL_MSG("RSA_new failed"); + return NULL; + } + + if (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, + WOLFSSL_RSA_LOAD_PRIVATE) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("RSA_LoadDer failed"); + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + if (r != NULL) + *r = rsa; + + return rsa; +} + +#if !defined(HAVE_FAST_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(NO_RSA) && !defined(HAVE_USER_RSA) +/* Converts an internal RSA structure to DER format. + * If "pp" is null then buffer size only is returned. + * If "*pp" is null then a created buffer is set in *pp and the caller is + * responsible for free'ing it. + * Returns size of DER on success and WOLFSSL_FAILURE if error + */ +int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey"); + + /* check for bad functions arguments */ + if (rsa == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return BAD_FUNC_ARG; + } + + if ((ret = wolfSSL_RSA_To_Der(rsa, pp, 0)) < 0) { + WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); + return WOLFSSL_FAILURE; + } + + return ret; /* returns size of DER if successful */ +} + + +int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, const unsigned char **pp) +{ + int ret; + + /* check for bad functions arguments */ + if (rsa == NULL) { + WOLFSSL_MSG("Bad Function Arguments"); + return BAD_FUNC_ARG; + } + + if ((ret = wolfSSL_RSA_To_Der(rsa, (byte**)pp, 1)) < 0) { + WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); + return WOLFSSL_FAILURE; + } + + return ret; +} +#endif /* !defined(HAVE_FAST_RSA) && defined(WOLFSSL_KEY_GEN) && \ + * !defined(NO_RSA) && !defined(HAVE_USER_RSA) */ + +#endif /* !NO_RSA */ +#endif /* OPENSSL_EXTRA */ + +#if !defined(NO_RSA) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +/* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ +int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf, int derSz) +{ + return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE); +} + + +int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf, + int derSz, int opt) +{ + + word32 idx = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_RSA_LoadDer"); + + if (rsa == NULL || rsa->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + + if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { + ret = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, derSz); + } + else { + ret = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, derSz); + } + + if (ret < 0) { + if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { + WOLFSSL_MSG("RsaPrivateKeyDecode failed"); + } + else { + WOLFSSL_MSG("RsaPublicKeyDecode failed"); + } + return SSL_FATAL_ERROR; + } + + if (SetRsaExternal(rsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetRsaExternal failed"); + return WOLFSSL_FATAL_ERROR; + } + + rsa->inSet = 1; + + return WOLFSSL_SUCCESS; +} + +#if defined(WC_RSA_PSS) && (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)) +static int hash2mgf(enum wc_HashType hType) +{ + switch (hType) { +#ifndef NO_SHA + case WC_HASH_TYPE_SHA: + return WC_MGF1SHA1; +#endif +#ifndef NO_SHA256 +#ifdef WOLFSSL_SHA224 + case WC_HASH_TYPE_SHA224: + return WC_MGF1SHA224; +#endif + case WC_HASH_TYPE_SHA256: + return WC_MGF1SHA256; +#endif +#ifdef WOLFSSL_SHA384 + case WC_HASH_TYPE_SHA384: + return WC_MGF1SHA384; +#endif +#ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + return WC_MGF1SHA512; +#endif + case WC_HASH_TYPE_NONE: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_MD5: + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_SHA3_224: + case WC_HASH_TYPE_SHA3_256: + case WC_HASH_TYPE_SHA3_384: + case WC_HASH_TYPE_SHA3_512: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: + default: + WOLFSSL_MSG("Unrecognized or unsupported hash function"); + return WC_MGF1NONE; + } +} + +/* + * +-----------+ + * | M | + * +-----------+ + * | + * V + * Hash + * | + * V + * +--------+----------+----------+ + * M' = |Padding1| mHash | salt | + * +--------+----------+----------+ + * | + * +--------+----------+ V + * DB = |Padding2|maskedseed| Hash + * +--------+----------+ | + * | | + * V | +--+ + * xor <--- MGF <---| |bc| + * | | +--+ + * | | | + * V V V + * +-------------------+----------+--+ + * EM = | maskedDB |maskedseed|bc| + * +-------------------+----------+--+ + * Diagram taken from https://tools.ietf.org/html/rfc3447#section-9.1 + */ +int wolfSSL_RSA_padding_add_PKCS1_PSS(WOLFSSL_RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const WOLFSSL_EVP_MD *hashAlg, int saltLen) +{ + int hashLen, emLen, mgf; + int ret = WOLFSSL_FAILURE; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG _tmpRNG[1]; + WC_RNG* tmpRNG = _tmpRNG; +#endif + enum wc_HashType hashType; + + WOLFSSL_ENTER("wolfSSL_RSA_padding_add_PKCS1_PSS"); + + if (!rsa || !EM || !mHash || !hashAlg) { + return WOLFSSL_FAILURE; + } + + if (!(rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRNG, &initTmpRng))) { + WOLFSSL_MSG("WOLFSSL_RSA_GetRNG error"); + goto cleanup; + } + + if (!rsa->exSet && SetRsaExternal(rsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetRsaExternal error"); + goto cleanup; + } + + hashType = wolfSSL_EVP_md2macType(hashAlg); + if (hashType < WC_HASH_TYPE_NONE || hashType > WC_HASH_TYPE_MAX) { + WOLFSSL_MSG("wolfSSL_EVP_md2macType error"); + goto cleanup; + } + + if ((mgf = hash2mgf(hashType)) == WC_MGF1NONE) { + WOLFSSL_MSG("hash2mgf error"); + goto cleanup; + } + + if ((hashLen = wolfSSL_EVP_MD_size(hashAlg)) < 0) { + WOLFSSL_MSG("wolfSSL_EVP_MD_size error"); + goto cleanup; + } + + if ((emLen = wolfSSL_RSA_size(rsa)) <= 0) { + WOLFSSL_MSG("wolfSSL_RSA_size error"); + goto cleanup; + } + + switch (saltLen) { + /* Negative saltLen values are treated differently */ + case RSA_PSS_SALTLEN_DIGEST: + saltLen = hashLen; + break; + case RSA_PSS_SALTLEN_MAX_SIGN: + case RSA_PSS_SALTLEN_MAX: + saltLen = emLen - hashLen - 2; + break; + default: + if (saltLen < 0) { + /* Not any currently implemented negative value */ + WOLFSSL_MSG("invalid saltLen"); + goto cleanup; + } + } + + if (wc_RsaPad_ex(mHash, wolfSSL_EVP_MD_size(hashAlg), EM, emLen, + RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD, + wolfSSL_EVP_md2macType(hashAlg), mgf, NULL, 0, saltLen, + wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) { + WOLFSSL_MSG("wc_RsaPad_ex error"); + goto cleanup; + } + + ret = WOLFSSL_SUCCESS; +cleanup: + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + if (tmpRNG) + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +/* + * Refer to wolfSSL_RSA_padding_add_PKCS1_PSS + * for an explanation of the parameters. + */ +int wolfSSL_RSA_verify_PKCS1_PSS(WOLFSSL_RSA *rsa, const unsigned char *mHash, + const WOLFSSL_EVP_MD *hashAlg, + const unsigned char *EM, int saltLen) +{ + int hashLen, mgf, emLen, mPrimeLen; + enum wc_HashType hashType; + byte *mPrime = NULL; + byte *buf = NULL; + + WOLFSSL_ENTER("wolfSSL_RSA_verify_PKCS1_PSS"); + + if (!rsa || !mHash || !hashAlg || !EM) { + return WOLFSSL_FAILURE; + } + + if ((hashLen = wolfSSL_EVP_MD_size(hashAlg)) < 0) { + return WOLFSSL_FAILURE; + } + + if ((emLen = wolfSSL_RSA_size(rsa)) <= 0) { + WOLFSSL_MSG("wolfSSL_RSA_size error"); + return WOLFSSL_FAILURE; + } + + switch (saltLen) { + /* Negative saltLen values are treated differently */ + case RSA_PSS_SALTLEN_DIGEST: + saltLen = hashLen; + break; + case RSA_PSS_SALTLEN_MAX_SIGN: + case RSA_PSS_SALTLEN_MAX: + saltLen = emLen - hashLen - 2; + break; + default: + if (saltLen < 0) { + /* Not any currently implemented negative value */ + WOLFSSL_MSG("invalid saltLen"); + return WOLFSSL_FAILURE; + } + } + + if (!rsa->exSet && SetRsaExternal(rsa) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + hashType = wolfSSL_EVP_md2macType(hashAlg); + if (hashType < WC_HASH_TYPE_NONE || hashType > WC_HASH_TYPE_MAX) { + WOLFSSL_MSG("wolfSSL_EVP_md2macType error"); + return WOLFSSL_FAILURE; + } + + if ((mgf = hash2mgf(hashType)) == WC_MGF1NONE) { + WOLFSSL_MSG("hash2mgf error"); + return WOLFSSL_FAILURE; + } + + if ((hashLen = wolfSSL_EVP_MD_size(hashAlg)) < 0) { + WOLFSSL_MSG("wolfSSL_EVP_MD_size error"); + return WOLFSSL_FAILURE; + } + + if (!(buf = (byte*)XMALLOC(emLen, NULL, DYNAMIC_TYPE_TMP_BUFFER))) { + WOLFSSL_MSG("malloc error"); + return WOLFSSL_FAILURE; + } + XMEMCPY(buf, EM, emLen); + + /* Remove and verify the PSS padding */ + if ((mPrimeLen = wc_RsaUnPad_ex(buf, emLen, &mPrime, + RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, hashType, + mgf, NULL, 0, saltLen, + wolfSSL_BN_num_bits(rsa->n), NULL)) < 0) { + WOLFSSL_MSG("wc_RsaPad_ex error"); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + /* Verify the hash is correct */ + if (wc_RsaPSS_CheckPadding_ex(mHash, hashLen, mPrime, mPrimeLen, hashType, + saltLen, wolfSSL_BN_num_bits(rsa->n)) + != MP_OKAY) { + WOLFSSL_MSG("wc_RsaPSS_CheckPadding_ex error"); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; +} +#endif + +#if defined(OPENSSL_EXTRA) +WOLFSSL_RSA_METHOD *wolfSSL_RSA_meth_new(const char *name, int flags) +{ + int name_len; + WOLFSSL_RSA_METHOD* meth; + + if (name == NULL) { + return NULL; + } + + meth = (WOLFSSL_RSA_METHOD*)XMALLOC(sizeof(WOLFSSL_RSA_METHOD), NULL, + DYNAMIC_TYPE_OPENSSL); + name_len = (int)XSTRLEN(name); + if (!meth) { + return NULL; + } + meth->flags = flags; + meth->name = (char*)XMALLOC(name_len+1, NULL, DYNAMIC_TYPE_OPENSSL); + if (!meth->name) { + XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + XMEMCPY(meth->name, name, name_len+1); + + return meth; +} + +void wolfSSL_RSA_meth_free(WOLFSSL_RSA_METHOD *meth) +{ + if (meth) { + XFREE(meth->name, NULL, DYNAMIC_TYPE_OPENSSL); + XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_RSA_meth_set(WOLFSSL_RSA_METHOD *rsa, void* p) +{ + (void)rsa; + (void)p; + WOLFSSL_STUB("RSA_METHOD is not implemented."); + return 1; +} +#endif + +int wolfSSL_RSA_set_method(WOLFSSL_RSA *rsa, WOLFSSL_RSA_METHOD *meth) +{ + if (rsa) + rsa->meth = meth; + return 1; +} + +const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_method(const WOLFSSL_RSA *rsa) +{ + if (!rsa) { + return NULL; + } + return rsa->meth; +} + +const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_default_method(void) +{ + return wolfSSL_RSA_meth_new("wolfSSL RSA", 0); +} + +int wolfSSL_RSA_flags(const WOLFSSL_RSA *r) +{ + if (r && r->meth) { + return r->meth->flags; + } else { + return 0; + } +} + +void wolfSSL_RSA_set_flags(WOLFSSL_RSA *r, int flags) +{ + if (r && r->meth) { + r->meth->flags = flags; + } +} + +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA) +WOLFSSL_RSA* wolfSSL_RSAPublicKey_dup(WOLFSSL_RSA *rsa) +{ + int derSz = 0; + byte *derBuf = NULL; + WOLFSSL_RSA* local; + + WOLFSSL_ENTER("wolfSSL_RSAPublicKey_dup"); + + if (!rsa) { + return NULL; + } + + local = wolfSSL_RSA_new(); + if (local == NULL) { + WOLFSSL_MSG("Error creating a new WOLFSSL_RSA structure"); + return NULL; + } + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1)) < 0) { + WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); + return NULL; + } + + if (wolfSSL_RSA_LoadDer_ex(local, + derBuf, derSz, + WOLFSSL_RSA_LOAD_PUBLIC) != SSL_SUCCESS) { + wolfSSL_RSA_free(local); + local = NULL; + } + XFREE(derBuf, NULL, DYNAMIC_TYPE_ASN1); + return local; +} +#endif + +void* wolfSSL_RSA_get_ex_data(const WOLFSSL_RSA *rsa, int idx) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get_ex_data"); +#ifdef HAVE_EX_DATA + if (rsa) { + return wolfSSL_CRYPTO_get_ex_data(&rsa->ex_data, idx); + } +#else + (void)rsa; + (void)idx; +#endif + return NULL; +} + +int wolfSSL_RSA_set_ex_data(WOLFSSL_RSA *rsa, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data"); + #ifdef HAVE_EX_DATA + if (rsa) { + return wolfSSL_CRYPTO_set_ex_data(&rsa->ex_data, idx, data); + } + #else + (void)rsa; + (void)idx; + (void)data; + #endif + return WOLFSSL_FAILURE; +} + +int wolfSSL_RSA_set0_key(WOLFSSL_RSA *r, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e, + WOLFSSL_BIGNUM *d) +{ + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((!r->n && !n) || (!r->e && !e)) + return 0; + + if (n) { + wolfSSL_BN_free(r->n); + r->n = n; + } + if (e) { + wolfSSL_BN_free(r->e); + r->e = e; + } + if (d) { + wolfSSL_BN_clear_free(r->d); + r->d = d; + } + + return 1; +} +#endif /* OPENSSL_EXTRA */ +#endif /* NO_RSA */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_DSA +/* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ +int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, int derSz) +{ + word32 idx = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_DSA_LoadDer"); + + if (dsa == NULL || dsa->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + + ret = DsaPrivateKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, derSz); + if (ret < 0) { + WOLFSSL_MSG("DsaPrivateKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetDsaExternal(dsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDsaExternal failed"); + return WOLFSSL_FATAL_ERROR; + } + + dsa->inSet = 1; + + return WOLFSSL_SUCCESS; +} + +/* Loads DSA key from DER buffer. opt = DSA_LOAD_PRIVATE or DSA_LOAD_PUBLIC. + returns 1 on success, or 0 on failure. */ +int wolfSSL_DSA_LoadDer_ex(WOLFSSL_DSA* dsa, const unsigned char* derBuf, + int derSz, int opt) +{ + word32 idx = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_DSA_LoadDer"); + + if (dsa == NULL || dsa->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + + if (opt == WOLFSSL_DSA_LOAD_PRIVATE) { + ret = DsaPrivateKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, derSz); + } + else { + ret = DsaPublicKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, derSz); + } + + if (ret < 0 && opt == WOLFSSL_DSA_LOAD_PRIVATE) { + WOLFSSL_MSG("DsaPrivateKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; + } + else if (ret < 0 && opt == WOLFSSL_DSA_LOAD_PUBLIC) { + WOLFSSL_MSG("DsaPublicKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetDsaExternal(dsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDsaExternal failed"); + return WOLFSSL_FATAL_ERROR; + } + + dsa->inSet = 1; + + return WOLFSSL_SUCCESS; +} +#endif /* !NO_DSA */ + +#ifdef HAVE_ECC +/* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ +int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, + int derSz) +{ + return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz, + WOLFSSL_EC_KEY_LOAD_PRIVATE); +} + +int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, + int derSz, int opt) +{ + word32 idx = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_LoadDer"); + + if (key == NULL || key->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + + if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { + ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal, + derSz); + } + else { + ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal, + derSz); + } + if (ret < 0) { + if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { + WOLFSSL_MSG("wc_EccPrivateKeyDecode failed"); + } + else { + WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); + } + return WOLFSSL_FATAL_ERROR; + } + + if (SetECKeyExternal(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetECKeyExternal failed"); + return WOLFSSL_FATAL_ERROR; + } + + key->inSet = 1; + + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_ECC */ + +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)) +/* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ +int wolfSSL_DH_LoadDer(WOLFSSL_DH* dh, const unsigned char* derBuf, int derSz) +{ + word32 idx = 0; + int ret; + + if (dh == NULL || dh->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + + ret = wc_DhKeyDecode(derBuf, &idx, (DhKey*)dh->internal, (word32)derSz); + if (ret < 0) { + WOLFSSL_MSG("wc_DhKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetDhExternal(dh) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDhExternal failed"); + return WOLFSSL_FATAL_ERROR; + } + + return WOLFSSL_SUCCESS; +} +#endif /* ! NO_DH && WOLFSSL_QT || OPENSSL_ALL */ + +#endif /* OPENSSL_EXTRA */ + + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + +/* increments ref count of WOLFSSL_RSA. Return 1 on success, 0 on error */ +int wolfSSL_RSA_up_ref(WOLFSSL_RSA* rsa) +{ + if (rsa) { + if (wc_LockMutex(&rsa->refMutex) != 0) { + WOLFSSL_MSG("Failed to lock x509 mutex"); + } + rsa->refCount++; + wc_UnLockMutex(&rsa->refMutex); + + return 1; + } + + return 0; +} + +/* increments ref count of WOLFSSL_X509. Return 1 on success, 0 on error */ +int wolfSSL_X509_up_ref(WOLFSSL_X509* x509) +{ + if (x509) { + if (wc_LockMutex(&x509->refMutex) != 0) { + WOLFSSL_MSG("Failed to lock x509 mutex"); + } + x509->refCount++; + wc_UnLockMutex(&x509->refMutex); + + return 1; + } + + return 0; +} + +#endif /* OPENSSL_EXTRA || OPENSSL_ALL */ + + +#ifdef WOLFSSL_ALT_CERT_CHAINS +int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl) +{ + int isUsing = 0; + if (ssl) + isUsing = ssl->options.usingAltCertChain; + return isUsing; +} +#endif /* WOLFSSL_ALT_CERT_CHAINS */ + + +#ifdef SESSION_CERTS + +#ifdef WOLFSSL_ALT_CERT_CHAINS +/* Get peer's alternate certificate chain */ +WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain"); + if (ssl) + return &ssl->session.altChain; + + return 0; +} +#endif /* WOLFSSL_ALT_CERT_CHAINS */ + + +/* Get peer's certificate chain */ +WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_peer_chain"); + if (ssl) + return &ssl->session.chain; + + return 0; +} + + +/* Get peer's certificate chain total count */ +int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain) +{ + WOLFSSL_ENTER("wolfSSL_get_chain_count"); + if (chain) + return chain->count; + + return 0; +} + + +/* Get peer's ASN.1 DER certificate at index (idx) length in bytes */ +int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) +{ + WOLFSSL_ENTER("wolfSSL_get_chain_length"); + if (chain) + return chain->certs[idx].length; + + return 0; +} + + +/* Get peer's ASN.1 DER certificate at index (idx) */ +byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) +{ + WOLFSSL_ENTER("wolfSSL_get_chain_cert"); + if (chain) + return chain->certs[idx].buffer; + + return 0; +} + + +/* Get peer's wolfSSL X509 certificate at index (idx) */ +WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx) +{ + int ret; + WOLFSSL_X509* x509 = NULL; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; +#else + DecodedCert cert[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_get_chain_X509"); + if (chain != NULL) { + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_DCERT); + if (cert != NULL) + #endif + { + InitDecodedCert(cert, chain->certs[idx].buffer, + chain->certs[idx].length, NULL); + + if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL)) != 0) { + WOLFSSL_MSG("Failed to parse cert"); + } + else { + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + if (x509 == NULL) { + WOLFSSL_MSG("Failed alloc X509"); + } + else { + InitX509(x509, 1, NULL); + + if ((ret = CopyDecodedToX509(x509, cert)) != 0) { + WOLFSSL_MSG("Failed to copy decoded"); + wolfSSL_X509_free(x509); + x509 = NULL; + } + } + } + + FreeDecodedCert(cert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + #endif + } + } + (void)ret; + + return x509; +} + + +/* Get peer's PEM certificate at index (idx), output to buffer if inLen big + enough else return error (-1). If buffer is NULL only calculate + outLen. Output length is in *outLen WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, + unsigned char* buf, int inLen, int* outLen) +{ +#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) + const char* header = NULL; + const char* footer = NULL; + int headerLen; + int footerLen; + int i; + int err; + word32 szNeeded = 0; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); + if (!chain || !outLen || idx < 0 || idx >= wolfSSL_get_chain_count(chain)) + return BAD_FUNC_ARG; + + err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer); + if (err != 0) + return err; + + headerLen = (int)XSTRLEN(header); + footerLen = (int)XSTRLEN(footer); + + /* Null output buffer return size needed in outLen */ + if(!buf) { + if(Base64_Encode(chain->certs[idx].buffer, chain->certs[idx].length, + NULL, &szNeeded) != LENGTH_ONLY_E) + return WOLFSSL_FAILURE; + *outLen = szNeeded + headerLen + footerLen; + return LENGTH_ONLY_E; + } + + /* don't even try if inLen too short */ + if (inLen < headerLen + footerLen + chain->certs[idx].length) + return BAD_FUNC_ARG; + + /* header */ + if (XMEMCPY(buf, header, headerLen) == NULL) + return WOLFSSL_FATAL_ERROR; + + i = headerLen; + + /* body */ + *outLen = inLen; /* input to Base64_Encode */ + if ( (err = Base64_Encode(chain->certs[idx].buffer, + chain->certs[idx].length, buf + i, (word32*)outLen)) < 0) + return err; + i += *outLen; + + /* footer */ + if ( (i + footerLen) > inLen) + return BAD_FUNC_ARG; + if (XMEMCPY(buf + i, footer, footerLen) == NULL) + return WOLFSSL_FATAL_ERROR; + *outLen += headerLen + footerLen; + + return WOLFSSL_SUCCESS; +#else + (void)chain; + (void)idx; + (void)buf; + (void)inLen; + (void)outLen; + return WOLFSSL_FAILURE; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + + +/* get session ID */ +WOLFSSL_ABI +const byte* wolfSSL_get_sessionID(const WOLFSSL_SESSION* session) +{ + WOLFSSL_ENTER("wolfSSL_get_sessionID"); + if (session) + return session->sessionID; + + return NULL; +} + + +#endif /* SESSION_CERTS */ + +#ifdef HAVE_FUZZER +void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) +{ + if (ssl) { + ssl->fuzzerCb = cbf; + ssl->fuzzerCtx = fCtx; + } +} +#endif + +#ifndef NO_CERTS +#ifdef HAVE_PK_CALLBACKS + +#ifdef HAVE_ECC +void wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb) +{ + if (ctx) + ctx->EccKeyGenCb = cb; +} +void wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EccKeyGenCtx = ctx; +} +void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EccKeyGenCtx; + + return NULL; +} + +WOLFSSL_ABI +void wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb) +{ + if (ctx) + ctx->EccSignCb = cb; +} +void wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EccSignCtx = ctx; +} +void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EccSignCtx; + + return NULL; +} + +void wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb) +{ + if (ctx) + ctx->EccVerifyCb = cb; +} +void wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EccVerifyCtx = ctx; +} +void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EccVerifyCtx; + + return NULL; +} + +void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, CallbackEccSharedSecret cb) +{ + if (ctx) + ctx->EccSharedSecretCb = cb; +} +void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EccSharedSecretCtx = ctx; +} +void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EccSharedSecretCtx; + + return NULL; +} +#endif /* HAVE_ECC */ + +#ifdef HAVE_ED25519 +void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) +{ + if (ctx) + ctx->Ed25519SignCb = cb; +} +void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->Ed25519SignCtx = ctx; +} +void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->Ed25519SignCtx; + + return NULL; +} + +void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) +{ + if (ctx) + ctx->Ed25519VerifyCb = cb; +} +void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->Ed25519VerifyCtx = ctx; +} +void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->Ed25519VerifyCtx; + + return NULL; +} +#endif /* HAVE_ED25519 */ + +#ifdef HAVE_CURVE25519 +void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx, + CallbackX25519KeyGen cb) +{ + if (ctx) + ctx->X25519KeyGenCb = cb; +} +void wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->X25519KeyGenCtx = ctx; +} +void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->X25519KeyGenCtx; + + return NULL; +} + +void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX25519SharedSecret cb) +{ + if (ctx) + ctx->X25519SharedSecretCb = cb; +} +void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->X25519SharedSecretCtx = ctx; +} +void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->X25519SharedSecretCtx; + + return NULL; +} +#endif /* HAVE_CURVE25519 */ + +#ifdef HAVE_ED448 +void wolfSSL_CTX_SetEd448SignCb(WOLFSSL_CTX* ctx, CallbackEd448Sign cb) +{ + if (ctx) + ctx->Ed448SignCb = cb; +} +void wolfSSL_SetEd448SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->Ed448SignCtx = ctx; +} +void* wolfSSL_GetEd448SignCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->Ed448SignCtx; + + return NULL; +} + +void wolfSSL_CTX_SetEd448VerifyCb(WOLFSSL_CTX* ctx, CallbackEd448Verify cb) +{ + if (ctx) + ctx->Ed448VerifyCb = cb; +} +void wolfSSL_SetEd448VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->Ed448VerifyCtx = ctx; +} +void* wolfSSL_GetEd448VerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->Ed448VerifyCtx; + + return NULL; +} +#endif /* HAVE_ED448 */ + +#ifdef HAVE_CURVE448 +void wolfSSL_CTX_SetX448KeyGenCb(WOLFSSL_CTX* ctx, + CallbackX448KeyGen cb) +{ + if (ctx) + ctx->X448KeyGenCb = cb; +} +void wolfSSL_SetX448KeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->X448KeyGenCtx = ctx; +} +void* wolfSSL_GetX448KeyGenCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->X448KeyGenCtx; + + return NULL; +} + +void wolfSSL_CTX_SetX448SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX448SharedSecret cb) +{ + if (ctx) + ctx->X448SharedSecretCb = cb; +} +void wolfSSL_SetX448SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->X448SharedSecretCtx = ctx; +} +void* wolfSSL_GetX448SharedSecretCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->X448SharedSecretCtx; + + return NULL; +} +#endif /* HAVE_CURVE448 */ + +#ifndef NO_RSA +void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb) +{ + if (ctx) + ctx->RsaSignCb = cb; +} +void wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) +{ + if (ctx) + ctx->RsaSignCheckCb = cb; +} +void wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->RsaSignCtx = ctx; +} +void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->RsaSignCtx; + + return NULL; +} + + +void wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) +{ + if (ctx) + ctx->RsaVerifyCb = cb; +} +void wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->RsaVerifyCtx = ctx; +} +void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->RsaVerifyCtx; + + return NULL; +} + +#ifdef WC_RSA_PSS +void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) +{ + if (ctx) + ctx->RsaPssSignCb = cb; +} +void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) +{ + if (ctx) + ctx->RsaPssSignCheckCb = cb; +} +void wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->RsaPssSignCtx = ctx; +} +void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->RsaPssSignCtx; + + return NULL; +} + +void wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) +{ + if (ctx) + ctx->RsaPssVerifyCb = cb; +} +void wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->RsaPssVerifyCtx = ctx; +} +void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->RsaPssVerifyCtx; + + return NULL; +} +#endif /* WC_RSA_PSS */ + +void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb) +{ + if (ctx) + ctx->RsaEncCb = cb; +} +void wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->RsaEncCtx = ctx; +} +void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->RsaEncCtx; + + return NULL; +} + +void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) +{ + if (ctx) + ctx->RsaDecCb = cb; +} +void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->RsaDecCtx = ctx; +} +void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->RsaDecCtx; + + return NULL; +} +#endif /* NO_RSA */ + +#endif /* HAVE_PK_CALLBACKS */ +#endif /* NO_CERTS */ + +#if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH) +void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb) +{ + if (ctx) + ctx->DhAgreeCb = cb; +} +void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->DhAgreeCtx = ctx; +} +void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->DhAgreeCtx; + + return NULL; +} +#endif /* HAVE_PK_CALLBACKS && !NO_DH */ + + +#ifdef WOLFSSL_HAVE_WOLFSCEP + /* Used by autoconf to see if wolfSCEP is available */ + void wolfSSL_wolfSCEP(void) {} +#endif + + +#ifdef WOLFSSL_HAVE_CERT_SERVICE + /* Used by autoconf to see if cert service is available */ + void wolfSSL_cert_service(void) {} +#endif + +#ifdef OPENSSL_EXTRA + #ifndef NO_CERTS + void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME *name) + { + WOLFSSL_ENTER("wolfSSL_X509_NAME_free"); + FreeX509Name(name, NULL); + XFREE(name, NULL, DYNAMIC_TYPE_X509); + } + + + /* Malloc's a new WOLFSSL_X509_NAME structure + * + * returns NULL on failure, otherwise returns a new structure. + */ + WOLFSSL_X509_NAME* wolfSSL_X509_NAME_new(void) + { + WOLFSSL_X509_NAME* name; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_new"); + + name = (WOLFSSL_X509_NAME*)XMALLOC(sizeof(WOLFSSL_X509_NAME), NULL, + DYNAMIC_TYPE_X509); + if (name != NULL) { + InitX509Name(name, 1); + } + return name; + } + + /* Creates a duplicate of a WOLFSSL_X509_NAME structure. + Returns a new WOLFSSL_X509_NAME structure or NULL on failure */ + WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(WOLFSSL_X509_NAME *name) + { + WOLFSSL_X509_NAME* dup = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_dup"); + + if (name == NULL) { + WOLFSSL_MSG("NULL parameter"); + return NULL; + } + + if (!(dup = wolfSSL_X509_NAME_new())) { + return NULL; + } + + /* copy contents */ + XMEMCPY(dup, name, sizeof(WOLFSSL_X509_NAME)); + InitX509Name(dup, 1); + dup->sz = name->sz; + + /* handle dynamic portions */ + if (name->dynamicName) { + if (!(dup->name = (char*)XMALLOC(name->sz, 0, + DYNAMIC_TYPE_OPENSSL))) { + goto err; + } + } + XMEMCPY(dup->name, name->name, name->sz); + #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + !defined(NO_ASN) + if (!(dup->fullName.fullName = (char*)XMALLOC(name->fullName.fullNameLen, + 0, DYNAMIC_TYPE_OPENSSL))) { + goto err; + } + XMEMCPY(dup->fullName.fullName, name->fullName.fullName, + name->fullName.fullNameLen); + #endif + + return dup; + + err: + if (dup) { + if (dup->dynamicName && dup->name) { + XFREE(dup->name, 0, DYNAMIC_TYPE_OPENSSL); + dup->name = NULL; + } + #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + !defined(NO_ASN) + if (dup->fullName.fullName && + dup->fullName.fullName != name->fullName.fullName) { + XFREE(dup->fullName.fullName, 0, DYNAMIC_TYPE_OPENSSL); + dup->fullName.fullName = NULL; + } + #endif + wolfSSL_X509_NAME_free(dup); + } + return NULL; + } + +#if defined(WOLFSSL_CERT_GEN) + /* helper function for CopyX509NameToCertName() + * + * returns WOLFSSL_SUCCESS on success + */ + static int CopyX509NameEntry(char* out, int mx, char* in, int inLen) + { + if (inLen > mx) { + WOLFSSL_MSG("Name too long"); + XMEMCPY(out, in, mx); + } + else { + XMEMCPY(out, in, inLen); + out[inLen] = '\0'; + } + + /* make sure is null terminated */ + out[mx-1] = '\0'; + + return WOLFSSL_SUCCESS; + } + + + /* Helper function to copy cert name from a WOLFSSL_X509_NAME structure to + * a CertName structure. + * + * returns WOLFSSL_SUCCESS on success and a negative error value on failure + */ + static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName) + { + DecodedName* dn = NULL; + + if (n == NULL || cName == NULL) { + return BAD_FUNC_ARG; + } + + dn = &(n->fullName); + + /* initialize cert name */ + cName->country[0] = '\0'; + cName->countryEnc = CTC_PRINTABLE; + cName->state[0] = '\0'; + cName->stateEnc = CTC_UTF8; + cName->locality[0] = '\0'; + cName->localityEnc = CTC_UTF8; + cName->sur[0] = '\0'; + cName->surEnc = CTC_UTF8; + cName->org[0] = '\0'; + cName->orgEnc = CTC_UTF8; + cName->unit[0] = '\0'; + cName->unitEnc = CTC_UTF8; + cName->commonName[0] = '\0'; + cName->commonNameEnc = CTC_UTF8; + cName->serialDev[0] = '\0'; + cName->serialDevEnc = CTC_PRINTABLE; + #ifdef WOLFSSL_CERT_EXT + cName->busCat[0] = '\0'; + cName->busCatEnc = CTC_UTF8; + cName->joiC[0] = '\0'; + cName->joiCEnc = CTC_PRINTABLE; + cName->joiSt[0] = '\0'; + cName->joiStEnc = CTC_PRINTABLE; + #endif + cName->email[0] = '\0'; + + + /* ASN_COUNTRY_NAME */ + WOLFSSL_MSG("Copy Country Name"); + if (CopyX509NameEntry(cName->country, CTC_NAME_SIZE, dn->fullName + dn->cIdx, + dn->cLen) != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_ORGUNIT_NAME */ + WOLFSSL_MSG("Copy Org Unit Name"); + if (CopyX509NameEntry(cName->unit, CTC_NAME_SIZE, dn->fullName + dn->ouIdx, + dn->ouLen) != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_ORG_NAME */ + WOLFSSL_MSG("Copy Org Name"); + if (CopyX509NameEntry(cName->org, CTC_NAME_SIZE, dn->fullName + dn->oIdx, + dn->oLen) != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_STATE_NAME */ + WOLFSSL_MSG("Copy State Name"); + if (CopyX509NameEntry(cName->state, CTC_NAME_SIZE, dn->fullName + dn->stIdx, + dn->stLen) != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_LOCALITY_NAME */ + WOLFSSL_MSG("Copy Locality Name"); + if (CopyX509NameEntry(cName->locality, CTC_NAME_SIZE, + dn->fullName + dn->lIdx, dn->lLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_SUR_NAME */ + WOLFSSL_MSG("Copy Sur Name"); + if (CopyX509NameEntry(cName->sur, CTC_NAME_SIZE, dn->fullName + dn->snIdx, + dn->snLen) != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_COMMON_NAME */ + WOLFSSL_MSG("Copy Common Name"); + if (CopyX509NameEntry(cName->commonName, CTC_NAME_SIZE, + dn->fullName + dn->cnIdx, dn->cnLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + + /* ASN_SERIAL_NUMBER */ + WOLFSSL_MSG("Copy Serial Number of Device"); + if (CopyX509NameEntry(cName->serialDev, CTC_NAME_SIZE, + dn->fullName + dn->serialIdx, dn->serialLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + + #ifdef WOLFSSL_CERT_EXT + /* ASN_BUS_CAT */ + WOLFSSL_MSG("Copy Business Category"); + if (CopyX509NameEntry(cName->busCat, CTC_NAME_SIZE, + dn->fullName + dn->bcIdx, dn->bcLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + + /* JoI Country */ + WOLFSSL_MSG("Copy Jurisdiction of Incorporation Country"); + if (CopyX509NameEntry(cName->joiC, CTC_NAME_SIZE, + dn->fullName + dn->jcIdx, dn->jcLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + + /* JoI State */ + WOLFSSL_MSG("Copy Jurisdiction of Incorporation State"); + if (CopyX509NameEntry(cName->joiSt, CTC_NAME_SIZE, + dn->fullName + dn->jsIdx, dn->jsLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + #endif + + WOLFSSL_MSG("Copy Email"); + if (CopyX509NameEntry(cName->email, CTC_NAME_SIZE, + dn->fullName + dn->emailIdx, dn->emailLen) + != SSL_SUCCESS) { + return BUFFER_E; + } + + return WOLFSSL_SUCCESS; + } + +#ifdef WOLFSSL_CERT_REQ + static int ReqCertFromX509(Cert* cert, WOLFSSL_X509* req) + { + int ret; + + if (wc_InitCert(cert) != 0) + return WOLFSSL_FAILURE; + + ret = CopyX509NameToCertName(&req->subject, &cert->subject); + if (ret == WOLFSSL_SUCCESS) { + cert->version = req->version; + cert->isCA = req->isCa; +#ifdef WOLFSSL_CERT_EXT + if (req->subjKeyIdSz != 0) { + XMEMCPY(cert->skid, req->subjKeyId, req->subjKeyIdSz); + cert->skidSz = req->subjKeyIdSz; + } + if (req->keyUsageSet) + cert->keyUsage = req->keyUsage; + /* Extended Key Usage not supported. */ +#endif + } + + return ret; + } +#endif + + /* convert a WOLFSSL_X509 to a Cert structure for writing out */ + static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) + { + int ret; + #ifdef WOLFSSL_CERT_EXT + int i; + #endif + + WOLFSSL_ENTER("wolfSSL_X509_to_Cert()"); + + if (x509 == NULL || cert == NULL) { + return BAD_FUNC_ARG; + } + + wc_InitCert(cert); + + cert->version = (int)wolfSSL_X509_get_version(x509); + + #ifdef WOLFSSL_ALT_NAMES + if (x509->notBefore.length > 0) { + if ((x509->notBefore.length + 2) < CTC_DATE_SIZE) { + cert->beforeDate[0] = x509->notBefore.type; + cert->beforeDate[1] = x509->notBefore.length; + XMEMCPY(&cert->beforeDate[2], x509->notBefore.data, + x509->notBefore.length); + cert->beforeDateSz = x509->notBefore.length + 2; + } + else { + WOLFSSL_MSG("Not before date too large"); + return WOLFSSL_FAILURE; + } + } + else { + cert->beforeDateSz = 0; + } + if (x509->notAfter.length > 0) { + if ((x509->notAfter.length + 2) < CTC_DATE_SIZE) { + cert->afterDate[0] = x509->notAfter.type; + cert->afterDate[1] = x509->notAfter.length; + XMEMCPY(&cert->afterDate[2], x509->notAfter.data, + x509->notAfter.length); + cert->afterDateSz = x509->notAfter.length + 2; + } + else { + WOLFSSL_MSG("Not after date too large"); + return WOLFSSL_FAILURE; + } + } + else { + cert->afterDateSz = 0; + } + + cert->altNamesSz = FlattenAltNames(cert->altNames, + sizeof(cert->altNames), x509->altNames); + + #endif /* WOLFSSL_ALT_NAMES */ + + cert->sigType = wolfSSL_X509_get_signature_type(x509); + cert->keyType = x509->pubKeyOID; + cert->isCA = wolfSSL_X509_get_isCA(x509); + + #ifdef WOLFSSL_CERT_EXT + if (x509->subjKeyIdSz < CTC_MAX_SKID_SIZE) { + XMEMCPY(cert->skid, x509->subjKeyId, x509->subjKeyIdSz); + cert->skidSz = (int)x509->subjKeyIdSz; + } + else { + WOLFSSL_MSG("Subject Key ID too large"); + return WOLFSSL_FAILURE; + } + + if (x509->authKeyIdSz < CTC_MAX_AKID_SIZE) { + XMEMCPY(cert->akid, x509->authKeyId, x509->authKeyIdSz); + cert->akidSz = (int)x509->authKeyIdSz; + } + else { + WOLFSSL_MSG("Auth Key ID too large"); + return WOLFSSL_FAILURE; + } + + for (i = 0; i < x509->certPoliciesNb; i++) { + /* copy the smaller of MAX macros, by default they are currently equal*/ + if ((int)CTC_MAX_CERTPOL_SZ <= (int)MAX_CERTPOL_SZ) { + XMEMCPY(cert->certPolicies[i], x509->certPolicies[i], + CTC_MAX_CERTPOL_SZ); + } + else { + XMEMCPY(cert->certPolicies[i], x509->certPolicies[i], + MAX_CERTPOL_SZ); + } + } + cert->certPoliciesNb = (word16)x509->certPoliciesNb; + + cert->keyUsage = x509->keyUsage; + #endif /* WOLFSSL_CERT_EXT */ + + #ifdef WOLFSSL_CERT_REQ + /* copy over challenge password for REQ certs */ + XMEMCPY(cert->challengePw, x509->challengePw, CTC_NAME_SIZE); + #endif + + if (x509->serialSz <= CTC_SERIAL_SIZE) { + XMEMCPY(cert->serial, x509->serial, x509->serialSz); + } + else { + WOLFSSL_MSG("Serial size error"); + return WOLFSSL_FAILURE; + } + + /* copy over Name structures */ + if (x509->issuerSet) + cert->selfSigned = 0; + if ((ret = CopyX509NameToCertName(&(x509->issuer), &(cert->issuer))) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error copying over issuer names"); + WOLFSSL_LEAVE("wolfSSL_X509_to_Cert()", ret); + return WOLFSSL_FAILURE; + } + if ((ret = CopyX509NameToCertName(&(x509->subject), &(cert->subject))) + != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error copying over subject names"); + WOLFSSL_LEAVE("wolfSSL_X509_to_Cert()", ret); + return WOLFSSL_FAILURE; + } + + cert->heap = x509->heap; + + return WOLFSSL_SUCCESS; + } + + + /* returns the sig type to use on success i.e CTC_SHAwRSA and WOLFSSL_FALURE + * on fail case */ + static int wolfSSL_sigTypeFromPKEY(WOLFSSL_EVP_MD* md, + WOLFSSL_EVP_PKEY* pkey) + { + int hashType; + int sigType = WOLFSSL_FAILURE; + + /* Convert key type and hash algorithm to a signature algorithm */ + if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) == WOLFSSL_FAILURE) + return WOLFSSL_FAILURE; + + + if (pkey->type == EVP_PKEY_RSA) { + switch (hashType) { + case WC_HASH_TYPE_SHA: + sigType = CTC_SHAwRSA; + break; + case WC_HASH_TYPE_SHA224: + sigType = CTC_SHA224wRSA; + break; + case WC_HASH_TYPE_SHA256: + sigType = CTC_SHA256wRSA; + break; + case WC_HASH_TYPE_SHA384: + sigType = CTC_SHA384wRSA; + break; + case WC_HASH_TYPE_SHA512: + sigType = CTC_SHA512wRSA; + break; + default: + return WOLFSSL_FAILURE; + } + } + else if (pkey->type == EVP_PKEY_EC) { + switch (hashType) { + case WC_HASH_TYPE_SHA: + sigType = CTC_SHAwECDSA; + break; + case WC_HASH_TYPE_SHA224: + sigType = CTC_SHA224wECDSA; + break; + case WC_HASH_TYPE_SHA256: + sigType = CTC_SHA256wECDSA; + break; + case WC_HASH_TYPE_SHA384: + sigType = CTC_SHA384wECDSA; + break; + case WC_HASH_TYPE_SHA512: + sigType = CTC_SHA512wECDSA; + break; + default: + return WOLFSSL_FAILURE; + } + } + else + return WOLFSSL_FAILURE; + return sigType; + } + + + /* generates DER buffer from WOLFSSL_X509 + * If req == 1 then creates a request DER buffer + * + * updates derSz with certificate body size on success + * return WOLFSSL_SUCCESS on success + */ + static int wolfSSL_X509_make_der(WOLFSSL_X509* x509, int req, + unsigned char* der, int* derSz) + { + int ret; + Cert cert; + void* key = NULL; + int type = -1; + #ifndef NO_RSA + RsaKey rsa; + #endif + #ifdef HAVE_ECC + ecc_key ecc; + #endif + WC_RNG rng; + word32 idx = 0; + + if (x509 == NULL || der == NULL || derSz == NULL) + return BAD_FUNC_ARG; + + #ifndef WOLFSSL_CERT_REQ + if (req) { + WOLFSSL_MSG("WOLFSSL_CERT_REQ needed for certificate request"); + return WOLFSSL_FAILURE; + } + #endif + + #ifdef WOLFSSL_CERT_REQ + if (req) { + if (ReqCertFromX509(&cert, x509) != WOLFSSL_SUCCESS) + return WOLFSSL_FAILURE; + } + else + #endif + { + /* Create a Cert that has the certificate fields. */ + if (CertFromX509(&cert, x509) != WOLFSSL_SUCCESS) + return WOLFSSL_FAILURE; + } + + /* Create a public key object from requests public key. */ + #ifndef NO_RSA + if (x509->pubKeyOID == RSAk) { + type = RSA_TYPE; + ret = wc_InitRsaKey(&rsa, x509->heap); + if (ret != 0) + return ret; + ret = wc_RsaPublicKeyDecode(x509->pubKey.buffer, &idx, &rsa, + x509->pubKey.length); + if (ret != 0) { + wc_FreeRsaKey(&rsa); + return ret; + } + key = (void*)&rsa; + } + #endif + #ifdef HAVE_ECC + if (x509->pubKeyOID == ECDSAk) { + type = ECC_TYPE; + ret = wc_ecc_init(&ecc); + if (ret != 0) + return ret; + ret = wc_EccPublicKeyDecode(x509->pubKey.buffer, &idx, &ecc, + x509->pubKey.length); + if (ret != 0) { + wc_ecc_free(&ecc); + return ret; + } + key = (void*)&ecc; + } + #endif + if (key == NULL) + return WOLFSSL_FAILURE; + + /* Make the body of the certificate request. */ + #ifdef WOLFSSL_CERT_REQ + if (req) { + ret = wc_MakeCertReq_ex(&cert, der, *derSz, type, key); + } + else + #endif + { + ret = wc_InitRng(&rng); + if (ret != 0) + return WOLFSSL_FAILURE; + + ret = wc_MakeCert_ex(&cert, der, *derSz, type, key, &rng); + wc_FreeRng(&rng); + } + if (ret < 0) { + return ret; + } + + /* Dispose of the public key object. */ + #ifndef NO_RSA + if (x509->pubKeyOID == RSAk) + wc_FreeRsaKey(&rsa); + #endif + #ifdef HAVE_ECC + if (x509->pubKeyOID == ECDSAk) + wc_ecc_free(&ecc); + #endif + *derSz = ret; + + return WOLFSSL_SUCCESS; + } + + + /* signs a der buffer for the WOLFSSL_X509 structure using the PKEY and MD + * hash passed in + * + * WARNING: this free's and replaces the existing DER buffer in the + * WOLFSSL_X509 with the newly signed buffer. + * returns size of signed buffer on success and negative values on fail + */ + static int wolfSSL_X509_resign_cert(WOLFSSL_X509* x509, int req, + unsigned char* der, int derSz, int certBodySz, WOLFSSL_EVP_MD* md, + WOLFSSL_EVP_PKEY* pkey) + { + int ret; + void* key = NULL; + int type = -1; + int sigType; + WC_RNG rng; + + sigType = wolfSSL_sigTypeFromPKEY(md, pkey); + if (sigType == WOLFSSL_FAILURE) + return WOLFSSL_FATAL_ERROR; + + + /* Get the private key object and type from pkey. */ + #ifndef NO_RSA + if (pkey->type == EVP_PKEY_RSA) { + type = RSA_TYPE; + key = pkey->rsa->internal; + } + #endif + #ifdef HAVE_ECC + if (pkey->type == EVP_PKEY_EC) { + type = ECC_TYPE; + key = pkey->ecc->internal; + } + #endif + + /* Sign the certificate request body. */ + ret = wc_InitRng(&rng); + if (ret != 0) + return ret; + ret = wc_SignCert_ex(certBodySz, sigType, der, derSz, type, key, &rng); + wc_FreeRng(&rng); + if (ret < 0) + return ret; + + /* Put in the new certificate encoding into the x509 object. */ + FreeDer(&x509->derCert); + type = CERT_TYPE; + #ifdef WOLFSSL_REQ_CERT + if (req) { + type = CERTREQ_TYPE; + } + #endif + + if (AllocDer(&x509->derCert, ret, type, NULL) != 0) + return WOLFSSL_FATAL_ERROR; + XMEMCPY(x509->derCert->buffer, der, ret); + x509->derCert->length = ret; + + (void)req; + return ret; + } + + + /* returns the size of signature on success */ + int wolfSSL_X509_sign(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, + const WOLFSSL_EVP_MD* md) + { + int ret; + byte der[4096]; /* @TODO dynamic set based on expected cert size */ + int derSz = sizeof(der); + + WOLFSSL_ENTER("wolfSSL_X509_sign"); + + if (x509 == NULL || pkey == NULL || md == NULL) + return WOLFSSL_FAILURE; + + x509->sigOID = wolfSSL_sigTypeFromPKEY((WOLFSSL_EVP_MD*)md, pkey); + if ((ret = wolfSSL_X509_make_der(x509, 0, der, &derSz)) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Unable to make DER for X509"); + WOLFSSL_LEAVE("wolfSSL_X509_sign", ret); + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_X509_resign_cert(x509, 0, der, sizeof(der), derSz, + (WOLFSSL_EVP_MD*)md, pkey); + if (ret <= 0) { + WOLFSSL_LEAVE("wolfSSL_X509_sign", ret); + return WOLFSSL_FAILURE; + } + + return ret; + } + + + /* Converts the x509 name structure into DER format. + * + * out pointer to either a pre setup buffer or a pointer to null for + * creating a dynamic buffer. In the case that a pre-existing buffer is + * used out will be incremented the size of the DER buffer on success. + * + * returns the size of the buffer on success, or negative value with failure + */ + int wolfSSL_i2d_X509_NAME(WOLFSSL_X509_NAME* name, unsigned char** out) + { + CertName cName; + unsigned char buf[256]; /* ASN_MAX_NAME */ + int sz; + WOLFSSL_ENTER("wolfSSL_i2d_X509_NAME"); + + if (out == NULL || name == NULL) { + return BAD_FUNC_ARG; + } + XMEMSET(&cName, 0, sizeof(CertName)); + + if (CopyX509NameToCertName(name, &cName) != SSL_SUCCESS) { + WOLFSSL_MSG("Error converting x509 name to internal CertName"); + return SSL_FATAL_ERROR; + } + + sz = SetName(buf, sizeof(buf), &cName); + if (sz < 0) { + return sz; + } + + /* using buffer passed in */ + if (*out != NULL) { + XMEMCPY(*out, buf, sz); + *out += sz; + } + else { + *out = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL); + if (*out == NULL) { + return MEMORY_E; + } + XMEMCPY(*out, buf, sz); + } + + return sz; + } +#endif /* WOLFSSL_CERT_GEN */ + + + /* Compares the two X509 names. If the size of x is larger then y then a + * positive value is returned if x is smaller a negative value is returned. + * In the case that the sizes are equal a the value of strcmp between the + * two names is returned. + * + * x First name for comparison + * y Second name to compare with x + */ + int wolfSSL_X509_NAME_cmp(const WOLFSSL_X509_NAME* x, + const WOLFSSL_X509_NAME* y) + { + const char* _x; + const char* _y; + WOLFSSL_ENTER("wolfSSL_X509_NAME_cmp"); + + if (x == NULL || y == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return -2; + } + + if (x == y) { + return 0; /* match */ + } + + if (x->sz != y->sz) { + return x->sz - y->sz; + } + + /* + * If the name member is not set or is immediately null terminated then + * compare the staticName member + */ + _x = (x->name && *x->name) ? x->name : x->staticName; + _y = (y->name && *y->name) ? y->name : y->staticName; + + return XSTRNCMP(_x, _y, x->sz); /* y sz is the same */ + } + + + WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, + pem_password_cb *cb, void *u) + { + WOLFSSL_X509* x509 = NULL; +#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) + unsigned char* pem = NULL; + int pemSz; + long i = 0, l; + const char* footer = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509"); + + if (bp == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_X509", BAD_FUNC_ARG); + return NULL; + } + + if ((l = wolfSSL_BIO_get_len(bp)) <= 0) { + #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + /* No certificate in buffer */ + WOLFSSL_ERROR(ASN_NO_PEM_HEADER); + #endif + return NULL; + } + + pem = (unsigned char*)XMALLOC(l, 0, DYNAMIC_TYPE_PEM); + if (pem == NULL) + return NULL; + + i = 0; + if (wc_PemGetHeaderFooter(CERT_TYPE, NULL, &footer) != 0) { + XFREE(pem, 0, DYNAMIC_TYPE_PEM); + return NULL; + } + + /* TODO: Inefficient + * reading in one byte at a time until see "END CERTIFICATE" + */ + while ((l = wolfSSL_BIO_read(bp, (char *)&pem[i], 1)) == 1) { + i++; + if (i > 26 && XMEMCMP((char *)&pem[i-26], footer, 25) == 0) { + if (pem[i-1] == '\r') { + /* found \r , Windows line ending is \r\n so try to read one + * more byte for \n, ignoring return value */ + (void)wolfSSL_BIO_read(bp, (char *)&pem[i++], 1); + } + break; + } + } + #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + if (l == 0) + WOLFSSL_ERROR(ASN_NO_PEM_HEADER); + #endif + pemSz = (int)i; + x509 = wolfSSL_X509_load_certificate_buffer(pem, pemSz, + WOLFSSL_FILETYPE_PEM); + + if (x != NULL) { + *x = x509; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ + (void)bp; + (void)x; + (void)cb; + (void)u; + + return x509; + } + + WOLFSSL_X509_CRL *wolfSSL_PEM_read_bio_X509_CRL(WOLFSSL_BIO *bp, + WOLFSSL_X509_CRL **x, pem_password_cb *cb, void *u) + { +#if defined(WOLFSSL_PEM_TO_DER) && defined(HAVE_CRL) + unsigned char* pem = NULL; + int pemSz; + int derSz; + DerBuffer* der = NULL; + WOLFSSL_X509_CRL* crl = NULL; + + if ((pemSz = wolfSSL_BIO_get_len(bp)) <= 0) { + goto err; + } + + pem = (unsigned char*)XMALLOC(pemSz, 0, DYNAMIC_TYPE_PEM); + if (pem == NULL) { + goto err; + } + + if (wolfSSL_BIO_read(bp, pem, pemSz) != pemSz) { + goto err; + } + + if((PemToDer(pem, pemSz, CRL_TYPE, &der, NULL, NULL, NULL)) < 0) { + goto err; + } + derSz = der->length; + if((crl = wolfSSL_d2i_X509_CRL(x, der->buffer, derSz)) == NULL) { + goto err; + } + +err: + if(pem != NULL) { + XFREE(pem, 0, DYNAMIC_TYPE_PEM); + } + if(der != NULL) { + FreeDer(&der); + } + + (void)cb; + (void)u; + + return crl; +#else + (void)bp; + (void)x; + (void)cb; + (void)u; + + return NULL; +#endif + } + +#if !defined(NO_FILESYSTEM) + static void* wolfSSL_PEM_read_X509_ex(XFILE fp, void **x, + pem_password_cb *cb, void *u, int type) + { + unsigned char* pem = NULL; + int pemSz; + long i = 0, l; + void *newx509; + int derSz; + DerBuffer* der = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_read_X509"); + + if (fp == XBADFILE) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_X509", BAD_FUNC_ARG); + return NULL; + } + /* Read cert from file */ + i = XFTELL(fp); + if (i < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_X509", BAD_FUNC_ARG); + return NULL; + } + + if (XFSEEK(fp, 0, XSEEK_END) != 0) + return NULL; + l = XFTELL(fp); + if (l < 0) + return NULL; + if (XFSEEK(fp, i, SEEK_SET) != 0) + return NULL; + pemSz = (int)(l - i); + + /* check calculated length */ + if (pemSz > MAX_WOLFSSL_FILE_SIZE || pemSz < 0) { + WOLFSSL_MSG("PEM_read_X509_ex file size error"); + return NULL; + } + + /* allocate pem buffer */ + pem = (unsigned char*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_PEM); + if (pem == NULL) + return NULL; + + if ((int)XFREAD((char *)pem, 1, pemSz, fp) != pemSz) + goto err_exit; + + switch (type) { + case CERT_TYPE: + newx509 = (void *)wolfSSL_X509_load_certificate_buffer(pem, + pemSz, WOLFSSL_FILETYPE_PEM); + break; + + #ifdef HAVE_CRL + case CRL_TYPE: + if ((PemToDer(pem, pemSz, CRL_TYPE, &der, NULL, NULL, NULL)) < 0) + goto err_exit; + derSz = der->length; + newx509 = (void*)wolfSSL_d2i_X509_CRL((WOLFSSL_X509_CRL **)x, + (const unsigned char *)der->buffer, derSz); + if (newx509 == NULL) + goto err_exit; + FreeDer(&der); + break; + #endif + + default: + goto err_exit; + } + if (x != NULL) { + *x = newx509; + } + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + return newx509; + + err_exit: + if (pem != NULL) + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + if (der != NULL) + FreeDer(&der); + + /* unused */ + (void)cb; + (void)u; + (void)derSz; + + return NULL; + } + + WOLFSSL_API WOLFSSL_X509* wolfSSL_PEM_read_X509(XFILE fp, WOLFSSL_X509 **x, + pem_password_cb *cb, void *u) + { + return (WOLFSSL_X509* )wolfSSL_PEM_read_X509_ex(fp, (void **)x, cb, u, CERT_TYPE); + } + +#if defined(HAVE_CRL) + WOLFSSL_API WOLFSSL_X509_CRL* wolfSSL_PEM_read_X509_CRL(XFILE fp, WOLFSSL_X509_CRL **crl, + pem_password_cb *cb, void *u) + { + return (WOLFSSL_X509_CRL* )wolfSSL_PEM_read_X509_ex(fp, (void **)crl, cb, u, CRL_TYPE); + } +#endif + + int wolfSSL_PEM_write_X509(XFILE fp, WOLFSSL_X509* x) + { + int ret; + WOLFSSL_BIO* bio; + + if (x == NULL) + return 0; + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); + if (bio == NULL) + return 0; + + if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) { + wolfSSL_BIO_free(bio); + bio = NULL; + } + + ret = wolfSSL_PEM_write_bio_X509(bio, x); + + if (bio != NULL) + wolfSSL_BIO_free(bio); + + return ret; + } +#endif /* !NO_FILESYSTEM */ + + #define PEM_BEGIN "-----BEGIN " + #define PEM_BEGIN_SZ 11 + #define PEM_END "-----END " + #define PEM_END_SZ 9 + #define PEM_HDR_FIN "-----" + #define PEM_HDR_FIN_SZ 5 + #define PEM_HDR_FIN_EOL_NEWLINE "-----\n" + #define PEM_HDR_FIN_EOL_NULL_TERM "-----\0" + #define PEM_HDR_FIN_EOL_SZ 6 + + int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header, + unsigned char **data, long *len) + { + int ret = WOLFSSL_SUCCESS; + char pem[256]; + int pemLen; + char* p; + char* nameStr = NULL; + int nameLen = 0; + char* headerStr = NULL; + int headerLen; + int headerFound = 0; + unsigned char* der = NULL; + word32 derLen = 0; + + if (bio == NULL || name == NULL || header == NULL || data == NULL || + len == NULL) { + return WOLFSSL_FAILURE; + } + + /* Find header line. */ + pem[sizeof(pem) - 1] = '\0'; + while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { + if (XSTRNCMP(pem, PEM_BEGIN, PEM_BEGIN_SZ) == 0) + break; + } + if (pemLen <= 0) + ret = WOLFSSL_FAILURE; + /* Have a header line. */ + if (ret == WOLFSSL_SUCCESS) { + while (pem[pemLen - 1] == '\r' || pem[pemLen - 1] == '\n') + pemLen--; + pem[pemLen] = '\0'; + if (XSTRNCMP(pem + pemLen - PEM_HDR_FIN_SZ, PEM_HDR_FIN, + PEM_HDR_FIN_SZ) != 0) { + ret = WOLFSSL_FAILURE; + } + } + + /* Get out name. */ + if (ret == WOLFSSL_SUCCESS) { + nameLen = pemLen - PEM_BEGIN_SZ - PEM_HDR_FIN_SZ; + nameStr = (char*)XMALLOC(nameLen + 1, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (nameStr == NULL) + ret = WOLFSSL_FAILURE; + } + if (ret == WOLFSSL_SUCCESS) { + XSTRNCPY(nameStr, pem + PEM_BEGIN_SZ, nameLen); + nameStr[nameLen] = '\0'; + + /* Get header of PEM - encryption header. */ + headerLen = 0; + while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { + while (pemLen > 0 && (pem[pemLen - 1] == '\r' || + pem[pemLen - 1] == '\n')) { + pemLen--; + } + pem[pemLen++] = '\n'; + pem[pemLen] = '\0'; + + /* Header separator is a blank line. */ + if (pem[0] == '\n') { + headerFound = 1; + break; + } + + /* Didn't find a blank line - no header. */ + if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) { + der = (unsigned char*)headerStr; + derLen = headerLen; + /* Empty header - empty string. */ + headerStr = (char*)XMALLOC(1, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (headerStr == NULL) + ret = WOLFSSL_FAILURE; + else + headerStr[0] = '\0'; + break; + } + + p = (char*)XREALLOC(headerStr, headerLen + pemLen + 1, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (p == NULL) { + ret = WOLFSSL_FAILURE; + break; + } + + headerStr = p; + XMEMCPY(headerStr + headerLen, pem, pemLen + 1); + headerLen += pemLen; + } + if (pemLen <= 0) + ret = WOLFSSL_FAILURE; + } + + /* Get body of PEM - if there was a header */ + if (ret == WOLFSSL_SUCCESS && headerFound) { + derLen = 0; + while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { + while (pemLen > 0 && (pem[pemLen - 1] == '\r' || + pem[pemLen - 1] == '\n')) { + pemLen--; + } + pem[pemLen++] = '\n'; + pem[pemLen] = '\0'; + + if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) + break; + + p = (char*)XREALLOC(der, derLen + pemLen + 1, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (p == NULL) { + ret = WOLFSSL_FAILURE; + break; + } + + der = (unsigned char*)p; + XMEMCPY(der + derLen, pem, pemLen + 1); + derLen += pemLen; + } + if (pemLen <= 0) + ret = WOLFSSL_FAILURE; + } + + /* Check trailer. */ + if (ret == WOLFSSL_SUCCESS) { + if (XSTRNCMP(pem + PEM_END_SZ, nameStr, nameLen) != 0) + ret = WOLFSSL_FAILURE; + } + if (ret == WOLFSSL_SUCCESS) { + if (XSTRNCMP(pem + PEM_END_SZ + nameLen, + PEM_HDR_FIN_EOL_NEWLINE, + PEM_HDR_FIN_EOL_SZ) != 0 && + XSTRNCMP(pem + PEM_END_SZ + nameLen, + PEM_HDR_FIN_EOL_NULL_TERM, + PEM_HDR_FIN_EOL_SZ) != 0) { + ret = WOLFSSL_FAILURE; + } + } + + /* Base64 decode body. */ + if (ret == WOLFSSL_SUCCESS) { + if (Base64_Decode(der, derLen, der, &derLen) != 0) + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + *name = nameStr; + *header = headerStr; + *data = der; + *len = derLen; + nameStr = NULL; + headerStr = NULL; + der = NULL; + } + + if (nameStr != NULL) + XFREE(nameStr, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (headerStr != NULL) + XFREE(headerStr, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der != NULL) + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; + } + + int wolfSSL_PEM_write_bio(WOLFSSL_BIO* bio, const char *name, + const char *header, const unsigned char *data, + long len) + { + int err = 0; + int outSz = 0; + int nameLen; + int headerLen; + byte* pem = NULL; + word32 pemLen; + word32 derLen = (word32)len; + + if (bio == NULL || name == NULL || header == NULL || data == NULL) + return 0; + + nameLen = (int)XSTRLEN(name); + headerLen = (int)XSTRLEN(header); + + pemLen = (derLen + 2) / 3 * 4; + pemLen += (pemLen + 63) / 64; + + pem = (byte*)XMALLOC(pemLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + err = pem == NULL; + if (!err) + err = Base64_Encode(data, derLen, pem, &pemLen) != 0; + + if (!err) { + err = wolfSSL_BIO_write(bio, PEM_BEGIN, PEM_BEGIN_SZ) != + (int)PEM_BEGIN_SZ; + } + if (!err) + err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen; + if (!err) { + err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL_NEWLINE, + PEM_HDR_FIN_EOL_SZ) != (int)PEM_HDR_FIN_EOL_SZ; + } + if (!err && headerLen > 0) { + err = wolfSSL_BIO_write(bio, header, headerLen) != headerLen; + /* Blank line after a header and before body. */ + if (!err) + err = wolfSSL_BIO_write(bio, "\n", 1) != 1; + headerLen++; + } + if (!err) + err = wolfSSL_BIO_write(bio, pem, pemLen) != (int)pemLen; + if (!err) + err = wolfSSL_BIO_write(bio, PEM_END, PEM_END_SZ) != + (int)PEM_END_SZ; + if (!err) + err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen; + if (!err) { + err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL_NEWLINE, + PEM_HDR_FIN_EOL_SZ) != (int)PEM_HDR_FIN_EOL_SZ; + } + + if (!err) { + outSz = PEM_BEGIN_SZ + nameLen + PEM_HDR_FIN_EOL_SZ + headerLen + + pemLen + PEM_END_SZ + nameLen + PEM_HDR_FIN_EOL_SZ; + } + + if (pem != NULL) + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return outSz; + } + +#if !defined(NO_FILESYSTEM) + int wolfSSL_PEM_read(XFILE fp, char **name, char **header, + unsigned char **data, long *len) + { + int ret; + WOLFSSL_BIO* bio; + + if (name == NULL || header == NULL || data == NULL || len == NULL) + return WOLFSSL_FAILURE; + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); + if (bio == NULL) + return 0; + + if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) { + wolfSSL_BIO_free(bio); + bio = NULL; + } + + ret = wolfSSL_PEM_read_bio(bio, name, header, data, len); + + if (bio != NULL) + wolfSSL_BIO_free(bio); + + return ret; + } + + int wolfSSL_PEM_write(XFILE fp, const char *name, const char *header, + const unsigned char *data, long len) + { + int ret; + WOLFSSL_BIO* bio; + + if (name == NULL || header == NULL || data == NULL) + return 0; + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); + if (bio == NULL) + return 0; + + if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) { + wolfSSL_BIO_free(bio); + bio = NULL; + } + + ret = wolfSSL_PEM_write_bio(bio, name, header, data, len); + + if (bio != NULL) + wolfSSL_BIO_free(bio); + + return ret; + } +#endif + + int wolfSSL_PEM_get_EVP_CIPHER_INFO(char* header, EncryptedInfo* cipher) + { + if (header == NULL || cipher == NULL) + return WOLFSSL_FAILURE; + + XMEMSET(cipher, 0, sizeof(*cipher)); + + if (wc_EncryptedInfoParse(cipher, &header, XSTRLEN(header)) != 0) + return WOLFSSL_FAILURE; + + return WOLFSSL_SUCCESS; + } + + int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data, + long* len, pem_password_cb* callback, void* ctx) + { + int ret = WOLFSSL_SUCCESS; + char password[NAME_SZ]; + int passwordSz; + + if (cipher == NULL || data == NULL || len == NULL || callback == NULL) + return WOLFSSL_FAILURE; + + passwordSz = callback(password, sizeof(password), PEM_PASS_READ, ctx); + if (passwordSz < 0) + ret = WOLFSSL_FAILURE; + + if (ret == WOLFSSL_SUCCESS) { + if (wc_BufferKeyDecrypt(cipher, data, (word32)*len, (byte*)password, + passwordSz, WC_MD5) != 0) { + ret = WOLFSSL_FAILURE; + } + } + + if (passwordSz > 0) + XMEMSET(password, 0, passwordSz); + + return ret; + } + + /* + * bp : bio to read X509 from + * x : x509 to write to + * cb : password call back for reading PEM + * u : password + * _AUX is for working with a trusted X509 certificate + */ + WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_AUX(WOLFSSL_BIO *bp, + WOLFSSL_X509 **x, pem_password_cb *cb, void *u) { + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509"); + + /* AUX info is; trusted/rejected uses, friendly name, private key id, + * and potentially a stack of "other" info. wolfSSL does not store + * friendly name or private key id yet in WOLFSSL_X509 for human + * readability and does not support extra trusted/rejected uses for + * root CA. */ + return wolfSSL_PEM_read_bio_X509(bp, x, cb, u); + } + + +#ifdef OPENSSL_ALL + /* create and return a new WOLFSSL_X509_PKEY structure or NULL on failure */ + static WOLFSSL_X509_PKEY* wolfSSL_X509_PKEY_new(void* heap) + { + WOLFSSL_X509_PKEY* ret; + + ret = (WOLFSSL_X509_PKEY*)XMALLOC(sizeof(WOLFSSL_X509_PKEY), heap, + DYNAMIC_TYPE_KEY); + if (ret != NULL) { + XMEMSET(ret, 0, sizeof(WOLFSSL_X509_PKEY)); + ret->heap = heap; + } + return ret; + } + + + /* sets the values of X509_PKEY based on certificate passed in + * return WOLFSSL_SUCCESS on success */ + static int wolfSSL_X509_PKEY_set(WOLFSSL_X509_PKEY* xPkey, + WOLFSSL_X509* x509) + { + if (xPkey == NULL || x509 == NULL) { + return BAD_FUNC_ARG; + } + wolfSSL_EVP_PKEY_free(xPkey->dec_pkey); + xPkey->dec_pkey = wolfSSL_X509_get_pubkey(x509); + if (xPkey->dec_pkey == NULL) { + return WOLFSSL_FAILURE; + } + return WOLFSSL_SUCCESS; + } + + + /* free up all memory used by "xPkey" passed in */ + static void wolfSSL_X509_PKEY_free(WOLFSSL_X509_PKEY* xPkey) + { + if (xPkey != NULL) { + wolfSSL_EVP_PKEY_free(xPkey->dec_pkey); + } + XFREE(xPkey, xPkey->heap, DYNAMIC_TYPE_KEY); + } + + + /* Takes control of x509 on success + * helper function to break out code needed to set WOLFSSL_X509_INFO up + * free's "info" passed in if is not defaults + * + * returns WOLFSSL_SUCCESS on success + */ + static int wolfSSL_X509_INFO_set(WOLFSSL_X509_INFO* info, + WOLFSSL_X509* x509) + { + if (info == NULL || x509 == NULL) { + return BAD_FUNC_ARG; + } + + /* check is fresh "info" passed in, if not free it */ + if (info->x509 != NULL || info->x_pkey != NULL) { + WOLFSSL_X509_INFO* tmp; + + tmp = wolfSSL_X509_INFO_new(); + if (tmp == NULL) { + WOLFSSL_MSG("Unable to create new structure"); + return MEMORY_E; + } + wolfSSL_X509_INFO_free(info); + info = tmp; + } + + info->x509 = x509; + + //@TODO info->num + //@TODO info->enc_cipher + //@TODO info->enc_len + //@TODO info->enc_data + //@TODO info->crl + + info->x_pkey = wolfSSL_X509_PKEY_new(x509->heap); + return wolfSSL_X509_PKEY_set(info->x_pkey, x509); + } + + + /* + * bio WOLFSSL_BIO to read certificates from + * sk possible stack to push more X509_INFO structs to. Can be NULL + * cb callback password for encrypted PEM certificates + * u user input such as password + * + * returns stack on success and NULL or default stack passed in on fail + */ + WOLF_STACK_OF(WOLFSSL_X509_INFO)* wolfSSL_PEM_X509_INFO_read_bio( + WOLFSSL_BIO* bio, WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk, + pem_password_cb* cb, void* u) + { + WOLF_STACK_OF(WOLFSSL_X509_INFO)* localSk; + WOLFSSL_X509* x509 = NULL; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_PEM_X509_INFO_read_bio"); + + /* attempt to used passed in stack or create a new one */ + if (sk != NULL) { + localSk = sk; + } + else { + localSk = wolfSSL_sk_X509_INFO_new_null(); + } + if (localSk == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", MEMORY_E); + return NULL; + } + + /* parse through BIO and push new info's found onto stack */ + do { + x509 = wolfSSL_PEM_read_bio_X509(bio, NULL, cb, u); + if (x509 != NULL) { + WOLFSSL_X509_INFO* current; + + current = wolfSSL_X509_INFO_new(); + if (current == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", MEMORY_E); + return NULL; + } + ret = wolfSSL_X509_INFO_set(current, x509); + if (ret != WOLFSSL_SUCCESS) { + wolfSSL_X509_free(x509); + } + else { + wolfSSL_sk_X509_INFO_push(localSk, current); + } + } + } while (x509 != NULL && ret == WOLFSSL_SUCCESS); + WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", ret); + return localSk; + } +#endif /* OPENSSL_ALL */ + + void wolfSSL_X509_NAME_ENTRY_free(WOLFSSL_X509_NAME_ENTRY* ne) + { + WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_free"); + if (ne != NULL) { + if (ne->value != NULL && ne->value != &(ne->data)) { + wolfSSL_ASN1_STRING_free(ne->value); + } + XFREE(ne, NULL, DYNAMIC_TYPE_NAME_ENTRY); + } + } + + + WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_new(void) + { + WOLFSSL_X509_NAME_ENTRY* ne; + + ne = (WOLFSSL_X509_NAME_ENTRY*)XMALLOC(sizeof(WOLFSSL_X509_NAME_ENTRY), + NULL, DYNAMIC_TYPE_NAME_ENTRY); + if (ne != NULL) { + XMEMSET(ne, 0, sizeof(WOLFSSL_X509_NAME_ENTRY)); + ne->value = &(ne->data); + } + + return ne; + } + + + /* Create a new WOLFSSL_X509_NAME_ENTRY structure based on the text passed + * in. Returns NULL on failure */ + WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_create_by_txt( + WOLFSSL_X509_NAME_ENTRY **neIn, const char *txt, int type, + const unsigned char *data, int dataSz) + { + int nid = -1; + WOLFSSL_X509_NAME_ENTRY* ne = NULL; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_create_by_txt()"); + + if (txt == NULL) { + return NULL; + } + + if (neIn != NULL) { + ne = *neIn; + } + + nid = wolfSSL_OBJ_txt2nid(txt); + if (nid == NID_undef) { + WOLFSSL_MSG("Unable to find text"); + ne = NULL; + } + else { + if (ne == NULL) { + ne = wolfSSL_X509_NAME_ENTRY_new(); + if (ne == NULL) { + return NULL; + } + } + ne->nid = nid; + ne->value = wolfSSL_ASN1_STRING_type_new(type); + if (ne->value != NULL) { + wolfSSL_ASN1_STRING_set(ne->value, (const void*)data, dataSz); + ne->set = 1; + } + } + + return ne; + } + + + WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_create_by_NID( + WOLFSSL_X509_NAME_ENTRY** out, int nid, int type, + const unsigned char* data, int dataSz) + { + WOLFSSL_X509_NAME_ENTRY* ne; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_create_by_NID()"); + + ne = wolfSSL_X509_NAME_ENTRY_new(); + if (ne == NULL) { + return NULL; + } + + ne->nid = nid; + ne->value = wolfSSL_ASN1_STRING_type_new(type); + wolfSSL_ASN1_STRING_set(ne->value, (const void*)data, dataSz); + ne->set = 1; + + if (out != NULL) { + *out = ne; + } + + return ne; + } + + static int RebuildFullNameAdd(DecodedName* dName, char* data) + { + int totalLen = 0; + int i; + char* fullName; + int idx; + + if (dName->cnLen != 0) + totalLen += dName->cnLen + 4; + if (dName->snLen != 0) + totalLen += dName->snLen + 4; + if (dName->cLen != 0) + totalLen += dName->cLen + 3; + if (dName->lLen != 0) + totalLen += dName->lLen + 3; + if (dName->stLen != 0) + totalLen += dName->stLen + 4; + if (dName->oLen != 0) + totalLen += dName->oLen + 3; + if (dName->ouLen != 0) + totalLen += dName->ouLen + 4; + if (dName->emailLen != 0) + totalLen += dName->emailLen + 14; + if (dName->uidLen != 0) + totalLen += dName->uidLen + 5; + if (dName->serialLen != 0) + totalLen += dName->serialLen + 14; + if (dName->dcNum != 0) { + for (i = 0; i < dName->dcNum; i++) + totalLen += dName->dcLen[i] + 4; + } + + fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509); + if (fullName == NULL) + return MEMORY_E; + + idx = 0; + dName->entryCount = 0; + if (dName->cnLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_COMMON_NAME, 4); + idx += 4; + if (dName->cnIdx == -1) + XMEMCPY(fullName + idx, data, dName->cnLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->cnIdx, + dName->cnLen); + } + dName->cnIdx = idx; + idx += dName->cnLen; + } + if (dName->snLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_SUR_NAME, 4); + idx += 4; + if (dName->snIdx == -1) + XMEMCPY(fullName + idx, data, dName->snLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->snIdx, + dName->snLen); + } + dName->snIdx = idx; + idx += dName->snLen; + } + if (dName->cLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_COUNTRY_NAME, 3); + idx += 3; + if (dName->cIdx == -1) + XMEMCPY(fullName + idx, data, dName->cLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->cIdx, + dName->cLen); + } + dName->cIdx = idx; + idx += dName->cLen; + } + if (dName->lLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_LOCALITY_NAME, 3); + idx += 3; + if (dName->lIdx == -1) + XMEMCPY(fullName + idx, data, dName->lLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->lIdx, + dName->lLen); + } + dName->lIdx = idx; + idx += dName->lLen; + } + if (dName->stLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_STATE_NAME, 4); + idx += 4; + if (dName->stIdx == -1) + XMEMCPY(fullName + idx, data, dName->stLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->stIdx, + dName->stLen); + } + dName->stIdx = idx; + idx += dName->stLen; + } + if (dName->oLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_ORG_NAME, 3); + idx += 3; + if (dName->oIdx == -1) + XMEMCPY(fullName + idx, data, dName->oLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->oIdx, + dName->oLen); + } + dName->oIdx = idx; + idx += dName->oLen; + } + if (dName->ouLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_ORGUNIT_NAME, 4); + idx += 4; + if (dName->ouIdx == -1) + XMEMCPY(fullName + idx, data, dName->ouLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->ouIdx, + dName->ouLen); + } + dName->ouIdx = idx; + idx += dName->ouLen; + } + if (dName->emailLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, "/emailAddress=", 14); + idx += 14; + if (dName->emailIdx == -1) + XMEMCPY(fullName + idx, data, dName->emailLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->emailIdx, + dName->emailLen); + } + dName->emailIdx = idx; + idx += dName->emailLen; + } + if (dName->dcNum != 0) { + for (i = 0; i < dName->dcNum; i++) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_DOMAIN_COMPONENT, 4); + idx += 4; + XMEMCPY(fullName + idx, dName->fullName + dName->dcIdx[i], + dName->dcLen[i]); + dName->dcIdx[i] = idx; + idx += dName->dcLen[i]; + } + } + if (dName->uidLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, "/UID=", 5); + idx += 5; + if (dName->uidIdx == -1) + XMEMCPY(fullName + idx, data, dName->uidLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->uidIdx, + dName->uidLen); + } + dName->uidIdx = idx; + idx += dName->uidLen; + } + if (dName->serialLen != 0) { + dName->entryCount++; + XMEMCPY(fullName + idx, WOLFSSL_SERIAL_NUMBER, 14); + idx += 14; + if (dName->serialIdx == -1) + XMEMCPY(fullName + idx, data, dName->serialLen); + else { + XMEMCPY(fullName + idx, dName->fullName + dName->serialIdx, + dName->serialLen); + } + dName->serialIdx = idx; + idx += dName->serialLen; + } + + if (dName->fullName != NULL) + XFREE(dName->fullName, NULL, DYNAMIC_TYPE_X509); + dName->fullName = fullName; + dName->fullNameLen = idx + 1; + + return 0; + } + + /* Copies entry into name. With it being copied freeing entry becomes the + * callers responsibility. + * returns 1 for success and 0 for error */ + int wolfSSL_X509_NAME_add_entry(WOLFSSL_X509_NAME* name, + WOLFSSL_X509_NAME_ENTRY* entry, int idx, int set) + { + int i; + int fullName = 1; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_add_entry()"); + + switch (entry->nid) { + case ASN_COMMON_NAME: + name->fullName.cnIdx = -1; + name->fullName.cnLen = entry->value->length; + name->fullName.cnNid = entry->nid; + break; + case ASN_SUR_NAME: + name->fullName.snIdx = -1; + name->fullName.snLen = entry->value->length; + name->fullName.snNid = entry->nid; + break; + case ASN_SERIAL_NUMBER: + name->fullName.serialIdx = -1; + name->fullName.serialLen = entry->value->length; + name->fullName.serialNid = entry->nid; + break; + case ASN_COUNTRY_NAME: + name->fullName.cIdx = -1; + name->fullName.cLen = entry->value->length; + name->fullName.cNid = entry->nid; + break; + case ASN_LOCALITY_NAME: + name->fullName.lIdx = -1; + name->fullName.lLen = entry->value->length; + name->fullName.lNid = entry->nid; + break; + case ASN_STATE_NAME: + name->fullName.stIdx = -1; + name->fullName.stLen = entry->value->length; + name->fullName.stNid = entry->nid; + break; + case ASN_ORG_NAME: + name->fullName.oIdx = -1; + name->fullName.oLen = entry->value->length; + name->fullName.oNid = entry->nid; + break; + case ASN_ORGUNIT_NAME: + name->fullName.ouIdx = -1; + name->fullName.ouLen = entry->value->length; + name->fullName.ouNid = entry->nid; + break; + case NID_emailAddress: + name->fullName.emailIdx = -1; + name->fullName.emailLen = entry->value->length; + name->fullName.emailNid = entry->nid; + break; + case ASN_USER_ID: + name->fullName.uidIdx = -1; + name->fullName.uidLen = entry->value->length; + name->fullName.uidNid = entry->nid; + break; + case ASN_DOMAIN_COMPONENT: + name->fullName.dcIdx[0] = -1; + name->fullName.dcLen[0] = entry->value->length; + break; + default: + fullName = 0; + break; + } + + if (fullName) { + int nid = entry->nid; + + if (nid == NID_emailAddress) { + nid = (int)ASN_EMAIL_NAME; + } + + if (idx >= DN_NAMES_MAX + DOMAIN_COMPONENT_MAX) { + return WOLFSSL_FAILURE; + } + + if (idx >= 0) { + name->fullName.loc[idx] = nid; + if (idx == name->fullName.locSz) { + name->fullName.locSz += 1; + } + } + + /* place at end */ + if (idx < 0 && name->fullName.locSz + 1 + < DN_NAMES_MAX + DOMAIN_COMPONENT_MAX) { + name->fullName.loc[name->fullName.locSz] = nid; + name->fullName.locSz += 1; + } + + if (RebuildFullNameAdd(&name->fullName, entry->value->data) != 0) + return WOLFSSL_FAILURE; + } + else { + for (i = 0; i < MAX_NAME_ENTRIES; i++) { + if (name->extra[i].set != 1) { /* not set so overwritten */ + WOLFSSL_X509_NAME_ENTRY* current = &(name->extra[i]); + WOLFSSL_ASN1_STRING* str; + + WOLFSSL_MSG("Found place for name entry"); + + XMEMCPY(current, entry, sizeof(WOLFSSL_X509_NAME_ENTRY)); + str = entry->value; + XMEMCPY(&(current->data), str, sizeof(WOLFSSL_ASN1_STRING)); + current->value = &(current->data); + current->data.data = (char*)XMALLOC(str->length, + name->x509->heap, DYNAMIC_TYPE_OPENSSL); + + if (current->data.data == NULL) { + return SSL_FAILURE; + } + XMEMCPY(current->data.data, str->data, str->length); + + /* make sure is null terminated */ + current->data.data[str->length - 1] = '\0'; + + current->set = 1; /* make sure now listed as set */ + break; + } + } + + if (i == MAX_NAME_ENTRIES) { + WOLFSSL_MSG("No spot found for name entry"); + return SSL_FAILURE; + } + } + + (void)idx; + (void)set; + return SSL_SUCCESS; + } + + int wolfSSL_X509_NAME_add_entry_by_txt(WOLFSSL_X509_NAME *name, + const char *field, int type, + const unsigned char *bytes, int len, + int loc, int set) + { + int ret = WOLFSSL_FAILURE; + int nid; + WOLFSSL_X509_NAME_ENTRY* entry; + + (void)type; + WOLFSSL_ENTER("wolfSSL_X509_NAME_add_entry_by_txt"); + + if (name == NULL || field == NULL) + return WOLFSSL_FAILURE; + + if ((nid = wolfSSL_OBJ_txt2nid(field)) == NID_undef) + return WOLFSSL_FAILURE; + + entry = wolfSSL_X509_NAME_ENTRY_create_by_NID(NULL, + nid, type, (unsigned char*)bytes, len); + if (entry == NULL) + return WOLFSSL_FAILURE; + + ret = wolfSSL_X509_NAME_add_entry(name, entry, loc, set); + wolfSSL_X509_NAME_ENTRY_free(entry); + + return ret; + } + + int wolfSSL_X509_NAME_add_entry_by_NID(WOLFSSL_X509_NAME *name, int nid, + int type, const unsigned char *bytes, + int len, int loc, int set) + { + int ret; + WOLFSSL_X509_NAME_ENTRY* entry; + entry = wolfSSL_X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); + if (entry == NULL) + return WOLFSSL_FAILURE; + ret = wolfSSL_X509_NAME_add_entry(name, entry, loc, set); + wolfSSL_X509_NAME_ENTRY_free(entry); + return ret; + } + #endif /* !NO_CERTS */ + + + /* NID variables are dependent on compatibility header files currently + * + * returns a pointer to a new WOLFSSL_ASN1_OBJECT struct on success and NULL + * on fail + */ + + WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj(int id) + { + return wolfSSL_OBJ_nid2obj_ex(id, NULL); + } + + + WOLFSSL_LOCAL WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj_ex(int id, + WOLFSSL_ASN1_OBJECT* arg_obj) + { + word32 oidSz = 0; + const byte* oid; + word32 type = 0; + WOLFSSL_ASN1_OBJECT* obj = arg_obj; + byte objBuf[MAX_OID_SZ + MAX_LENGTH_SZ + 1]; /* +1 for object tag */ + word32 objSz = 0; + const char* sName = NULL; + int i; + + WOLFSSL_ENTER("wolfSSL_OBJ_nid2obj()"); + + for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) { + if (wolfssl_object_info[i].nid == id) { + id = wolfssl_object_info[i].id; + sName = wolfssl_object_info[i].sName; + type = wolfssl_object_info[i].type; + break; + } + } + if (i == (int)WOLFSSL_OBJECT_INFO_SZ) { + WOLFSSL_MSG("NID not in table"); + #ifdef WOLFSSL_QT + sName = NULL; + type = id; + #else + return NULL; + #endif + } + + #ifdef HAVE_ECC + if (type == 0 && wc_ecc_get_oid(id, &oid, &oidSz) > 0) { + type = oidCurveType; + } + #endif /* HAVE_ECC */ + + if (sName != NULL) { + if (XSTRLEN(sName) > WOLFSSL_MAX_SNAME - 1) { + WOLFSSL_MSG("Attempted short name is too large"); + return NULL; + } + } + + oid = OidFromId(id, type, &oidSz); + + /* set object ID to buffer */ + if (obj == NULL){ + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + } else { + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC; + } + obj->type = id; + obj->grp = type; + + obj->sName[0] = '\0'; + if (sName != NULL) { + XMEMCPY(obj->sName, (char*)sName, XSTRLEN((char*)sName)); + } + + objBuf[0] = ASN_OBJECT_ID; objSz++; + objSz += SetLength(oidSz, objBuf + 1); + XMEMCPY(objBuf + objSz, oid, oidSz); + objSz += oidSz; + obj->objSz = objSz; + if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) || + (obj->obj == NULL)) { + obj->obj = (byte*)XREALLOC((byte*)obj->obj, obj->objSz, NULL, + DYNAMIC_TYPE_ASN1); + if (obj->obj == NULL) { + wolfSSL_ASN1_OBJECT_free(obj); + return NULL; + } + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ; + } else { + obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ; + } + XMEMCPY((byte*)obj->obj, objBuf, obj->objSz); + + (void)type; + + return obj; + } + + static const char* oid_translate_num_to_str(const char* oid) + { + const struct oid_dict { + const char* num; + const char* desc; + } oid_dict[] = { + { "2.5.29.37.0", "Any Extended Key Usage" }, + { "1.3.6.1.5.5.7.3.1", "TLS Web Server Authentication" }, + { "1.3.6.1.5.5.7.3.2", "TLS Web Client Authentication" }, + { "1.3.6.1.5.5.7.3.3", "Code Signing" }, + { "1.3.6.1.5.5.7.3.4", "E-mail Protection" }, + { "1.3.6.1.5.5.7.3.8", "Time Stamping" }, + { "1.3.6.1.5.5.7.3.9", "OCSP Signing" }, + { NULL, NULL } + }; + const struct oid_dict* idx; + + for (idx = oid_dict; idx->num != NULL; idx++) { + if (!XSTRNCMP(oid, idx->num, XSTRLEN(idx->num))) { + return idx->desc; + } + } + return NULL; + } + + /* if no_name is one than use numerical form otherwise can be short name. + * + * returns the buffer size on success + */ + int wolfSSL_OBJ_obj2txt(char *buf, int bufLen, WOLFSSL_ASN1_OBJECT *a, int no_name) + { + int bufSz; + const char* desc; + + WOLFSSL_ENTER("wolfSSL_OBJ_obj2txt()"); + + if (buf == NULL || bufLen <= 1 || a == NULL) { + WOLFSSL_MSG("Bad input argument"); + return WOLFSSL_FAILURE; + } + + if (no_name == 1) { + int length; + word32 idx = 0; + byte tag; + + if (GetASNTag(a->obj, &idx, &tag, a->objSz) != 0) { + return WOLFSSL_FAILURE; + } + + if (tag != ASN_OBJECT_ID) { + WOLFSSL_MSG("Bad ASN1 Object"); + return WOLFSSL_FAILURE; + } + + if (GetLength((const byte*)a->obj, &idx, &length, + a->objSz) < 0 || length < 0) { + return ASN_PARSE_E; + } + + if (bufLen < MAX_OID_STRING_SZ) { + bufSz = bufLen - 1; + } + else { + bufSz = MAX_OID_STRING_SZ; + } + + if ((bufSz = DecodePolicyOID(buf, (word32)bufSz, a->obj + idx, + (word32)length)) <= 0) { + WOLFSSL_MSG("Error decoding OID"); + return WOLFSSL_FAILURE; + } + + } + else { /* return short name */ + if (XSTRLEN(a->sName) + 1 < (word32)bufLen - 1) { + bufSz = (int)XSTRLEN(a->sName); + } + else { + bufSz = bufLen - 1; + } + if (bufSz) { + XMEMCPY(buf, a->sName, bufSz); + } + else if (wolfSSL_OBJ_obj2txt(buf, bufLen, a, 1)) { + if ((desc = oid_translate_num_to_str(buf))) { + bufSz = (int)XSTRLEN(desc); + XMEMCPY(buf, desc, min(bufSz, bufLen)); + } + } + else if (a->type == GEN_DNS || a->type == GEN_EMAIL || a->type == GEN_URI) { + bufSz = (int)XSTRLEN((const char*)a->obj); + XMEMCPY(buf, a->obj, min(bufSz, bufLen)); + } + } + + buf[bufSz] = '\0'; + #ifdef WOLFSSL_QT + /* For unknown extension types, QT expects the short name to be the + text representation of the oid */ + if (XSTRLEN(a->sName) == 0) { + XMEMCPY(a->sName, buf, bufSz); + } + #endif + return bufSz; + } +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) && !defined(NO_ASN) + /* DN_Tags to strings */ + static const struct DN_Tag_Strings { + enum DN_Tags tag; + const char* str; + } dn_tag_strings[] = { + { ASN_COMMON_NAME, "CN" }, + { ASN_SUR_NAME, "SN" }, + { ASN_SERIAL_NUMBER, "serialNumber" }, + { ASN_COUNTRY_NAME, "C" }, + { ASN_LOCALITY_NAME, "L" }, + { ASN_STATE_NAME, "ST" }, + { ASN_ORG_NAME, "O"}, + { ASN_ORGUNIT_NAME, "OU"}, + { ASN_BUS_CAT, "businessCategory"}, + { ASN_EMAIL_NAME, "emailAddress"}, + { ASN_USER_ID, "UID"}, + { ASN_DOMAIN_COMPONENT, "DC"}, + { ASN_DN_NULL, NULL } + }; + + int wolfSSL_X509_NAME_get_index_by_OBJ(WOLFSSL_X509_NAME *name, + const WOLFSSL_ASN1_OBJECT *obj, + int idx) { + const struct DN_Tag_Strings* dn; + enum DN_Tags tag = ASN_DN_NULL; + + if (!name || idx >= name->fullName.locSz || + !obj || !obj->obj) { + return -1; + } + + if (idx < 0) { + idx = 0; + } + for (dn = dn_tag_strings; dn->str != NULL; dn++) { + /* Find the DN_Tags number for the name */ + if (XSTRNCMP((const char*) obj->sName, dn->str, obj->objSz - 1) == 0) { + tag = dn->tag; + break; + } + } + if (!tag) { + /* Unable to identify desired name */ + return -1; + } + for (idx++; idx < name->fullName.locSz; idx++) { + /* Find index of desired name */ + if ((enum DN_Tags)name->fullName.loc[idx] == tag) { + return idx; + } + } + return -1; + } +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) + +#ifndef NO_SHA + /* One shot SHA1 hash of message. + * + * d message to hash + * n size of d buffer + * md buffer to hold digest. Should be SHA_DIGEST_SIZE. + * + * Note: if md is null then a static buffer of SHA_DIGEST_SIZE is used. + * When the static buffer is used this function is not thread safe. + * + * Returns a pointer to the message digest on success and NULL on failure. + */ + unsigned char *wolfSSL_SHA1(const unsigned char *d, size_t n, + unsigned char *md) + { + static byte dig[WC_SHA_DIGEST_SIZE]; + wc_Sha sha; + + WOLFSSL_ENTER("wolfSSL_SHA1"); + + if (wc_InitSha_ex(&sha, NULL, 0) != 0) { + WOLFSSL_MSG("SHA1 Init failed"); + return NULL; + } + + if (wc_ShaUpdate(&sha, (const byte*)d, (word32)n) != 0) { + WOLFSSL_MSG("SHA1 Update failed"); + return NULL; + } + + if (wc_ShaFinal(&sha, dig) != 0) { + WOLFSSL_MSG("SHA1 Final failed"); + return NULL; + } + + wc_ShaFree(&sha); + + if (md != NULL) { + XMEMCPY(md, dig, WC_SHA_DIGEST_SIZE); + return md; + } + else { + return (unsigned char*)dig; + } + } +#endif /* ! NO_SHA */ + +#ifndef NO_SHA256 + /* One shot SHA256 hash of message. + * + * d message to hash + * n size of d buffer + * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE. + * + * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. + * When the static buffer is used this function is not thread safe. + * + * Returns a pointer to the message digest on success and NULL on failure. + */ + unsigned char *wolfSSL_SHA256(const unsigned char *d, size_t n, + unsigned char *md) + { + static byte dig[WC_SHA256_DIGEST_SIZE]; + wc_Sha256 sha; + + WOLFSSL_ENTER("wolfSSL_SHA256"); + + if (wc_InitSha256_ex(&sha, NULL, 0) != 0) { + WOLFSSL_MSG("SHA256 Init failed"); + return NULL; + } + + if (wc_Sha256Update(&sha, (const byte*)d, (word32)n) != 0) { + WOLFSSL_MSG("SHA256 Update failed"); + return NULL; + } + + if (wc_Sha256Final(&sha, dig) != 0) { + WOLFSSL_MSG("SHA256 Final failed"); + return NULL; + } + + wc_Sha256Free(&sha); + + if (md != NULL) { + XMEMCPY(md, dig, WC_SHA256_DIGEST_SIZE); + return md; + } + else { + return (unsigned char*)dig; + } + } +#endif /* ! NO_SHA256 */ + +#ifdef WOLFSSL_SHA384 + /* One shot SHA384 hash of message. + * + * d message to hash + * n size of d buffer + * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE. + * + * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. + * When the static buffer is used this function is not thread safe. + * + * Returns a pointer to the message digest on success and NULL on failure. + */ + unsigned char *wolfSSL_SHA384(const unsigned char *d, size_t n, + unsigned char *md) + { + static byte dig[WC_SHA384_DIGEST_SIZE]; + wc_Sha384 sha; + + WOLFSSL_ENTER("wolfSSL_SHA384"); + + if (wc_InitSha384_ex(&sha, NULL, 0) != 0) { + WOLFSSL_MSG("SHA384 Init failed"); + return NULL; + } + + if (wc_Sha384Update(&sha, (const byte*)d, (word32)n) != 0) { + WOLFSSL_MSG("SHA384 Update failed"); + return NULL; + } + + if (wc_Sha384Final(&sha, dig) != 0) { + WOLFSSL_MSG("SHA384 Final failed"); + return NULL; + } + + wc_Sha384Free(&sha); + + if (md != NULL) { + XMEMCPY(md, dig, WC_SHA384_DIGEST_SIZE); + return md; + } + else { + return (unsigned char*)dig; + } + } +#endif /* WOLFSSL_SHA384 */ + + +#if defined(WOLFSSL_SHA512) + /* One shot SHA512 hash of message. + * + * d message to hash + * n size of d buffer + * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE. + * + * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. + * When the static buffer is used this function is not thread safe. + * + * Returns a pointer to the message digest on success and NULL on failure. + */ + unsigned char *wolfSSL_SHA512(const unsigned char *d, size_t n, + unsigned char *md) + { + static byte dig[WC_SHA512_DIGEST_SIZE]; + wc_Sha512 sha; + + WOLFSSL_ENTER("wolfSSL_SHA512"); + + if (wc_InitSha512_ex(&sha, NULL, 0) != 0) { + WOLFSSL_MSG("SHA512 Init failed"); + return NULL; + } + + if (wc_Sha512Update(&sha, (const byte*)d, (word32)n) != 0) { + WOLFSSL_MSG("SHA512 Update failed"); + return NULL; + } + + if (wc_Sha512Final(&sha, dig) != 0) { + WOLFSSL_MSG("SHA512 Final failed"); + return NULL; + } + + wc_Sha512Free(&sha); + + if (md != NULL) { + XMEMCPY(md, dig, WC_SHA512_DIGEST_SIZE); + return md; + } + else { + return (unsigned char*)dig; + } + } +#endif /* defined(WOLFSSL_SHA512) */ +#endif /* OPENSSL_EXTRA */ + +#ifndef WOLFCRYPT_ONLY +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) + + char wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x) + { + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate"); + + FreeDer(&ctx->certificate); /* Make sure previous is free'd */ + ret = AllocDer(&ctx->certificate, x->derCert->length, CERT_TYPE, + ctx->heap); + if (ret != 0) + return 0; + + XMEMCPY(ctx->certificate->buffer, x->derCert->buffer, + x->derCert->length); +#ifdef KEEP_OUR_CERT + if (ctx->ourCert != NULL && ctx->ownOurCert) { + FreeX509(ctx->ourCert); + XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509); + } + #ifndef WOLFSSL_X509_STORE_CERTS + ctx->ourCert = x; + #else + ctx->ourCert = wolfSSL_X509_d2i(NULL, x->derCert->buffer,x->derCert->length); + if(ctx->ourCert == NULL){ + return 0; + } + #endif + + ctx->ownOurCert = 0; +#endif + + /* Update the available options with public keys. */ + switch (x->pubKeyOID) { + case RSAk: + ctx->haveRSA = 1; + break; + #ifdef HAVE_ED25519 + case ED25519k: + #endif + #ifdef HAVE_ED448 + case ED448k: + #endif + case ECDSAk: + ctx->haveECC = 1; + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + ctx->pkCurveOID = x->pkCurveOID; + #endif + break; + } + + return WOLFSSL_SUCCESS; + } + + int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) + { + int ret; + if (ctx == NULL || x509 == NULL || x509->derCert == NULL) { + return WOLFSSL_FAILURE; + } + + ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer, + x509->derCert->length, WOLFSSL_FILETYPE_ASN1); + + return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + } + + int wolfSSL_BIO_read_filename(WOLFSSL_BIO *b, const char *name) { + #ifndef NO_FILESYSTEM + XFILE fp; + + WOLFSSL_ENTER("wolfSSL_BIO_new_file"); + + if ((wolfSSL_BIO_get_fp(b, &fp) == WOLFSSL_SUCCESS) && (fp != XBADFILE)) + { + XFCLOSE(fp); + } + + fp = XFOPEN(name, "r"); + if (fp == XBADFILE) + return WOLFSSL_BAD_FILE; + + if (wolfSSL_BIO_set_fp(b, fp, BIO_CLOSE) != WOLFSSL_SUCCESS) { + XFCLOSE(fp); + return WOLFSSL_BAD_FILE; + } + + /* file is closed when bio is free'd */ + return WOLFSSL_SUCCESS; + #else + (void)name; + (void)b; + return WOLFSSL_NOT_IMPLEMENTED; + #endif + } + + /* Return the corresponding short name for the nid . + * or NULL if short name can't be found. + */ + const char * wolfSSL_OBJ_nid2sn(int n) { + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t i; + WOLFSSL_ENTER("wolfSSL_OBJ_nid2sn"); + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { + if (obj_info->nid == n) { + return obj_info->sName; + } + } + WOLFSSL_MSG("SN not found"); + return NULL; + } + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + int wolfSSL_OBJ_sn2nid(const char *sn) { + WOLFSSL_ENTER("wolfSSL_OBJ_sn2nid"); + if (sn == NULL) + return NID_undef; + return wc_OBJ_sn2nid(sn); + } +#endif + + + /* Gets the NID value that corresponds with the ASN1 object. + * + * o ASN1 object to get NID of + * + * Return NID on success and a negative value on failure + */ + int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o) + { + word32 oid = 0; + word32 idx = 0; + + WOLFSSL_ENTER("wolfSSL_OBJ_obj2nid"); + + if (o == NULL) { + return -1; + } + + #ifdef WOLFSSL_QT + if (o->grp == oidCertExtType) { + /* If nid is an unknown extension, return NID_undef */ + if (wolfSSL_OBJ_nid2sn(o->nid) == NULL) + return NID_undef; + } + #endif + + if (o->nid > 0) + return o->nid; + if (GetObjectId(o->obj, &idx, &oid, o->grp, o->objSz) < 0) { + WOLFSSL_MSG("Issue getting OID of object"); + return -1; + } + + return oid2nid(oid, o->grp); + } + + /* Returns the long name that corresponds with an ASN1_OBJECT nid value. + * n : NID value of ASN1_OBJECT to search */ + const char* wolfSSL_OBJ_nid2ln(int n) + { + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t i; + WOLFSSL_ENTER("wolfSSL_OBJ_nid2ln"); + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { + if (obj_info->nid == n) { + return obj_info->lName; + } + } + WOLFSSL_MSG("NID not found in table"); + return NULL; + } + + /* Return the corresponding NID for the long name + * or NID_undef if NID can't be found. + */ + int wolfSSL_OBJ_ln2nid(const char *ln) + { + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t i, lnlen; + WOLFSSL_ENTER("wolfSSL_OBJ_ln2nid"); + if (ln && (lnlen = XSTRLEN(ln)) > 0) { + /* Accept input like "/commonName=" */ + if (ln[0] == '/') { + ln++; + lnlen--; + } + if (lnlen) { + if (ln[lnlen-1] == '=') { + lnlen--; + } + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { + if (lnlen == XSTRLEN(obj_info->lName) && + XSTRNCMP(ln, obj_info->lName, lnlen) == 0) { + return obj_info->nid; + } + } + } + } + return NID_undef; + } + + /* compares two objects, return 0 if equal */ + int wolfSSL_OBJ_cmp(const WOLFSSL_ASN1_OBJECT* a, + const WOLFSSL_ASN1_OBJECT* b) + { + WOLFSSL_ENTER("wolfSSL_OBJ_cmp"); + + if (a != NULL && b != NULL && + a->obj != NULL && b->obj != NULL && + a->objSz == b->objSz) { + return XMEMCMP(a->obj, b->obj, a->objSz); + } + + return WOLFSSL_FATAL_ERROR; + } + + /* Gets the NID value that is related to the OID string passed in. Example + * string would be "2.5.29.14" for subject key ID. + * + * returns NID value on success and NID_undef on error + */ + int wolfSSL_OBJ_txt2nid(const char* s) + { + unsigned int i; + #ifdef WOLFSSL_CERT_EXT + int ret; + unsigned int sum = 0; + unsigned int outSz = MAX_OID_SZ; + unsigned char out[MAX_OID_SZ]; + #endif + + WOLFSSL_ENTER("OBJ_txt2nid"); + + if (s == NULL) { + return NID_undef; + } + + #ifdef WOLFSSL_CERT_EXT + ret = EncodePolicyOID(out, &outSz, s, NULL); + if (ret == 0) { + /* sum OID */ + for (i = 0; i < outSz; i++) { + sum += out[i]; + } + } + #endif /* WOLFSSL_CERT_EXT */ + + /* get the group that the OID's sum is in + * @TODO possible conflict with multiples */ + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { + int len; + #ifdef WOLFSSL_CERT_EXT + if (ret == 0) { + if (wolfssl_object_info[i].id == (int)sum) { + return wolfssl_object_info[i].nid; + } + } + #endif + + /* try as a short name */ + len = (int)XSTRLEN(s); + if (XSTRNCMP(wolfssl_object_info[i].sName, s, len) == 0) { + return wolfssl_object_info[i].nid; + } + + /* try as a long name */ + if (XSTRNCMP(wolfssl_object_info[i].lName, s, len) == 0) { + return wolfssl_object_info[i].nid; + } + } + + return NID_undef; + } + + /* Creates new ASN1_OBJECT from short name, long name, or text + * representation of oid. If no_name is 0, then short name, long name, and + * numerical value of oid are interpreted. If no_name is 1, then only the + * numerical value of the oid is interpreted. + * + * Returns pointer to ASN1_OBJECT on success, or NULL on error. + */ +#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) + WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_txt2obj(const char* s, int no_name) + { + int len, i, ret; + int nid = NID_undef; + unsigned int outSz = MAX_OID_SZ; + unsigned char out[MAX_OID_SZ]; + unsigned int sum = 0; + + WOLFSSL_ENTER("wolfSSL_OBJ_txt2obj"); + + if (s == NULL) + return NULL; + + /* If s is numerical value, try to sum oid */ + ret = EncodePolicyOID(out, &outSz, s, NULL); + if (ret == 0) { + for (i = 0; i < (int)outSz; i++) { + sum += out[i]; + } + } + + len = (int)XSTRLEN(s); + + /* TODO: update short names in wolfssl_object_info and check OID sums + are correct */ + for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) { + /* Short name, long name, and numerical value are interpreted */ + if (no_name == 0 && ((XSTRNCMP(s, wolfssl_object_info[i].sName, len) == 0) || + (XSTRNCMP(s, wolfssl_object_info[i].lName, len) == 0) || + (wolfssl_object_info[i].id == (int)sum))) + nid = wolfssl_object_info[i].nid; + /* Only numerical value is interpreted */ + else if (no_name == 1 && wolfssl_object_info[i].id == (int)sum) + nid = wolfssl_object_info[i].nid; + } + + if (nid != NID_undef) + return wolfSSL_OBJ_nid2obj(nid); + + return NULL; + } +#endif + + /* compatibility function. Its intended use is to remove OID's from an + * internal table that have been added with OBJ_create. wolfSSL manages its + * own internal OID values and does not currently support OBJ_create. */ + void wolfSSL_OBJ_cleanup(void) + { + WOLFSSL_ENTER("wolfSSL_OBJ_cleanup()"); + } + + #ifndef NO_WOLFSSL_STUB + int wolfSSL_OBJ_create(const char *oid, const char *sn, const char *ln) + { + (void)oid; + (void)sn; + (void)ln; + WOLFSSL_STUB("wolfSSL_OBJ_create"); + return WOLFSSL_FAILURE; + } + #endif + + void wolfSSL_set_verify_depth(WOLFSSL *ssl, int depth) + { + #if !defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB) + (void)ssl; + (void)depth; + WOLFSSL_STUB("wolfSSL_set_verify_depth"); + #else + WOLFSSL_ENTER("wolfSSL_set_verify_depth"); + ssl->options.verifyDepth = (byte)depth; + #endif + } + + + WOLFSSL_ASN1_OBJECT * wolfSSL_X509_NAME_ENTRY_get_object(WOLFSSL_X509_NAME_ENTRY *ne) { + WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_object"); + if (ne == NULL) return NULL; + if (wolfSSL_OBJ_nid2obj_ex(ne->nid, &ne->object) != NULL) { + ne->object.nid = ne->nid; + return &ne->object; + } + return NULL; + } + + + /* looks up the DN given the location "loc". "loc" is the number indicating + * the order that the DN was parsed as, 0 is first DN parsed. + * + * returns the setup WOLFSSL_X509_NAME pointer on success and NULL on fail + */ + static WOLFSSL_X509_NAME* wolfSSL_nameByLoc(WOLFSSL_X509_NAME *name, int loc) + { + char* pt = NULL; + int sz = 0; + + switch (name->fullName.loc[loc]) + { + case ASN_COMMON_NAME: + sz = name->fullName.cnLen; + pt = &name->fullName.fullName[name->fullName.cnIdx]; + name->cnEntry.nid = name->fullName.cnNid; + break; + case ASN_COUNTRY_NAME: + sz = name->fullName.cLen; + pt = &name->fullName.fullName[name->fullName.cIdx]; + name->cnEntry.nid = name->fullName.cNid; + break; + case ASN_LOCALITY_NAME: + sz = name->fullName.lLen; + pt = &name->fullName.fullName[name->fullName.lIdx]; + name->cnEntry.nid = name->fullName.lNid; + break; + case ASN_STATE_NAME: + sz = name->fullName.stLen; + pt = &name->fullName.fullName[name->fullName.stIdx]; + name->cnEntry.nid = name->fullName.stNid; + break; + case ASN_ORG_NAME: + sz = name->fullName.oLen; + pt = &name->fullName.fullName[name->fullName.oIdx]; + name->cnEntry.nid = name->fullName.oNid; + break; + case ASN_ORGUNIT_NAME: + sz = name->fullName.ouLen; + pt = &name->fullName.fullName[name->fullName.ouIdx]; + name->cnEntry.nid = name->fullName.ouNid; + break; + case ASN_EMAIL_NAME: + sz = name->fullName.emailLen; + pt = &name->fullName.fullName[name->fullName.emailIdx]; + name->cnEntry.nid = name->fullName.emailNid; + break; + case ASN_SUR_NAME: + sz = name->fullName.snLen; + pt = &name->fullName.fullName[name->fullName.snIdx]; + name->cnEntry.nid = name->fullName.snNid; + break; + case ASN_USER_ID: + sz = name->fullName.uidLen; + pt = &name->fullName.fullName[name->fullName.uidIdx]; + name->cnEntry.nid = name->fullName.uidNid; + break; + case ASN_SERIAL_NUMBER: + sz = name->fullName.serialLen; + pt = &name->fullName.fullName[name->fullName.serialIdx]; + name->cnEntry.nid = name->fullName.serialNid; + break; +#ifdef WOLFSSL_CERT_EXT + case ASN_BUS_CAT: + sz = name->fullName.bcLen; + pt = &name->fullName.fullName[name->fullName.bcIdx]; + break; +#endif + + case ASN_DOMAIN_COMPONENT: + /* get index of DC i.e. first or second or ... case */ + { + int idx = 0, i; + for (i = 0; i < loc; i++) { + if (name->fullName.loc[i] == ASN_DOMAIN_COMPONENT) { + idx++; + } + } + + /* check that index is not larger than max buffer size or larger + * than the number of domain components parsed */ + if (idx >= DOMAIN_COMPONENT_MAX || idx > name->fullName.dcNum) { + WOLFSSL_MSG("Index was larger then domain buffer"); + return NULL; + } + pt = &name->fullName.fullName[name->fullName.dcIdx[idx]], + sz = name->fullName.dcLen[idx]; + name->cnEntry.nid = ASN_DOMAIN_COMPONENT; + name->cnEntry.data.type = CTC_UTF8; + } + break; + + default: + return NULL; + } + + /* -1 to leave room for trailing terminator 0 */ + if (sz == 0 || sz >= CTC_NAME_SIZE - 1) + return NULL; + if (wolfSSL_ASN1_STRING_set(name->cnEntry.value, pt, sz) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error setting local ASN1 string data"); + return NULL; + } + name->cnEntry.value->type = CTC_UTF8; + name->cnEntry.set = 1; + return name; + } + + + WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry( + WOLFSSL_X509_NAME *name, int loc) + { + WOLFSSL_ENTER("wolfSSL_X509_NAME_get_entry"); + + if (name == NULL) { + return NULL; + } + + if (loc < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + if (loc <= DN_NAMES_MAX + name->fullName.dcNum) { + if (wolfSSL_nameByLoc(name, loc) != NULL) + return &name->cnEntry; + } + /* DC component */ + if (name->fullName.dcMode) { + if (name->fullName.fullName != NULL){ + if (loc == name->fullName.dcNum){ + name->cnEntry.data.data + = &name->fullName.fullName[name->fullName.cIdx]; + name->cnEntry.data.length = name->fullName.cLen; + name->cnEntry.nid = ASN_COUNTRY_NAME; + } else { + name->cnEntry.data.data + = &name->fullName.fullName[name->fullName.dcIdx[loc]]; + name->cnEntry.data.length = name->fullName.dcLen[loc]; + name->cnEntry.nid = ASN_DOMAIN_COMPONENT; + } + } + name->cnEntry.data.type = CTC_UTF8; + /* common name index case */ + } else if (loc == name->fullName.cnIdx && name->x509 != NULL) { + /* get CN shortcut from x509 since it has null terminator */ + name->cnEntry.data.data = name->x509->subjectCN; + name->cnEntry.data.length = name->fullName.cnLen; + name->cnEntry.data.type = CTC_UTF8; + name->cnEntry.nid = ASN_COMMON_NAME; + name->cnEntry.set = 1; + } else { + WOLFSSL_MSG("loc passed in is not in range of parsed DN's"); + return NULL; + } + return &name->cnEntry; + } + + #ifndef NO_WOLFSSL_STUB + int wolfSSL_X509_check_private_key(WOLFSSL_X509 *x509, WOLFSSL_EVP_PKEY *key) + { + (void) x509; + (void) key; + WOLFSSL_ENTER("wolfSSL_X509_check_private_key"); + WOLFSSL_STUB("X509_check_private_key"); + + return WOLFSSL_SUCCESS; + } + + WOLF_STACK_OF(WOLFSSL_X509_NAME) *wolfSSL_dup_CA_list( + WOLF_STACK_OF(WOLFSSL_X509_NAME) *sk) + { + (void) sk; + WOLFSSL_ENTER("wolfSSL_dup_CA_list"); + WOLFSSL_STUB("SSL_dup_CA_list"); + + return NULL; + } + + #endif + +#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || + HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ +#endif /* OPENSSL_EXTRA */ + +#ifndef WOLFCRYPT_ONLY + +#ifdef OPENSSL_EXTRA + +/* wolfSSL uses negative values for error states. This function returns an + * unsigned type so the value returned is the absolute value of the error. + */ +unsigned long wolfSSL_ERR_peek_last_error_line(const char **file, int *line) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); + + (void)line; + (void)file; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(DEBUG_WOLFSSL) || \ + defined(WOLFSSL_HAPROXY) + { + int ret; + + if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) { + WOLFSSL_MSG("Issue peeking at error node in queue"); + return 0; + } + #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + if (ret == -ASN_NO_PEM_HEADER) + return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; + #endif + return (unsigned long)ret; + } +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif +} + + +#ifndef NO_CERTS +int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey"); + + if (ctx == NULL || pkey == NULL) { + return WOLFSSL_FAILURE; + } + + if (pkey->pkey.ptr != NULL) { + /* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */ + return wolfSSL_CTX_use_PrivateKey_buffer(ctx, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, SSL_FILETYPE_ASN1); + } + + WOLFSSL_MSG("wolfSSL private key not set"); + return BAD_FUNC_ARG; +} +#endif /* !NO_CERTS */ + + +#if defined(HAVE_EX_DATA) || defined(FORTRESS) +void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX* ctx, int idx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data"); + #ifdef HAVE_EX_DATA + if(ctx != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx); + } + #else + (void)ctx; + (void)idx; + #endif + return NULL; +} + +int wolfSSL_CTX_get_ex_new_index(long idx, void* arg, void* a, void* b, + void* c) +{ + static int ctx_idx = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_get_ex_new_index"); + (void)idx; + (void)arg; + (void)a; + (void)b; + (void)c; + + return ctx_idx++; +} + +/* Return the index that can be used for the WOLFSSL structure to store + * application data. + * + */ +int wolfSSL_get_ex_new_index(long argValue, void* arg, + WOLFSSL_CRYPTO_EX_new* cb1, WOLFSSL_CRYPTO_EX_dup* cb2, + WOLFSSL_CRYPTO_EX_free* cb3) +{ + static int ssl_idx = 0; + + WOLFSSL_ENTER("wolfSSL_get_ex_new_index"); + + (void)argValue; + (void)arg; + (void)cb1; + (void)cb2; + (void)cb3; + + return ssl_idx++; +} + + +int wolfSSL_CTX_set_ex_data(WOLFSSL_CTX* ctx, int idx, void* data) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data"); + #ifdef HAVE_EX_DATA + if (ctx != NULL) + { + return wolfSSL_CRYPTO_set_ex_data(&ctx->ex_data, idx, data); + } + #else + (void)ctx; + (void)idx; + (void)data; + #endif + return WOLFSSL_FAILURE; +} +#endif + + +/* Returns char* to app data stored in ex[0]. + * + * ssl WOLFSSL structure to get app data from + */ +void* wolfSSL_get_app_data(const WOLFSSL *ssl) +{ + /* checkout exdata stuff... */ + WOLFSSL_ENTER("wolfSSL_get_app_data"); + + return wolfSSL_get_ex_data(ssl, 0); +} + + +/* Set ex array 0 to have app data + * + * ssl WOLFSSL struct to set app data in + * arg data to be stored + * + * Returns SSL_SUCCESS on success and SSL_FAILURE on failure + */ +int wolfSSL_set_app_data(WOLFSSL *ssl, void* arg) { + WOLFSSL_ENTER("wolfSSL_set_app_data"); + + return wolfSSL_set_ex_data(ssl, 0, arg); +} + + +int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data) +{ + WOLFSSL_ENTER("wolfSSL_set_ex_data"); +#if defined(HAVE_EX_DATA) || defined(FORTRESS) + if (ssl != NULL) + { + return wolfSSL_CRYPTO_set_ex_data(&ssl->ex_data, idx, data); + } +#else + WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); + (void)ssl; + (void)idx; + (void)data; +#endif + return WOLFSSL_FAILURE; +} + + + +void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx) +{ + WOLFSSL_ENTER("wolfSSL_get_ex_data"); +#if defined(HAVE_EX_DATA) || defined(FORTRESS) + if (ssl != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&ssl->ex_data, idx); + } +#else + WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); + (void)ssl; + (void)idx; +#endif + return 0; +} + +#ifndef NO_DSA +WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x, + pem_password_cb *cb, void *u) +{ + WOLFSSL_DSA* dsa; + DsaKey* key; + int length; + unsigned char* buf; + word32 bufSz; + int ret; + word32 idx = 0; + DerBuffer* pDer; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSAparams"); + + ret = wolfSSL_BIO_get_mem_data(bp, &buf); + if (ret <= 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret); + return NULL; + } + + bufSz = (word32)ret; + + if (cb != NULL || u != NULL) { + /* + * cb is for a call back when encountering encrypted PEM files + * if cb == NULL and u != NULL then u = null terminated password string + */ + WOLFSSL_MSG("Not yet supporting call back or password for encrypted PEM"); + } + + if ((ret = PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL, + NULL)) < 0 ) { + WOLFSSL_MSG("Issue converting from PEM to DER"); + return NULL; + } + + if ((ret = GetSequence(pDer->buffer, &idx, &length, pDer->length)) < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret); + FreeDer(&pDer); + return NULL; + } + + dsa = wolfSSL_DSA_new(); + if (dsa == NULL) { + FreeDer(&pDer); + WOLFSSL_MSG("Error creating DSA struct"); + return NULL; + } + + key = (DsaKey*)dsa->internal; + if (key == NULL) { + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + WOLFSSL_MSG("Error finding DSA key struct"); + return NULL; + } + + if (GetInt(&key->p, pDer->buffer, &idx, pDer->length) < 0 || + GetInt(&key->q, pDer->buffer, &idx, pDer->length) < 0 || + GetInt(&key->g, pDer->buffer, &idx, pDer->length) < 0 ) { + WOLFSSL_MSG("dsa key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; + } + + if (SetIndividualExternal(&dsa->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa p key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; + } + + if (SetIndividualExternal(&dsa->q, &key->q) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa q key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; + } + + if (SetIndividualExternal(&dsa->g, &key->g) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa g key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; + } + + if (x != NULL) { + *x = dsa; + } + + FreeDer(&pDer); + return dsa; +} +#endif /* NO_DSA */ +#endif /* OPENSSL_EXTRA */ +#endif /* WOLFCRYPT_ONLY */ + +#if defined(OPENSSL_EXTRA) + +/* Begin functions for openssl/buffer.h */ +WOLFSSL_BUF_MEM* wolfSSL_BUF_MEM_new(void) +{ + WOLFSSL_BUF_MEM* buf; + buf = (WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), NULL, + DYNAMIC_TYPE_OPENSSL); + if (buf) { + XMEMSET(buf, 0, sizeof(WOLFSSL_BUF_MEM)); + } + return buf; +} + + +/* returns length of buffer on success */ +int wolfSSL_BUF_MEM_grow(WOLFSSL_BUF_MEM* buf, size_t len) +{ + int len_int = (int)len; + int mx; + + /* verify provided arguments */ + if (buf == NULL || len_int < 0) { + return 0; /* BAD_FUNC_ARG; */ + } + + /* check to see if fits in existing length */ + if (buf->length > len) { + buf->length = len; + return len_int; + } + + /* check to see if fits in max buffer */ + if (buf->max >= len) { + if (buf->data != NULL) { + XMEMSET(&buf->data[buf->length], 0, len - buf->length); + } + buf->length = len; + return len_int; + } + + /* expand size, to handle growth */ + mx = (len_int + 3) / 3 * 4; + + /* use realloc */ + buf->data = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf->data == NULL) { + return 0; /* ERR_R_MALLOC_FAILURE; */ + } + + buf->max = mx; + XMEMSET(&buf->data[buf->length], 0, len - buf->length); + buf->length = len; + + return len_int; +} + +void wolfSSL_BUF_MEM_free(WOLFSSL_BUF_MEM* buf) +{ + if (buf) { + if (buf->data) { + XFREE(buf->data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + buf->data = NULL; + } + buf->max = 0; + buf->length = 0; + XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); + } +} +/* End Functions for openssl/buffer.h */ + +#endif /* OPENSSL_EXTRA */ + + +#if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ + || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) + +WOLFSSL_BIO *wolfSSL_BIO_new_file(const char *filename, const char *mode) +{ +#ifndef NO_FILESYSTEM + WOLFSSL_BIO* bio; + XFILE fp; + + WOLFSSL_ENTER("wolfSSL_BIO_new_file"); + + fp = XFOPEN(filename, mode); + if (fp == XBADFILE) + return NULL; + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); + if (bio == NULL) { + XFCLOSE(fp); + return bio; + } + + if (wolfSSL_BIO_set_fp(bio, fp, BIO_CLOSE) != WOLFSSL_SUCCESS) { + XFCLOSE(fp); + wolfSSL_BIO_free(bio); + bio = NULL; + } + + /* file is closed when BIO is free'd */ + return bio; +#else + (void)filename; + (void)mode; + return NULL; +#endif /* NO_FILESYSTEM */ +} + +#ifndef NO_FILESYSTEM +WOLFSSL_BIO* wolfSSL_BIO_new_fp(XFILE fp, int close_flag) +{ + WOLFSSL_BIO* bio; + + WOLFSSL_ENTER("wolfSSL_BIO_new_fp"); + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); + if (bio == NULL) { + return bio; + } + + if (wolfSSL_BIO_set_fp(bio, fp, close_flag) != WOLFSSL_SUCCESS) { + wolfSSL_BIO_free(bio); + bio = NULL; + } + + /* file is closed when BIO is free'd or by user depending on flag */ + return bio; +} +#endif + + +#ifndef NO_DH +WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bio, WOLFSSL_DH **x, + pem_password_cb *cb, void *u) +{ +#ifndef NO_FILESYSTEM + WOLFSSL_DH* localDh = NULL; + unsigned char* mem = NULL; + word32 size; + long sz; + int ret; + DerBuffer *der = NULL; + byte* p = NULL; + byte* g = NULL; + word32 pSz = MAX_DH_SIZE; + word32 gSz = MAX_DH_SIZE; + int memAlloced = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DHparams"); + (void)cb; + (void)u; + + if (bio == NULL) { + WOLFSSL_MSG("Bad Function Argument bio is NULL"); + return NULL; + } + + if (bio->type == WOLFSSL_BIO_MEMORY) { + /* Use the buffer directly. */ + ret = wolfSSL_BIO_get_mem_data(bio, &mem); + if (mem == NULL || ret <= 0) { + WOLFSSL_MSG("Failed to get data from bio struct"); + goto end; + } + size = ret; + } + else if (bio->type == WOLFSSL_BIO_FILE) { + /* Read whole file into a new buffer. */ + if (XFSEEK((XFILE)bio->ptr, 0, SEEK_END) != 0) + goto end; + sz = XFTELL((XFILE)bio->ptr); + if (XFSEEK((XFILE)bio->ptr, 0, SEEK_SET) != 0) + goto end; + if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0L) { + WOLFSSL_MSG("PEM_read_bio_DHparams file size error"); + goto end; + } + mem = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_PEM); + if (mem == NULL) + goto end; + memAlloced = 1; + + if (wolfSSL_BIO_read(bio, (char *)mem, (int)sz) <= 0) + goto end; + size = (word32)sz; + } + else { + WOLFSSL_MSG("BIO type not supported for reading DH parameters"); + goto end; + } + + ret = PemToDer(mem, size, DH_PARAM_TYPE, &der, NULL, NULL, NULL); + if (ret != 0) + goto end; + + /* Use the object passed in, otherwise allocate a new object */ + if (x != NULL) + localDh = *x; + if (localDh == NULL) { + localDh = wolfSSL_DH_new(); + if (localDh == NULL) + goto end; + } + + /* Load data in manually */ + p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + if (p == NULL || g == NULL) + goto end; + + /* Extract the p and g as data from the DER encoded DH parameters. */ + ret = wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz); + if (ret != 0) { + if (x != NULL && localDh != *x) + XFREE(localDh, NULL, DYNAMIC_TYPE_OPENSSL); + localDh = NULL; + goto end; + } + + if (x != NULL) + *x = localDh; + + /* Put p and g in as big numbers. */ + if (localDh->p != NULL) { + wolfSSL_BN_free(localDh->p); + localDh->p = NULL; + } + if (localDh->g != NULL) { + wolfSSL_BN_free(localDh->g); + localDh->g = NULL; + } + localDh->p = wolfSSL_BN_bin2bn(p, pSz, NULL); + localDh->g = wolfSSL_BN_bin2bn(g, gSz, NULL); + if (localDh->p == NULL || localDh->g == NULL) { + if (x != NULL && localDh != *x) + wolfSSL_DH_free(localDh); + localDh = NULL; + } + + if (localDh != NULL && localDh->inSet == 0) { + if (SetDhInternal(localDh) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Unable to set internal DH structure"); + wolfSSL_DH_free(localDh); + localDh = NULL; + } + } + +end: + if (memAlloced) XFREE(mem, NULL, DYNAMIC_TYPE_PEM); + if (der != NULL) FreeDer(&der); + XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + return localDh; +#else + (void)bio; + (void)x; + (void)cb; + (void)u; + return NULL; +#endif +} + +#ifndef NO_FILESYSTEM +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) +/* Convert DH key parameters to DER format, write to output (outSz) + * If output is NULL then max expected size is set to outSz and LENGTH_ONLY_E is + * returned. + * + * Note : static function due to redefinition complications with DhKey and FIPS + * version 2 build. + * + * return bytes written on success */ +int wc_DhParamsToDer(DhKey* key, byte* out, word32* outSz) +{ + word32 sz = 0, idx = 0; + int pSz = 0, gSz = 0, ret; + byte scratch[MAX_LENGTH_SZ]; + + if (key == NULL || outSz == NULL) { + return BAD_FUNC_ARG; + } + + pSz = mp_unsigned_bin_size(&key->p); + if (pSz < 0) { + return pSz; + } + if (mp_leading_bit(&key->p)) { + pSz++; + } + + gSz = mp_unsigned_bin_size(&key->g); + if (gSz < 0) { + return gSz; + } + if (mp_leading_bit(&key->g)) { + gSz++; + } + + sz = ASN_TAG_SZ; /* Integer */ + sz += SetLength(pSz, scratch); + sz += ASN_TAG_SZ; /* Integer */ + sz += SetLength(gSz, scratch); + sz += gSz + pSz; + + if (out == NULL) { + byte seqScratch[MAX_SEQ_SZ]; + + *outSz = sz + SetSequence(sz, seqScratch); + return LENGTH_ONLY_E; + } + + if (*outSz < MAX_SEQ_SZ || *outSz < sz) { + return BUFFER_E; + } + + idx += SetSequence(sz, out); + if (*outSz < idx + sz) { + return BUFFER_E; + } + + out[idx++] = ASN_INTEGER; + idx += SetLength(pSz, out + idx); + if (mp_leading_bit(&key->p)) { + out[idx++] = 0x00; + pSz -= 1; /* subtract 1 from size to account for leading 0 */ + } + ret = mp_to_unsigned_bin(&key->p, out + idx); + if (ret != MP_OKAY) { + return BUFFER_E; + } + idx += pSz; + + out[idx++] = ASN_INTEGER; + idx += SetLength(gSz, out + idx); + if (mp_leading_bit(&key->g)) { + out[idx++] = 0x00; + gSz -= 1; /* subtract 1 from size to account for leading 0 */ + } + ret = mp_to_unsigned_bin(&key->g, out + idx); + if (ret != MP_OKAY) { + return BUFFER_E; + } + idx += gSz; + return idx; +} + +int wc_DhPubKeyToDer(DhKey* key, byte* out, word32* outSz) +{ + word32 sz = 0; + word32 paramSz = 0; + int ret; + int pubSz = 0; + int idx = 0; + byte scratch[MAX_ALGO_SZ]; + + /* Get size of entire key */ + + /* SEQUENCE <--| SetAlgoId + * OBJECT IDENTIFIER <--| + * SEQUENCE <-- + * INTEGER | wc_DhParamsToDer + * INTEGER <-- + */ + ret = wc_DhParamsToDer(key, NULL, ¶mSz); + if (ret != LENGTH_ONLY_E) + return ASN_PARSE_E; + sz += paramSz; + sz += SetAlgoID(DHk, scratch, oidKeyType, paramSz); + + /* BIT STRING + * INTEGER + */ + pubSz = mp_unsigned_bin_size(&key->pub); + if (pubSz < 0) + return pubSz; + + if (mp_leading_bit(&key->pub)) + pubSz++; + + sz += ASN_TAG_SZ; /* Integer */ + sz += SetLength(pubSz, scratch); + sz += pubSz; + + sz += SetBitString(pubSz, 0, scratch); + + if (out == NULL) { + /* Uppermost SEQUENCE */ + *outSz = sz + SetSequence(sz, scratch); + return LENGTH_ONLY_E; + } + /* end get size of entire key */ + + /* Check for indexing errors */ + if (*outSz < MAX_SEQ_SZ || *outSz < sz) { + return BUFFER_E; + } + + /* Build Up Entire Key */ + + idx += SetSequence(sz, out); + + idx += SetAlgoID(DHk, out+idx, oidKeyType, paramSz); + ret = wc_DhParamsToDer(key, out+idx, ¶mSz); + if (ret < 0) + return ret; + idx += ret; + + /* BIT STRING + * INTEGER + */ + idx += SetBitString(pubSz, 0, out+idx); + + out[idx++] = ASN_INTEGER; + idx += SetLength(pubSz, out + idx); + if (mp_leading_bit(&key->pub)) { + out[idx++] = 0x00; + pubSz -= 1; /* subtract 1 from size to account for leading 0 */ + } + ret = mp_to_unsigned_bin(&key->pub, out + idx); + if (ret != MP_OKAY) { + return BUFFER_E; + } + idx += pubSz; + + return idx; +} + +int wc_DhPrivKeyToDer(DhKey* key, byte* out, word32* outSz) +{ + word32 sz = 0; + word32 paramSz = 0; + int ret; + int privSz = 0; + int idx = 0; + byte scratch[MAX_ALGO_SZ]; + + /* Get size of entire key */ + + /* INTEGER 0 */ + sz += ASN_TAG_SZ; /* Integer */ + sz += SetLength(1, scratch); + sz += 1; + + /* SEQUENCE <--| SetAlgoId + * OBJECT IDENTIFIER <--| + * SEQUENCE <-- + * INTEGER | wc_DhParamsToDer + * INTEGER <-- + */ + ret = wc_DhParamsToDer(key, NULL, ¶mSz); + if (ret != LENGTH_ONLY_E) + return ASN_PARSE_E; + sz += paramSz; + sz += SetAlgoID(DHk, scratch, oidKeyType, paramSz); + + /* OCTET STRING + * INTEGER + */ + privSz = mp_unsigned_bin_size(&key->priv); + if (privSz < 0) + return privSz; + else if (privSz > 256) /* Key is larger than 2048 */ + return ASN_VERSION_E; + + if (mp_leading_bit(&key->priv)) + privSz++; + + sz += ASN_TAG_SZ; /* Integer */ + sz += SetLength(privSz, scratch); + sz += privSz; + + sz += SetOctetString(privSz + ASN_OCTET_STRING, scratch); + + if (out == NULL) { + /* Uppermost SEQUENCE */ + *outSz = sz + SetSequence(sz, scratch); + return LENGTH_ONLY_E; + } + /* end get size of entire key */ + + /* Check for indexing errors */ + if (*outSz < MAX_SEQ_SZ || *outSz < sz) { + return BUFFER_E; + } + + /* Build Up Entire Key */ + + idx += SetSequence(sz, out); + + /* INTEGER 0 */ + out[idx++] = ASN_INTEGER; + idx += SetLength(1, out+idx); + out[idx++] = 0; + + idx += SetAlgoID(DHk, out+idx, oidKeyType, paramSz); + ret = wc_DhParamsToDer(key, out+idx, ¶mSz); + if (ret < 0) + return ret; + idx += ret; + + /* OCTET STRING + * INTEGER + */ + if (privSz == 256) { + idx += SetOctetString(privSz + ASN_OCTET_STRING, out+idx); + } else if (privSz == 128) { + idx += SetOctetString(privSz + ASN_OCTET_STRING-1, out+idx); + } else if (privSz == 64) { + idx += SetOctetString(privSz + ASN_OCTET_STRING-2, out+idx); + } else { + WOLFSSL_MSG("Unsupported key size"); + return ASN_VERSION_E; + } + + out[idx++] = ASN_INTEGER; + idx += SetLength(privSz, out + idx); + if (mp_leading_bit(&key->priv)) { + out[idx++] = 0x00; + privSz -= 1; /* subtract 1 from size to account for leading 0 */ + } + ret = mp_to_unsigned_bin(&key->priv, out + idx); + if (ret != MP_OKAY) { + return BUFFER_E; + } + idx += privSz; + + return idx; +} + +/* Writes the DH parameters in PEM format from "dh" out to the file pointer + * passed in. + * + * returns WOLFSSL_SUCCESS on success + */ +int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh) +{ + int ret; + word32 derSz = 0, pemSz = 0; + byte *der, *pem; + DhKey* key; + + WOLFSSL_ENTER("wolfSSL_PEM_write_DHparams"); + + if (dh == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", BAD_FUNC_ARG); + return WOLFSSL_FAILURE; + } + + if (dh->inSet == 0) { + if (SetDhInternal(dh) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Unable to set internal DH structure"); + return WOLFSSL_FAILURE; + } + } + key = (DhKey*)dh->internal; + ret = wc_DhParamsToDer(key, NULL, &derSz); + if (ret != LENGTH_ONLY_E) { + WOLFSSL_MSG("Failed to get size of DH params"); + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); + return WOLFSSL_FAILURE; + } + + der = (byte*)XMALLOC(derSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", MEMORY_E); + return WOLFSSL_FAILURE; + } + ret = wc_DhParamsToDer(key, der, &derSz); + if (ret <= 0) { + WOLFSSL_MSG("Failed to export DH params"); + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); + XFREE(der, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + /* convert to PEM */ + ret = wc_DerToPem(der, derSz, NULL, 0, DH_PARAM_TYPE); + if (ret < 0) { + WOLFSSL_MSG("Failed to convert DH params to PEM"); + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); + XFREE(der, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + pemSz = (word32)ret; + + pem = (byte*)XMALLOC(pemSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", MEMORY_E); + XFREE(der, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + ret = wc_DerToPem(der, derSz, pem, pemSz, DH_PARAM_TYPE); + XFREE(der, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ret < 0) { + WOLFSSL_MSG("Failed to convert DH params to PEM"); + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); + XFREE(pem, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + ret = (int)XFWRITE(pem, 1, pemSz, fp); + XFREE(pem, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ret <= 0) { + WOLFSSL_MSG("Failed to write to file"); + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); + return WOLFSSL_FAILURE; + } + + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_QT || OPENSSL_ALL */ +#endif /* !NO_FILESYSTEM */ +#endif /* !NO_DH */ + +#ifdef WOLFSSL_CERT_GEN + +#ifdef WOLFSSL_CERT_REQ +/* writes the x509 from x to the WOLFSSL_BIO bp + * + * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail + */ +int wolfSSL_PEM_write_bio_X509_REQ(WOLFSSL_BIO *bp, WOLFSSL_X509 *x) +{ + byte* pem; + int pemSz = 0; + const unsigned char* der; + int derSz; + int ret; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509_REQ()"); + + if (x == NULL || bp == NULL) { + return WOLFSSL_FAILURE; + } + + der = wolfSSL_X509_get_der(x, &derSz); + if (der == NULL) { + return WOLFSSL_FAILURE; + } + + /* get PEM size */ + pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERTREQ_TYPE); + if (pemSz < 0) { + return WOLFSSL_FAILURE; + } + + /* create PEM buffer and convert from DER */ + pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) { + return WOLFSSL_FAILURE; + } + if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERTREQ_TYPE) < 0) { + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + /* write the PEM to BIO */ + ret = wolfSSL_BIO_write(bp, pem, pemSz); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret <= 0) return WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_CERT_REQ */ + + +/* writes the x509 from x to the WOLFSSL_BIO bp + * + * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail + */ +int wolfSSL_PEM_write_bio_X509_AUX(WOLFSSL_BIO *bp, WOLFSSL_X509 *x) +{ + byte* pem; + int pemSz = 0; + const unsigned char* der; + int derSz; + int ret; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509_AUX()"); + + if (bp == NULL || x == NULL) { + WOLFSSL_MSG("NULL argument passed in"); + return WOLFSSL_FAILURE; + } + + der = wolfSSL_X509_get_der(x, &derSz); + if (der == NULL) { + return WOLFSSL_FAILURE; + } + + /* get PEM size */ + pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERT_TYPE); + if (pemSz < 0) { + return WOLFSSL_FAILURE; + } + + /* create PEM buffer and convert from DER */ + pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) { + return WOLFSSL_FAILURE; + } + if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERT_TYPE) < 0) { + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + /* write the PEM to BIO */ + ret = wolfSSL_BIO_write(bp, pem, pemSz); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret <= 0) return WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_CERT_GEN */ + +int wolfSSL_PEM_write_bio_X509(WOLFSSL_BIO *bio, WOLFSSL_X509 *cert) +{ + byte* pem; + int pemSz = 0; + const unsigned char* der; + int derSz; + int ret; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509_AUX()"); + + if (bio == NULL || cert == NULL) { + WOLFSSL_MSG("NULL argument passed in"); + return WOLFSSL_FAILURE; + } + + der = wolfSSL_X509_get_der(cert, &derSz); + if (der == NULL) { + return WOLFSSL_FAILURE; + } + + /* get PEM size */ + pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERT_TYPE); + if (pemSz < 0) { + return WOLFSSL_FAILURE; + } + + /* create PEM buffer and convert from DER */ + pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) { + return WOLFSSL_FAILURE; + } + if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERT_TYPE) < 0) { + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + /* write the PEM to BIO */ + ret = wolfSSL_BIO_write(bio, pem, pemSz); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret <= 0) return WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; +} + + +#if defined(OPENSSL_EXTRA) && !defined(NO_DH) +/* Initialize ctx->dh with dh's params. Return WOLFSSL_SUCCESS on ok */ +long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh) +{ + int pSz, gSz; + byte *p, *g; + int ret=0; + + WOLFSSL_ENTER("wolfSSL_CTX_set_tmp_dh"); + + if(!ctx || !dh) + return BAD_FUNC_ARG; + + /* Get needed size for p and g */ + pSz = wolfSSL_BN_bn2bin(dh->p, NULL); + gSz = wolfSSL_BN_bn2bin(dh->g, NULL); + + if(pSz <= 0 || gSz <= 0) + return WOLFSSL_FATAL_ERROR; + + p = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if(!p) + return MEMORY_E; + + g = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if(!g) { + XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + return MEMORY_E; + } + + pSz = wolfSSL_BN_bn2bin(dh->p, p); + gSz = wolfSSL_BN_bn2bin(dh->g, g); + + if(pSz >= 0 && gSz >= 0) /* Conversion successful */ + ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz); + + XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + + return pSz > 0 && gSz > 0 ? ret : WOLFSSL_FATAL_ERROR; +} +#endif /* OPENSSL_EXTRA && !NO_DH */ + + +/* returns the enum value associated with handshake state + * + * ssl the WOLFSSL structure to get state of + */ +int wolfSSL_get_state(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_state"); + + if (ssl == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return SSL_FAILURE; + } + + return ssl->options.handShakeState; +} +#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ + || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) + +long wolfSSL_ctrl(WOLFSSL* ssl, int cmd, long opt, void* pt) +{ + WOLFSSL_ENTER("wolfSSL_ctrl"); + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (cmd) { + #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + case SSL_CTRL_SET_TLSEXT_HOSTNAME: + WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TLSEXT_HOSTNAME."); + #ifdef HAVE_SNI + if (pt == NULL) { + WOLFSSL_MSG("Passed in NULL Host Name."); + break; + } + return wolfSSL_set_tlsext_host_name(ssl, (const char*) pt); + #else + WOLFSSL_MSG("SNI not enabled."); + break; + #endif /* HAVE_SNI */ + #endif /* WOLFSSL_NGINX || WOLFSSL_QT || OPENSSL_ALL */ + default: + WOLFSSL_MSG("Case not implemented."); + } + (void)opt; + (void)pt; + return WOLFSSL_FAILURE; +} + +long wolfSSL_CTX_ctrl(WOLFSSL_CTX* ctx, int cmd, long opt, void* pt) +{ +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + long ctrl_opt; +#endif + long ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CTX_ctrl"); + if (ctx == NULL) + return WOLFSSL_FAILURE; + + switch (cmd) { + case SSL_CTRL_CHAIN: +#ifdef SESSION_CERTS + { + /* + * We don't care about opt here because a copy of the certificate is + * stored anyway so increasing the reference counter is not necessary. + * Just check to make sure that it is set to one of the correct values. + */ + WOLF_STACK_OF(WOLFSSL_X509)* sk = (WOLF_STACK_OF(WOLFSSL_X509)*) pt; + WOLFSSL_X509* x509; + int i; + if (opt != 0 && opt != 1) { + ret = WOLFSSL_FAILURE; + break; + } + /* Clear certificate chain */ + FreeDer(&ctx->certChain); + if (sk) { + for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { + x509 = wolfSSL_sk_X509_value(sk, i); + /* Prevent wolfSSL_CTX_add_extra_chain_cert from freeing cert */ + if (wolfSSL_X509_up_ref(x509) != 1) { + WOLFSSL_MSG("Error increasing reference count"); + continue; + } + if (wolfSSL_CTX_add_extra_chain_cert(ctx, x509) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error adding certificate to context"); + /* Decrease reference count on failure */ + wolfSSL_X509_free(x509); + } + } + } + /* Free previous chain */ + wolfSSL_sk_X509_free(ctx->x509Chain); + ctx->x509Chain = sk; + if (sk) { + for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { + x509 = wolfSSL_sk_X509_value(sk, i); + /* On successful setting of new chain up all refs */ + if (wolfSSL_X509_up_ref(x509) != 1) { + WOLFSSL_MSG("Error increasing reference count"); + continue; + } + } + } + } +#else + WOLFSSL_MSG("Session certificates not compiled in"); + ret = WOLFSSL_FAILURE; +#endif + break; + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + case SSL_CTRL_OPTIONS: + WOLFSSL_MSG("Entering Case: SSL_CTRL_OPTIONS."); + ctrl_opt = wolfSSL_CTX_set_options(ctx, opt); + + #ifdef WOLFSSL_QT + /* Set whether to use client or server cipher preference */ + if ((ctrl_opt & SSL_OP_CIPHER_SERVER_PREFERENCE) + == SSL_OP_CIPHER_SERVER_PREFERENCE) { + WOLFSSL_MSG("Using Server's Cipher Preference."); + ctx->useClientOrder = FALSE; + } else { + WOLFSSL_MSG("Using Client's Cipher Preference."); + ctx->useClientOrder = TRUE; + } + #endif /* WOLFSSL_QT */ + + return ctrl_opt; +#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ + case SSL_CTRL_EXTRA_CHAIN_CERT: + WOLFSSL_MSG("Entering Case: SSL_CTRL_EXTRA_CHAIN_CERT."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in x509 pointer NULL."); + ret = WOLFSSL_FAILURE; + break; + } + return wolfSSL_CTX_add_extra_chain_cert(ctx, (WOLFSSL_X509*)pt); + +#ifndef NO_DH + case SSL_CTRL_SET_TMP_DH: + WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_DH."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in DH pointer NULL."); + ret = WOLFSSL_FAILURE; + break; + } + return wolfSSL_CTX_set_tmp_dh(ctx, (WOLFSSL_DH*)pt); +#endif + +#ifdef HAVE_ECC + case SSL_CTRL_SET_TMP_ECDH: + WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_ECDH."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in ECDH pointer NULL."); + ret = WOLFSSL_FAILURE; + break; + } + return wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, (WOLFSSL_EC_KEY*)pt); +#endif + case SSL_CTRL_MODE: + wolfSSL_CTX_set_mode(ctx,opt); + break; + + default: + WOLFSSL_MSG("CTX_ctrl cmd not implemented"); + ret = WOLFSSL_FAILURE; + break; + } + + (void)ctx; + (void)cmd; + (void)opt; + (void)pt; + WOLFSSL_LEAVE("wolfSSL_CTX_ctrl", (int)ret); + return ret; +} + +#ifndef WOLFSSL_NO_STUB +long wolfSSL_CTX_callback_ctrl(WOLFSSL_CTX* ctx, int cmd, void (*fp)(void)) +{ + (void) ctx; + (void) cmd; + (void) fp; + WOLFSSL_STUB("wolfSSL_CTX_callback_ctrl"); + return WOLFSSL_FAILURE; + +} +#endif /* WOLFSSL_NO_STUB */ + +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx) +{ + return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0l, NULL); +} +#endif + +/* Returns the verifyCallback from the ssl structure if successful. +Returns NULL otherwise. */ +VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_verify_callback()"); + if (ssl) { + return ssl->verifyCallback; + } + return NULL; +} + +/* Creates a new bio pair. +Returns WOLFSSL_SUCCESS if no error, WOLFSSL_FAILURE otherwise.*/ +int wolfSSL_BIO_new_bio_pair(WOLFSSL_BIO **bio1_p, size_t writebuf1, + WOLFSSL_BIO **bio2_p, size_t writebuf2) +{ + WOLFSSL_BIO *bio1 = NULL, *bio2 = NULL; + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_BIO_new_bio_pair()"); + + if (bio1_p == NULL || bio2_p == NULL) { + WOLFSSL_MSG("Bad Function Argument"); + return BAD_FUNC_ARG; + } + + /* set up the new bio structures and write buf sizes */ + if ((bio1 = wolfSSL_BIO_new(wolfSSL_BIO_s_bio())) == NULL) { + WOLFSSL_MSG("Bio allocation failed"); + ret = WOLFSSL_FAILURE; + } + if (ret) { + if ((bio2 = wolfSSL_BIO_new(wolfSSL_BIO_s_bio())) == NULL) { + WOLFSSL_MSG("Bio allocation failed"); + ret = WOLFSSL_FAILURE; + } + } + if (ret && writebuf1) { + if (!(ret = wolfSSL_BIO_set_write_buf_size(bio1, writebuf1))) { + WOLFSSL_MSG("wolfSSL_BIO_set_write_buf() failure"); + } + } + if (ret && writebuf2) { + if (!(ret = wolfSSL_BIO_set_write_buf_size(bio2, writebuf2))) { + WOLFSSL_MSG("wolfSSL_BIO_set_write_buf() failure"); + } + } + + if (ret) { + if ((ret = wolfSSL_BIO_make_bio_pair(bio1, bio2))) { + *bio1_p = bio1; + *bio2_p = bio2; + } + } + if (!ret) { + wolfSSL_BIO_free(bio1); + bio1 = NULL; + wolfSSL_BIO_free(bio2); + bio2 = NULL; + } + return ret; +} + + +#if !defined(HAVE_FAST_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(NO_RSA) && !defined(HAVE_USER_RSA) +/* Converts an rsa key from a bio buffer into an internal rsa structure. +Returns a pointer to the new WOLFSSL_RSA structure. */ +WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) +{ + const unsigned char* bioMem = NULL; + int bioMemSz = 0; + WOLFSSL_RSA* key = NULL; + unsigned char maxKeyBuf[4096]; + unsigned char* bufPtr = NULL; + unsigned char* extraBioMem = NULL; + int extraBioMemSz = 0; + int derLength = 0; + int j = 0, i = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio()"); + + if (bio == NULL) { + WOLFSSL_MSG("Bad Function Argument"); + return NULL; + } + (void)out; + + bioMemSz = wolfSSL_BIO_pending(bio); + if (bioMemSz <= 0) { + WOLFSSL_MSG("wolfSSL_BIO_pending() failure"); + return NULL; + } + + bioMem = (unsigned char*)XMALLOC(bioMemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (bioMem == NULL) { + WOLFSSL_MSG("Malloc failure"); + return NULL; + } + + bufPtr = maxKeyBuf; + if (wolfSSL_BIO_read(bio, (unsigned char*)bioMem, (int)bioMemSz) == bioMemSz) { + const byte* bioMemPt = bioMem; /* leave bioMem pointer unaltered */ + if ((key = wolfSSL_d2i_RSAPrivateKey(NULL, &bioMemPt, bioMemSz)) == NULL) { + XFREE((unsigned char*)bioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + /* This function is used to get the total length of the rsa key. */ + derLength = wolfSSL_i2d_RSAPrivateKey(key, &bufPtr); + + /* Write extra data back into bio object if necessary. */ + extraBioMemSz = (bioMemSz - derLength); + if (extraBioMemSz > 0) { + extraBioMem = (unsigned char *)XMALLOC(extraBioMemSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (extraBioMem == NULL) { + WOLFSSL_MSG("Malloc failure"); + XFREE((unsigned char*)extraBioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE((unsigned char*)bioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + for (i = derLength; i < bioMemSz; i++) { + *(extraBioMem + j) = *(bioMem + i); + j++; + } + + wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz); + if (wolfSSL_BIO_pending(bio) <= 0) { + WOLFSSL_MSG("Failed to write memory to bio"); + XFREE((unsigned char*)extraBioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE((unsigned char*)bioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + XFREE((unsigned char*)extraBioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } + + if (out != NULL && key != NULL) { + *out = key; + } + } + XFREE((unsigned char*)bioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return key; +} +#endif + + +/* Adds the ASN1 certificate to the user ctx. +Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/ +int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz, + const unsigned char *der) +{ + WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1()"); + if (der != NULL && ctx != NULL) { + if (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz, + WOLFSSL_FILETYPE_ASN1) == WOLFSSL_SUCCESS) { + return WOLFSSL_SUCCESS; + } + + } + return WOLFSSL_FAILURE; +} + + +#if !defined(HAVE_FAST_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(NO_RSA) && !defined(HAVE_USER_RSA) +/* Adds the rsa private key to the user ctx. +Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/ +int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa) +{ + int ret; + int derSize; + unsigned char maxDerBuf[4096]; + unsigned char* key = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey()"); + + if (ctx == NULL || rsa == NULL) { + WOLFSSL_MSG("one or more inputs were NULL"); + return BAD_FUNC_ARG; + } + key = maxDerBuf; + /* convert RSA struct to der encoded buffer and get the size */ + if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &key)) <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure"); + return WOLFSSL_FAILURE; + } + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, (const unsigned char*)maxDerBuf, + derSize, SSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure"); + return WOLFSSL_FAILURE; + } + return ret; +} +#endif /* NO_RSA && !HAVE_FAST_RSA */ + + +/* Converts EVP_PKEY data from a bio buffer to a WOLFSSL_EVP_PKEY structure. +Returns pointer to private EVP_PKEY struct upon success, NULL if there +is a failure.*/ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** out) +{ + unsigned char* mem = NULL; + int memSz = 0; + WOLFSSL_EVP_PKEY* key = NULL; + int i = 0, j = 0; + unsigned char* extraBioMem = NULL; + int extraBioMemSz = 0; + int derLength = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio()"); + + if (bio == NULL) { + return NULL; + } + (void)out; + + memSz = wolfSSL_BIO_pending(bio); + if (memSz <= 0) { + WOLFSSL_MSG("wolfSSL_BIO_pending() failure"); + return NULL; + } + + mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + WOLFSSL_MSG("Malloc failure"); + return NULL; + } + + if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) { + /* Determines key type and returns the new private EVP_PKEY object */ + if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == NULL) { + WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + /* Write extra data back into bio object if necessary. */ + derLength = key->pkey_sz; + extraBioMemSz = (memSz - derLength); + if (extraBioMemSz > 0) { + extraBioMem = (unsigned char *)XMALLOC(extraBioMemSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (extraBioMem == NULL) { + WOLFSSL_MSG("Malloc failure"); + XFREE((unsigned char*)extraBioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + for (i = derLength; i < memSz; i++) { + *(extraBioMem + j) = *(mem + i); + j++; + } + + wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz); + if (wolfSSL_BIO_pending(bio) <= 0) { + WOLFSSL_MSG("Failed to write memory to bio"); + XFREE((unsigned char*)extraBioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + XFREE((unsigned char*)extraBioMem, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } + + if (out != NULL) { + *out = key; + } + } + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return key; +} + + +/* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure. + * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL + * on fail */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, + unsigned char** in, long inSz) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* mem; + long memSz = inSz; + + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP()"); + + if (in == NULL || *in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + mem = *in; + + #if !defined(NO_RSA) + { + RsaKey rsa; + word32 keyIdx = 0; + + /* test if RSA key */ + if (wc_InitRsaKey(&rsa, NULL) == 0 && + wc_RsaPrivateKeyDecode(mem, &keyIdx, &rsa, (word32)memSz) == 0) { + wc_FreeRsaKey(&rsa); + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey != NULL) { + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, + DYNAMIC_TYPE_PRIVATE_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_RSA; + if (out != NULL) { + *out = pkey; + } + + pkey->ownRsa = 1; + pkey->rsa = wolfSSL_RSA_new(); + if (pkey->rsa == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + if (wolfSSL_RSA_LoadDer_ex(pkey->rsa, + (const unsigned char*)pkey->pkey.ptr, + pkey->pkey_sz, WOLFSSL_RSA_LOAD_PRIVATE) != 1) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; + } + } + wc_FreeRsaKey(&rsa); + } + #endif /* NO_RSA */ + + #ifdef HAVE_ECC + { + word32 keyIdx = 0; + ecc_key ecc; + + /* test if ecc key */ + if (wc_ecc_init(&ecc) == 0 && + wc_EccPrivateKeyDecode(mem, &keyIdx, &ecc, (word32)memSz) == 0) { + wc_ecc_free(&ecc); + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey != NULL) { + pkey->pkey_sz = keyIdx; + pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL, + DYNAMIC_TYPE_PRIVATE_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, mem, keyIdx); + pkey->type = EVP_PKEY_EC; + if (out != NULL) { + *out = pkey; + } + return pkey; + } + } + wc_ecc_free(&ecc); + } + #endif /* HAVE_ECC */ + return pkey; +} +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ + + +/* stunnel compatibility functions*/ +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) +void wolfSSL_ERR_remove_thread_state(void* pid) +{ + (void) pid; + return; +} + +#ifndef NO_FILESYSTEM +/***TBD ***/ +void wolfSSL_print_all_errors_fp(XFILE fp) +{ + (void)fp; +} +#endif + +int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data"); +#ifdef HAVE_EX_DATA + if(session != NULL) { + return wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, data); + } +#else + (void)session; + (void)idx; + (void)data; +#endif + return WOLFSSL_FAILURE; +} + + +int wolfSSL_SESSION_get_ex_new_index(long idx, void* data, void* cb1, + void* cb2, CRYPTO_free_func* cb3) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_new_index"); + (void)idx; + (void)cb1; + (void)cb2; + (void)cb3; + if (XSTRNCMP((const char*)data, "redirect index", 14) == 0) { + return 0; + } + else if (XSTRNCMP((const char*)data, "addr index", 10) == 0) { + return 1; + } + return WOLFSSL_FAILURE; +} + + +void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data"); +#ifdef HAVE_EX_DATA + if (session != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx); + } +#else + (void)session; + (void)idx; +#endif + return NULL; +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int), + void *(*r) (void *, size_t, const char *, + int), void (*f) (void *)) +{ + (void) m; + (void) r; + (void) f; + WOLFSSL_ENTER("wolfSSL_CRYPTO_set_mem_ex_functions"); + WOLFSSL_STUB("CRYPTO_set_mem_ex_functions"); + + return WOLFSSL_FAILURE; +} +#endif + + +void wolfSSL_CRYPTO_cleanup_all_ex_data(void){ + WOLFSSL_ENTER("CRYPTO_cleanup_all_ex_data"); +} + + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator, + void (*callback) (int, int, void *), void *cb_arg) +{ + (void)prime_len; + (void)generator; + (void)callback; + (void)cb_arg; + WOLFSSL_ENTER("wolfSSL_DH_generate_parameters"); + WOLFSSL_STUB("DH_generate_parameters"); + + return NULL; +} +#endif + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_DH_generate_parameters_ex(WOLFSSL_DH* dh, int prime_len, int generator, + void (*callback) (int, int, void *)) +{ + (void)prime_len; + (void)generator; + (void)callback; + (void)dh; + WOLFSSL_ENTER("wolfSSL_DH_generate_parameters_ex"); + WOLFSSL_STUB("DH_generate_parameters_ex"); + + return -1; +} +#endif + +void wolfSSL_ERR_load_crypto_strings(void) +{ + WOLFSSL_ENTER("wolfSSL_ERR_load_crypto_strings"); + /* Do nothing */ + return; +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_FIPS_mode(void) +{ + WOLFSSL_ENTER("wolfSSL_FIPS_mode"); + WOLFSSL_STUB("FIPS_mode"); + + return WOLFSSL_FAILURE; +} +#endif + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_FIPS_mode_set(int r) +{ + (void)r; + WOLFSSL_ENTER("wolfSSL_FIPS_mode_set"); + WOLFSSL_STUB("FIPS_mode_set"); + + return WOLFSSL_FAILURE; +} +#endif + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_RAND_set_rand_method(const void *meth) +{ + (void) meth; + WOLFSSL_ENTER("wolfSSL_RAND_set_rand_method"); + WOLFSSL_STUB("RAND_set_rand_method"); + + /* if implemented RAND_bytes and RAND_pseudo_bytes need updated + * those two functions will call the respective functions from meth */ + return SSL_FAILURE; +} +#endif + +int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits) +{ + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_CIPHER_get_bits"); + + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + (void)alg_bits; + if (c!= NULL) + ret = c->bits; + #else + if (c != NULL && c->ssl != NULL) { + ret = 8 * c->ssl->specs.key_size; + if (alg_bits != NULL) { + *alg_bits = ret; + } + } + #endif + return ret; +} + +#if defined(OPENSSL_ALL) +WOLFSSL_X509_INFO* wolfSSL_X509_INFO_new(void) +{ + WOLFSSL_X509_INFO* info; + info = (WOLFSSL_X509_INFO*)XMALLOC(sizeof(WOLFSSL_X509_INFO), NULL, + DYNAMIC_TYPE_X509); + if (info) { + XMEMSET(info, 0, sizeof(*info)); + } + return info; +} + +void wolfSSL_X509_INFO_free(WOLFSSL_X509_INFO* info) +{ + if (info == NULL) + return; + + if (info->x509) { + wolfSSL_X509_free(info->x509); + info->x509 = NULL; + } +#ifdef HAVE_CRL + if (info->crl) { + wolfSSL_X509_CRL_free(info->crl); + info->crl = NULL; + } +#endif + wolfSSL_X509_PKEY_free(info->x_pkey); + info->x_pkey = NULL; + + XFREE(info, NULL, DYNAMIC_TYPE_X509); +} +#endif + +WOLFSSL_STACK* wolfSSL_sk_X509_INFO_new_null(void) +{ + WOLFSSL_STACK* sk = wolfSSL_sk_new_node(NULL); + if (sk) { + sk->type = STACK_TYPE_X509_INFO; + } + return sk; +} + + +/* returns value less than 0 on fail to match + * On a successful match the priority level found is returned + */ +int wolfSSL_sk_SSL_CIPHER_find( + WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, const WOLFSSL_CIPHER* toFind) +{ + WOLFSSL_STACK* next; + int i, sz; + + if (sk == NULL || toFind == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + sz = wolfSSL_sk_SSL_CIPHER_num(sk); + next = sk; + for (i = 0; i < sz && next != NULL; i++) { + if (next->data.cipher.cipherSuite0 == toFind->cipherSuite0 && + next->data.cipher.cipherSuite == toFind->cipherSuite) { + return sz - i; /* reverse because stack pushed highest on first */ + } + next = next->next; + } + return WOLFSSL_FATAL_ERROR; +} + + +/* copies over data of "in" to "out" */ +static void wolfSSL_CIPHER_copy(WOLFSSL_CIPHER* in, WOLFSSL_CIPHER* out) +{ + if (in == NULL || out == NULL) + return; + + out->cipherSuite = in->cipherSuite; + out->cipherSuite0 = in->cipherSuite0; +} + + +/* create duplicate of stack and return the new stack + * returns null on failure */ +WOLF_STACK_OF(WOLFSSL_CIPHER)* wolfSSL_sk_SSL_CIPHER_dup( + WOLF_STACK_OF(WOLFSSL_CIPHER)* in) +{ + WOLFSSL_STACK* current; + WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL; + int i, sz; + + sz = wolfSSL_sk_SSL_CIPHER_num(in); + current = in; + for (i = 0; i < sz && current != NULL; i++) { + WOLFSSL_STACK* add = wolfSSL_sk_new_node(in->heap); + if (add != NULL) { + add->type = STACK_TYPE_CIPHER; + wolfSSL_CIPHER_copy(&(current->data.cipher), &(add->data.cipher)); + add->num = i+1; + add->next = ret; + ret = add; + current = current->next; + } + } + return ret; +} + +/* nothing to do yet */ +static void wolfSSL_CIPHER_free(WOLFSSL_CIPHER* in) +{ + (void)in; +} + + +/* free's all nodes in the stack and there data */ +void wolfSSL_sk_SSL_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk) +{ + WOLFSSL_STACK* current = sk; + + while (current != NULL) { + WOLFSSL_STACK* toFree = current; + current = current->next; + + wolfSSL_CIPHER_free(&(toFree->data.cipher)); + wolfSSL_sk_free_node(toFree); + } +} + + +int wolfSSL_sk_X509_INFO_num(const WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_INFO_num"); + + if (sk == NULL) + return -1; + return (int)sk->num; +} + +WOLFSSL_X509_INFO* wolfSSL_sk_X509_INFO_value(const WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk, int i) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_INFO_value"); + + for (; sk != NULL && i > 0; i--) + sk = sk->next; + + if (i != 0 || sk == NULL) + return NULL; + return sk->data.info; +} + +WOLFSSL_X509_INFO* wolfSSL_sk_X509_INFO_pop(WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk) +{ + WOLFSSL_STACK* node; + WOLFSSL_X509_INFO* info; + + if (sk == NULL) { + return NULL; + } + + node = sk->next; + info = sk->data.info; + + if (node != NULL) { /* update sk and remove node from stack */ + sk->data.info = node->data.info; + sk->next = node->next; + XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); + } + else { /* last x509 in stack */ + sk->data.info = NULL; + } + + if (sk->num > 0) { + sk->num -= 1; + } + + return info; +} + +#if defined(OPENSSL_ALL) +void wolfSSL_sk_X509_INFO_pop_free(WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk, + void (*f) (WOLFSSL_X509_INFO*)) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_X509_INFO_pop_free"); + + if (sk == NULL) { + return; + } + + /* parse through stack freeing each node */ + node = sk->next; + while (node && sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + + if (f) + f(tmp->data.info); + else + wolfSSL_X509_INFO_free(tmp->data.info); + tmp->data.info = NULL; + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + if (f) + f(sk->data.info); + else + wolfSSL_X509_INFO_free(sk->data.info); + sk->data.info = NULL; + } + XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL); +} + +void wolfSSL_sk_X509_INFO_free(WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk) +{ + wolfSSL_sk_X509_INFO_pop_free(sk, NULL); +} + + +/* Adds the WOLFSSL_X509_INFO to the stack "sk". "sk" takes control of "in" and + * tries to free it when the stack is free'd. + * + * return 1 on success 0 on fail + */ +int wolfSSL_sk_X509_INFO_push(WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk, + WOLFSSL_X509_INFO* in) +{ + WOLFSSL_STACK* node; + + if (sk == NULL || in == NULL) { + return WOLFSSL_FAILURE; + } + + /* no previous values in stack */ + if (sk->data.info == NULL) { + sk->data.info = in; + sk->num += 1; + return WOLFSSL_SUCCESS; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_X509); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return WOLFSSL_FAILURE; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new obj onto head of stack */ + node->data.info = sk->data.info; + node->next = sk->next; + node->type = sk->type; + sk->next = node; + sk->data.info = in; + sk->num += 1; + + return WOLFSSL_SUCCESS; +} + + +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_sk_X509_NAME_new(wolf_sk_compare_cb cb) +{ + WOLFSSL_STACK* sk; + + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_new"); + + sk = wolfSSL_sk_new_node(NULL); + if (sk != NULL) { + sk->type = STACK_TYPE_X509_NAME; + sk->comp = cb; + } + + return sk; +} + +int wolfSSL_sk_X509_NAME_push(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, + WOLFSSL_X509_NAME* name) +{ + WOLFSSL_STACK* node; + + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_push"); + + if (sk == NULL || name == NULL) { + return BAD_FUNC_ARG; + } + + /* no previous values in stack */ + if (sk->data.name == NULL) { + sk->data.name = name; + sk->num += 1; + return 0; + } + + /* stack already has value(s) create a new node and add more */ + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_OPENSSL); + if (node == NULL) { + WOLFSSL_MSG("Memory error"); + return MEMORY_E; + } + XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); + + /* push new obj onto head of stack */ + node->data.name = sk->data.name; + node->next = sk->next; + sk->type = STACK_TYPE_X509_NAME; + sk->next = node; + sk->data.name = name; + sk->num += 1; + + return 0; +} + +/* return index of found, or negative to indicate not found */ +int wolfSSL_sk_X509_NAME_find(const WOLF_STACK_OF(WOLFSSL_X509_NAME) *sk, + WOLFSSL_X509_NAME *name) +{ + int i; + + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_find"); + + if (sk == NULL) + return BAD_FUNC_ARG; + + for (i = 0; sk; i++, sk = sk->next) { + if (wolfSSL_X509_NAME_cmp(sk->data.name, name) == 0) { + return i; + } + } + return -1; +} + +int wolfSSL_sk_X509_OBJECT_num(const WOLF_STACK_OF(WOLFSSL_X509_OBJECT) *s) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_OBJECT_num"); + if (s) { + return (int)s->num; + } else { + return 0; + } +} + + +int wolfSSL_sk_X509_NAME_set_cmp_func(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, + wolf_sk_compare_cb cb) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_set_cmp_func"); + + if (sk == NULL) + return BAD_FUNC_ARG; + + sk->comp = cb; + return 0; +} +#endif /* OPENSSL_ALL */ + +int wolfSSL_sk_X509_NAME_num(const WOLF_STACK_OF(WOLFSSL_X509_NAME) *sk) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_num"); + + if (sk == NULL) + return BAD_FUNC_ARG; + + return (int)sk->num; +} + +/* Getter function for WOLFSSL_X509_NAME pointer + * + * sk is the stack to retrieve pointer from + * i is the index value in stack + * + * returns a pointer to a WOLFSSL_X509_NAME structure on success and NULL on + * fail + */ +WOLFSSL_X509_NAME* wolfSSL_sk_X509_NAME_value(const STACK_OF(WOLFSSL_X509_NAME)* sk, + int i) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_value"); + + for (; sk != NULL && i > 0; i--) { + sk = sk->next; + } + + if (i != 0 || sk == NULL) + return NULL; + + return sk->data.name; +} + +WOLFSSL_X509_NAME* wolfSSL_sk_X509_NAME_pop(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk) +{ + WOLFSSL_STACK* node; + WOLFSSL_X509_NAME* name; + + if (sk == NULL) { + return NULL; + } + + node = sk->next; + name = sk->data.name; + + if (node != NULL) { /* update sk and remove node from stack */ + sk->data.name = node->data.name; + sk->next = node->next; + XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); + } + else { /* last x509 in stack */ + sk->data.name = NULL; + } + + if (sk->num > 0) { + sk->num -= 1; + } + + return name; +} + +void wolfSSL_sk_X509_NAME_pop_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, + void (*f) (WOLFSSL_X509_NAME*)) +{ + WOLFSSL_STACK* node; + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_pop_free"); + + if (sk == NULL) + return; + + node = sk->next; + while (node && sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + if (f) + f(tmp->data.name); + else + wolfSSL_X509_NAME_free(tmp->data.name); + tmp->data.name = NULL; + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + sk->num -= 1; + } + + /* free head of stack */ + if (sk->num == 1) { + if (f) + f(sk->data.name); + else + wolfSSL_X509_NAME_free(sk->data.name); + sk->data.name = NULL; + } + + XFREE(sk, sk->heap, DYNAMIC_TYPE_OPENSSL); +} + +/* Free only the sk structure, NOT X509_NAME members */ +void wolfSSL_sk_X509_NAME_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk) +{ + WOLFSSL_STACK* node; + WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_free"); + + if (sk == NULL) + return; + + node = sk->next; + while (sk->num > 1) { + WOLFSSL_STACK* tmp = node; + node = node->next; + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + sk->num -= 1; + } + + XFREE(sk, sk->heap, DYNAMIC_TYPE_OPENSSL); +} + +#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) +/* Helper function for X509_NAME_print_ex. Sets *buf to string for domain + name attribute based on NID. Returns size of buf */ +static int get_dn_attr_by_nid(int n, const char** buf) +{ + int len = 0; + const char *str; + + switch(n) + { + case NID_commonName : + str = "CN"; + len = 2; + break; + case NID_countryName: + str = "C"; + len = 1; + break; + case NID_localityName: + str = "L"; + len = 1; + break; + case NID_stateOrProvinceName: + str = "ST"; + len = 2; + break; + case NID_organizationName: + str = "O"; + len = 1; + break; + case NID_organizationalUnitName: + str = "OU"; + len = 2; + break; + case NID_emailAddress: + str = "emailAddress"; + len = 12; + break; + default: + WOLFSSL_MSG("Attribute type not found"); + str = NULL; + + } + if (buf != NULL) + *buf = str; + return len; +} +#endif + +/* + * The BIO output of wolfSSL_X509_NAME_print_ex does NOT include the null terminator + */ +int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, + int indent, unsigned long flags) +{ +#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + int count = 0, len = 0, totalSz = 0, tmpSz = 0; + char tmp[ASN_NAME_MAX]; + char fullName[ASN_NAME_MAX]; + const char *buf = NULL; + WOLFSSL_X509_NAME_ENTRY* ne; + WOLFSSL_ASN1_STRING* str; +#endif + int i; + (void)flags; + WOLFSSL_ENTER("wolfSSL_X509_NAME_print_ex"); + + for (i = 0; i < indent; i++) { + if (wolfSSL_BIO_write(bio, " ", 1) != 1) + return WOLFSSL_FAILURE; + } + +#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) + /* If XN_FLAG_DN_REV is present, print X509_NAME in reverse order */ + if (flags == (XN_FLAG_RFC2253 & ~XN_FLAG_DN_REV)) { + fullName[0] = '\0'; + count = wolfSSL_X509_NAME_entry_count(name); + for (i = 0; i < count; i++) { + ne = wolfSSL_X509_NAME_get_entry(name, count - i - 1); + if (ne == NULL) + return WOLFSSL_FAILURE; + + str = wolfSSL_X509_NAME_ENTRY_get_data(ne); + if (str == NULL) + return WOLFSSL_FAILURE; + + len = get_dn_attr_by_nid(ne->nid, &buf); + if (len == 0 || buf == NULL) + return WOLFSSL_FAILURE; + + tmpSz = str->length + len + 2; /* + 2 for '=' and comma */ + if (tmpSz > ASN_NAME_MAX) { + WOLFSSL_MSG("Size greater than ASN_NAME_MAX"); + return WOLFSSL_FAILURE; + } + + if (i < count - 1) { + /* tmpSz+1 for last null char */ + XSNPRINTF(tmp, tmpSz+1, "%s=%s,", buf, str->data); + XSTRNCAT(fullName, tmp, tmpSz); + } + else { + XSNPRINTF(tmp, tmpSz, "%s=%s", buf, str->data); + XSTRNCAT(fullName, tmp, tmpSz-1); + tmpSz--; /* Don't include null char in tmpSz */ + } + totalSz += tmpSz; + } + if (wolfSSL_BIO_write(bio, fullName, totalSz) != totalSz) + return WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; + } +#else + if (flags == XN_FLAG_RFC2253) { + if (wolfSSL_BIO_write(bio, name->name + 1, name->sz - 2) + != name->sz - 2) + return WOLFSSL_FAILURE; + } +#endif /* WOLFSSL_APACHE_HTTPD || OPENSSL_ALL || WOLFSSL_NGINX */ + else if (wolfSSL_BIO_write(bio, name->name, name->sz - 1) != name->sz - 1) + return WOLFSSL_FAILURE; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_ASN1_BIT_STRING* wolfSSL_X509_get0_pubkey_bitstr(const WOLFSSL_X509* x) +{ + (void)x; + WOLFSSL_ENTER("wolfSSL_X509_get0_pubkey_bitstr"); + WOLFSSL_STUB("X509_get0_pubkey_bitstr"); + + return NULL; +} +#endif + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) +{ + (void)ctx; + (void)session; + WOLFSSL_ENTER("wolfSSL_CTX_add_session"); + WOLFSSL_STUB("SSL_CTX_add_session"); + + return WOLFSSL_SUCCESS; +} +#endif + + +int wolfSSL_version(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_version"); + if (ssl->version.major == SSLv3_MAJOR) { + switch (ssl->version.minor) { + case SSLv3_MINOR : + return SSL3_VERSION; + case TLSv1_MINOR : + return TLS1_VERSION; + case TLSv1_1_MINOR : + return TLS1_1_VERSION; + case TLSv1_2_MINOR : + return TLS1_2_VERSION; + case TLSv1_3_MINOR : + return TLS1_3_VERSION; + default: + return WOLFSSL_FAILURE; + } + } + else if (ssl->version.major == DTLS_MAJOR) { + switch (ssl->version.minor) { + case DTLS_MINOR : + return DTLS1_VERSION; + case DTLSv1_2_MINOR : + return DTLS1_2_VERSION; + default: + return WOLFSSL_FAILURE; + } + } + return WOLFSSL_FAILURE; +} + + +int wolfSSL_X509_NAME_get_sz(WOLFSSL_X509_NAME* name) +{ + WOLFSSL_ENTER("wolfSSL_X509_NAME_get_sz"); + if(!name) + return -1; + return name->sz; +} + +#ifdef HAVE_SNI +int wolfSSL_set_tlsext_host_name(WOLFSSL* ssl, const char* host_name) +{ + int ret; + WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name"); + ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, + host_name, (word16)XSTRLEN(host_name)); + WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret); + return ret; +} + + +#ifndef NO_WOLFSSL_SERVER +const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) +{ + void * serverName = NULL; + if (ssl == NULL) + return NULL; + TLSX_SNI_GetRequest(ssl->extensions, type, &serverName); + return (const char *)serverName; +} +#endif /* NO_WOLFSSL_SERVER */ +#endif /* HAVE_SNI */ + +WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) +{ + if (ssl && ctx && SetSSL_CTX(ssl, ctx, 0) == WOLFSSL_SUCCESS) + return ssl->ctx; + return NULL; +} + + +VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback"); + if(ctx) + return ctx->verifyCallback; + return NULL; +} + + +void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_servername_callback"); + if (ctx) + ctx->sniRecvCb = cb; +} + +int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx, + CallbackSniRecv cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback"); + if (ctx) { + ctx->sniRecvCb = cb; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + +int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg"); + if (ctx) { + ctx->sniRecvCbArg = arg; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + +void wolfSSL_ERR_load_BIO_strings(void) { + WOLFSSL_ENTER("ERR_load_BIO_strings"); + /* do nothing */ +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_THREADID_set_callback(void(*threadid_func)(void*)) +{ + WOLFSSL_ENTER("wolfSSL_THREADID_set_callback"); + WOLFSSL_STUB("CRYPTO_THREADID_set_callback"); + (void)threadid_func; + return; +} +#endif + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_THREADID_set_numeric(void* id, unsigned long val) +{ + WOLFSSL_ENTER("wolfSSL_THREADID_set_numeric"); + WOLFSSL_STUB("CRYPTO_THREADID_set_numeric"); + (void)id; + (void)val; + return; +} +#endif + + +#ifndef NO_WOLFSSL_STUB +WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_STORE_get1_certs( + WOLFSSL_X509_STORE_CTX* ctx, WOLFSSL_X509_NAME* name) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_get1_certs"); + WOLFSSL_STUB("X509_STORE_get1_certs"); + (void)ctx; + (void)name; + return NULL; +} + +WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( + WOLFSSL_X509_STORE* store) +{ + WOLFSSL_ENTER("wolfSSL_X509_STORE_get0_objects"); + WOLFSSL_STUB("wolfSSL_X509_STORE_get0_objects"); + (void)store; + return NULL; +} + +WOLFSSL_X509_OBJECT* wolfSSL_sk_X509_OBJECT_delete( + WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* sk, int i) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_OBJECT_delete"); + WOLFSSL_STUB("wolfSSL_sk_X509_OBJECT_delete"); + (void)sk; + (void)i; + return NULL; +} + +void wolfSSL_X509_OBJECT_free(WOLFSSL_X509_OBJECT *a) +{ + WOLFSSL_ENTER("wolfSSL_X509_OBJECT_free"); + WOLFSSL_STUB("wolfSSL_X509_OBJECT_free"); + (void)a; +} + +#endif + + +#endif /* OPENSSL_ALL || (OPENSSL_EXTRA && (HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_LIGHTY)) */ + + +#if defined(OPENSSL_EXTRA) + +int wolfSSL_sk_X509_num(const WOLF_STACK_OF(WOLFSSL_X509) *s) +{ + WOLFSSL_ENTER("wolfSSL_sk_X509_num"); + + if (s == NULL) + return -1; + return (int)s->num; +} + +unsigned long wolfSSL_ERR_peek_last_error(void) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_NGINX) + { + int ret; + + if ((ret = wc_PeekErrorNode(-1, NULL, NULL, NULL)) < 0) { + WOLFSSL_MSG("Issue peeking at error node in queue"); + return 0; + } + if (ret == -ASN_NO_PEM_HEADER) + return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; + return (unsigned long)ret; + } +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif +} + +#endif /* OPENSSL_EXTRA */ + +WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_SSL_CTX"); + return ssl->ctx; +} + +#if defined(OPENSSL_ALL) || \ + defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + +const byte* wolfSSL_SESSION_get_id(WOLFSSL_SESSION* sess, unsigned int* idLen) +{ + WOLFSSL_ENTER("wolfSSL_SESSION_get_id"); + if(!sess || !idLen) { + WOLFSSL_MSG("Bad func args. Please provide idLen"); + return NULL; + } + *idLen = sess->sessionIDSz; + return sess->sessionID; +} + +#if (defined(HAVE_SESSION_TICKET) || defined(SESSION_CERTS)) && \ + !defined(NO_FILESYSTEM) + +#if defined(SESSION_CERTS) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) +/* returns a pointer to the protocol used by the session */ +static const char* wolfSSL_SESSION_get_protocol(const WOLFSSL_SESSION* in) +{ + return wolfSSL_internal_get_version((ProtocolVersion*)&in->version); +} +#endif + +/* returns true (non 0) if the session has EMS (extended master secret) */ +static int wolfSSL_SESSION_haveEMS(const WOLFSSL_SESSION* in) +{ + if (in == NULL) + return 0; + return in->haveEMS; +} + +#if defined(HAVE_SESSION_TICKET) +/* prints out the ticket to bio passed in + * return WOLFSSL_SUCCESS on success + */ +static int wolfSSL_SESSION_print_ticket(WOLFSSL_BIO* bio, + const WOLFSSL_SESSION* in, const char* tab) +{ + unsigned short i, j, z, sz; + short tag = 0; + byte* pt; + + + if (in == NULL || bio == NULL) { + return BAD_FUNC_ARG; + } + + sz = in->ticketLen; + pt = in->ticket; + + if (wolfSSL_BIO_printf(bio, "%s\n", (sz == 0)? " NONE": "") <= 0) + return WOLFSSL_FAILURE; + + for (i = 0; i < sz;) { + char asc[16]; + + if (sz - i < 16) { + if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag + (sz - i)) <= 0) + return WOLFSSL_FAILURE; + } + else { + if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag) <= 0) + return WOLFSSL_FAILURE; + } + for (j = 0; i < sz && j < 8; j++,i++) { + asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; + if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + } + + if (i < sz) { + asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; + if (wolfSSL_BIO_printf(bio, "-%02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + j++; + i++; + } + + for (; i < sz && j < 16; j++,i++) { + asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; + if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + } + + /* pad out spacing */ + for (z = j; z < 17; z++) { + if (wolfSSL_BIO_printf(bio, " ") <= 0) + return WOLFSSL_FAILURE; + } + + for (z = 0; z < j; z++) { + if (wolfSSL_BIO_printf(bio, "%c", asc[z]) <= 0) + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_printf(bio, "\n") <= 0) + return WOLFSSL_FAILURE; + + tag += 16; + } + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_SESSION_TICKET */ + + +/* prints out the session information in human readable form + * return WOLFSSL_SUCCESS on success + */ +int wolfSSL_SESSION_print(WOLFSSL_BIO *bp, const WOLFSSL_SESSION *x) +{ + const unsigned char* pt; + unsigned char buf[SECRET_LEN]; + unsigned int sz = 0, i; + int ret; + WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)x; + + if (session == NULL) { + WOLFSSL_MSG("Bad NULL argument"); + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_printf(bp, "%s\n", "SSL-Session:") <= 0) + return WOLFSSL_FAILURE; + +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + if (wolfSSL_BIO_printf(bp, " Protocol : %s\n", + wolfSSL_SESSION_get_protocol(session)) <= 0) + return WOLFSSL_FAILURE; +#endif + + if (wolfSSL_BIO_printf(bp, " Cipher : %s\n", + wolfSSL_SESSION_CIPHER_get_name(session)) <= 0) + return WOLFSSL_FAILURE; + + pt = wolfSSL_SESSION_get_id(session, &sz); + if (wolfSSL_BIO_printf(bp, " Session-ID: ") <= 0) + return WOLFSSL_FAILURE; + + for (i = 0; i < sz; i++) { + if (wolfSSL_BIO_printf(bp, "%02X", pt[i]) <= 0) + return WOLFSSL_FAILURE; + } + if (wolfSSL_BIO_printf(bp, "\n") <= 0) + return WOLFSSL_FAILURE; + + if (wolfSSL_BIO_printf(bp, " Session-ID-ctx: \n") <= 0) + return WOLFSSL_FAILURE; + + ret = wolfSSL_SESSION_get_master_key(x, buf, sizeof(buf)); + if (wolfSSL_BIO_printf(bp, " Master-Key: ") <= 0) + return WOLFSSL_FAILURE; + + if (ret > 0) { + sz = (unsigned int)ret; + for (i = 0; i < sz; i++) { + if (wolfSSL_BIO_printf(bp, "%02X", buf[i]) <= 0) + return WOLFSSL_FAILURE; + } + } + if (wolfSSL_BIO_printf(bp, "\n") <= 0) + return WOLFSSL_FAILURE; + + /* @TODO PSK identity hint and SRP */ + + if (wolfSSL_BIO_printf(bp, " TLS session ticket:") <= 0) + return WOLFSSL_FAILURE; + +#ifdef HAVE_SESSION_TICKET + if (wolfSSL_SESSION_print_ticket(bp, x, " ") != WOLFSSL_SUCCESS) + return WOLFSSL_FAILURE; +#endif + + if (wolfSSL_BIO_printf(bp, " Start Time: %ld\n", + wolfSSL_SESSION_get_time(x)) <= 0) + return WOLFSSL_FAILURE; + + if (wolfSSL_BIO_printf(bp, " Timeout : %ld (sec)\n", + wolfSSL_SESSION_get_timeout(x)) <= 0) + return WOLFSSL_FAILURE; + + /* @TODO verify return code print */ + + if (wolfSSL_BIO_printf(bp, " Extended master secret: %s\n", + (wolfSSL_SESSION_haveEMS(session) == 0)? "no" : "yes") <= 0) + return WOLFSSL_FAILURE; + + return WOLFSSL_SUCCESS; +} +#endif /* (HAVE_SESSION_TICKET || SESSION_CERTS) && !NO_FILESYSTEM */ + +#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL)) \ + || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) + +int wolfSSL_CTX_get_verify_mode(WOLFSSL_CTX* ctx) +{ + int mode = 0; + WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode"); + + if(!ctx) + return WOLFSSL_FATAL_ERROR; + + if (ctx->verifyPeer) + mode |= WOLFSSL_VERIFY_PEER; + else if (ctx->verifyNone) + mode |= WOLFSSL_VERIFY_NONE; + + if (ctx->failNoCert) + mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; + + if (ctx->failNoCertxPSK) + mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; + + WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode); + return mode; +} + +#endif +#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519) +/* return 1 if success, 0 if error + * output keys are little endian format + */ +int wolfSSL_EC25519_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) priv; + (void) privSz; + (void) pub; + (void) pubSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + int ret = WOLFSSL_FAILURE; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_EC25519_generate_key"); + + if (priv == NULL || privSz == NULL || *privSz < CURVE25519_KEYSIZE || + pub == NULL || pubSz == NULL || *pubSz < CURVE25519_KEYSIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FAILURE; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + curve25519_key key; + + if (wc_curve25519_init(&key) != MP_OKAY) + WOLFSSL_MSG("wc_curve25519_init failed"); + else if (wc_curve25519_make_key(rng, CURVE25519_KEYSIZE, &key)!=MP_OKAY) + WOLFSSL_MSG("wc_curve25519_make_key failed"); + /* export key pair */ + else if (wc_curve25519_export_key_raw_ex(&key, priv, privSz, pub, + pubSz, EC25519_LITTLE_ENDIAN) + != MP_OKAY) + WOLFSSL_MSG("wc_curve25519_export_key_raw_ex failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_curve25519_free(&key); + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* return 1 if success, 0 if error + * input and output keys are little endian format + */ +int wolfSSL_EC25519_shared_key(unsigned char *shared, unsigned int *sharedSz, + const unsigned char *priv, unsigned int privSz, + const unsigned char *pub, unsigned int pubSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) shared; + (void) sharedSz; + (void) priv; + (void) privSz; + (void) pub; + (void) pubSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + int ret = WOLFSSL_FAILURE; + curve25519_key privkey, pubkey; + + WOLFSSL_ENTER("wolfSSL_EC25519_shared_key"); + + if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE25519_KEYSIZE || + priv == NULL || privSz < CURVE25519_KEYSIZE || + pub == NULL || pubSz < CURVE25519_KEYSIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* import private key */ + if (wc_curve25519_init(&privkey) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_init privkey failed"); + return ret; + } + if (wc_curve25519_import_private_ex(priv, privSz, &privkey, + EC25519_LITTLE_ENDIAN) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_import_private_ex failed"); + wc_curve25519_free(&privkey); + return ret; + } + + /* import public key */ + if (wc_curve25519_init(&pubkey) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_init pubkey failed"); + wc_curve25519_free(&privkey); + return ret; + } + if (wc_curve25519_import_public_ex(pub, pubSz, &pubkey, + EC25519_LITTLE_ENDIAN) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_import_public_ex failed"); + wc_curve25519_free(&privkey); + wc_curve25519_free(&pubkey); + return ret; + } + + if (wc_curve25519_shared_secret_ex(&privkey, &pubkey, + shared, sharedSz, + EC25519_LITTLE_ENDIAN) != MP_OKAY) + WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_curve25519_free(&privkey); + wc_curve25519_free(&pubkey); + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} +#endif /* OPENSSL_EXTRA && HAVE_CURVE25519 */ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) +/* return 1 if success, 0 if error + * output keys are little endian format + */ +int wolfSSL_ED25519_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) priv; + (void) privSz; + (void) pub; + (void) pubSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + int ret = WOLFSSL_FAILURE; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_ED25519_generate_key"); + + if (priv == NULL || privSz == NULL || *privSz < ED25519_PRV_KEY_SIZE || + pub == NULL || pubSz == NULL || *pubSz < ED25519_PUB_KEY_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FATAL_ERROR; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + ed25519_key key; + + if (wc_ed25519_init(&key) != MP_OKAY) + WOLFSSL_MSG("wc_ed25519_init failed"); + else if (wc_ed25519_make_key(rng, ED25519_KEY_SIZE, &key)!=MP_OKAY) + WOLFSSL_MSG("wc_ed25519_make_key failed"); + /* export private key */ + else if (wc_ed25519_export_key(&key, priv, privSz, pub, pubSz)!=MP_OKAY) + WOLFSSL_MSG("wc_ed25519_export_key failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_ed25519_free(&key); + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* return 1 if success, 0 if error + * input and output keys are little endian format + * priv is a buffer containing private and public part of key + */ +int wolfSSL_ED25519_sign(const unsigned char *msg, unsigned int msgSz, + const unsigned char *priv, unsigned int privSz, + unsigned char *sig, unsigned int *sigSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) msg; + (void) msgSz; + (void) priv; + (void) privSz; + (void) sig; + (void) sigSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + ed25519_key key; + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_ED25519_sign"); + + if (priv == NULL || privSz != ED25519_PRV_KEY_SIZE || + msg == NULL || sig == NULL || *sigSz < ED25519_SIG_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* import key */ + if (wc_ed25519_init(&key) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_init failed"); + return ret; + } + if (wc_ed25519_import_private_key(priv, privSz/2, + priv+(privSz/2), ED25519_PUB_KEY_SIZE, + &key) != MP_OKAY){ + WOLFSSL_MSG("wc_ed25519_import_private failed"); + wc_ed25519_free(&key); + return ret; + } + + if (wc_ed25519_sign_msg(msg, msgSz, sig, sigSz, &key) != MP_OKAY) + WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_ed25519_free(&key); + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* return 1 if success, 0 if error + * input and output keys are little endian format + * pub is a buffer containing public part of key + */ +int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, + const unsigned char *pub, unsigned int pubSz, + const unsigned char *sig, unsigned int sigSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) msg; + (void) msgSz; + (void) pub; + (void) pubSz; + (void) sig; + (void) sigSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + ed25519_key key; + int ret = WOLFSSL_FAILURE, check = 0; + + WOLFSSL_ENTER("wolfSSL_ED25519_verify"); + + if (pub == NULL || pubSz != ED25519_PUB_KEY_SIZE || + msg == NULL || sig == NULL || sigSz != ED25519_SIG_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* import key */ + if (wc_ed25519_init(&key) != MP_OKAY) { + WOLFSSL_MSG("wc_curve25519_init failed"); + return ret; + } + if (wc_ed25519_import_public(pub, pubSz, &key) != MP_OKAY){ + WOLFSSL_MSG("wc_ed25519_import_public failed"); + wc_ed25519_free(&key); + return ret; + } + + if ((ret = wc_ed25519_verify_msg((byte*)sig, sigSz, msg, msgSz, + &check, &key)) != MP_OKAY) { + WOLFSSL_MSG("wc_ed25519_verify_msg failed"); + } + else if (!check) + WOLFSSL_MSG("wc_ed25519_verify_msg failed (signature invalid)"); + else + ret = WOLFSSL_SUCCESS; + + wc_ed25519_free(&key); + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +#endif /* OPENSSL_EXTRA && HAVE_ED25519 */ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE448) +/* return 1 if success, 0 if error + * output keys are little endian format + */ +int wolfSSL_EC448_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) priv; + (void) privSz; + (void) pub; + (void) pubSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + int ret = WOLFSSL_FAILURE; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_EC448_generate_key"); + + if (priv == NULL || privSz == NULL || *privSz < CURVE448_KEY_SIZE || + pub == NULL || pubSz == NULL || *pubSz < CURVE448_KEY_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FAILURE; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + curve448_key key; + + if (wc_curve448_init(&key) != MP_OKAY) + WOLFSSL_MSG("wc_curve448_init failed"); + else if (wc_curve448_make_key(rng, CURVE448_KEY_SIZE, &key)!=MP_OKAY) + WOLFSSL_MSG("wc_curve448_make_key failed"); + /* export key pair */ + else if (wc_curve448_export_key_raw_ex(&key, priv, privSz, pub, pubSz, + EC448_LITTLE_ENDIAN) + != MP_OKAY) + WOLFSSL_MSG("wc_curve448_export_key_raw_ex failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_curve448_free(&key); + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* return 1 if success, 0 if error + * input and output keys are little endian format + */ +int wolfSSL_EC448_shared_key(unsigned char *shared, unsigned int *sharedSz, + const unsigned char *priv, unsigned int privSz, + const unsigned char *pub, unsigned int pubSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) shared; + (void) sharedSz; + (void) priv; + (void) privSz; + (void) pub; + (void) pubSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + int ret = WOLFSSL_FAILURE; + curve448_key privkey, pubkey; + + WOLFSSL_ENTER("wolfSSL_EC448_shared_key"); + + if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE448_KEY_SIZE || + priv == NULL || privSz < CURVE448_KEY_SIZE || + pub == NULL || pubSz < CURVE448_KEY_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* import private key */ + if (wc_curve448_init(&privkey) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_init privkey failed"); + return ret; + } + if (wc_curve448_import_private_ex(priv, privSz, &privkey, + EC448_LITTLE_ENDIAN) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_import_private_ex failed"); + wc_curve448_free(&privkey); + return ret; + } + + /* import public key */ + if (wc_curve448_init(&pubkey) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_init pubkey failed"); + wc_curve448_free(&privkey); + return ret; + } + if (wc_curve448_import_public_ex(pub, pubSz, &pubkey, + EC448_LITTLE_ENDIAN) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_import_public_ex failed"); + wc_curve448_free(&privkey); + wc_curve448_free(&pubkey); + return ret; + } + + if (wc_curve448_shared_secret_ex(&privkey, &pubkey, shared, sharedSz, + EC448_LITTLE_ENDIAN) != MP_OKAY) + WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_curve448_free(&privkey); + wc_curve448_free(&pubkey); + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} +#endif /* OPENSSL_EXTRA && HAVE_CURVE448 */ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) +/* return 1 if success, 0 if error + * output keys are little endian format + */ +int wolfSSL_ED448_generate_key(unsigned char *priv, unsigned int *privSz, + unsigned char *pub, unsigned int *pubSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) priv; + (void) privSz; + (void) pub; + (void) pubSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + int ret = WOLFSSL_FAILURE; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG *tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + + WOLFSSL_ENTER("wolfSSL_ED448_generate_key"); + + if (priv == NULL || privSz == NULL || *privSz < ED448_PRV_KEY_SIZE || + pub == NULL || pubSz == NULL || *pubSz < ED448_PUB_KEY_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FATAL_ERROR; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) + WOLFSSL_MSG("Global RNG no Init"); + else + rng = &globalRNG; + } + + if (rng) { + ed448_key key; + + if (wc_ed448_init(&key) != MP_OKAY) + WOLFSSL_MSG("wc_ed448_init failed"); + else if (wc_ed448_make_key(rng, ED448_KEY_SIZE, &key) != MP_OKAY) + WOLFSSL_MSG("wc_ed448_make_key failed"); + /* export private key */ + else if (wc_ed448_export_key(&key, priv, privSz, pub, pubSz) != MP_OKAY) + WOLFSSL_MSG("wc_ed448_export_key failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_ed448_free(&key); + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* return 1 if success, 0 if error + * input and output keys are little endian format + * priv is a buffer containing private and public part of key + */ +int wolfSSL_ED448_sign(const unsigned char *msg, unsigned int msgSz, + const unsigned char *priv, unsigned int privSz, + unsigned char *sig, unsigned int *sigSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) msg; + (void) msgSz; + (void) priv; + (void) privSz; + (void) sig; + (void) sigSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + ed448_key key; + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_ED448_sign"); + + if (priv == NULL || privSz != ED448_PRV_KEY_SIZE || msg == NULL || + sig == NULL || *sigSz < ED448_SIG_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* import key */ + if (wc_ed448_init(&key) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_init failed"); + return ret; + } + if (wc_ed448_import_private_key(priv, privSz/2, priv+(privSz/2), + ED448_PUB_KEY_SIZE, &key) != MP_OKAY){ + WOLFSSL_MSG("wc_ed448_import_private failed"); + wc_ed448_free(&key); + return ret; + } + + if (wc_ed448_sign_msg(msg, msgSz, sig, sigSz, &key) != MP_OKAY) + WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); + else + ret = WOLFSSL_SUCCESS; + + wc_ed448_free(&key); + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +/* return 1 if success, 0 if error + * input and output keys are little endian format + * pub is a buffer containing public part of key + */ +int wolfSSL_ED448_verify(const unsigned char *msg, unsigned int msgSz, + const unsigned char *pub, unsigned int pubSz, + const unsigned char *sig, unsigned int sigSz) +{ +#ifndef WOLFSSL_KEY_GEN + WOLFSSL_MSG("No Key Gen built in"); + (void) msg; + (void) msgSz; + (void) pub; + (void) pubSz; + (void) sig; + (void) sigSz; + return WOLFSSL_FAILURE; +#else /* WOLFSSL_KEY_GEN */ + ed448_key key; + int ret = WOLFSSL_FAILURE, check = 0; + + WOLFSSL_ENTER("wolfSSL_ED448_verify"); + + if (pub == NULL || pubSz != ED448_PUB_KEY_SIZE || msg == NULL || + sig == NULL || sigSz != ED448_SIG_SIZE) { + WOLFSSL_MSG("Bad arguments"); + return WOLFSSL_FAILURE; + } + + /* import key */ + if (wc_ed448_init(&key) != MP_OKAY) { + WOLFSSL_MSG("wc_curve448_init failed"); + return ret; + } + if (wc_ed448_import_public(pub, pubSz, &key) != MP_OKAY){ + WOLFSSL_MSG("wc_ed448_import_public failed"); + wc_ed448_free(&key); + return ret; + } + + if ((ret = wc_ed448_verify_msg((byte*)sig, sigSz, msg, msgSz, &check, + &key)) != MP_OKAY) { + WOLFSSL_MSG("wc_ed448_verify_msg failed"); + } + else if (!check) + WOLFSSL_MSG("wc_ed448_verify_msg failed (signature invalid)"); + else + ret = WOLFSSL_SUCCESS; + + wc_ed448_free(&key); + + return ret; +#endif /* WOLFSSL_KEY_GEN */ +} + +#endif /* OPENSSL_EXTRA && HAVE_ED448 */ + +#ifdef WOLFSSL_JNI + +int wolfSSL_set_jobject(WOLFSSL* ssl, void* objPtr) +{ + WOLFSSL_ENTER("wolfSSL_set_jobject"); + if (ssl != NULL) + { + ssl->jObjectRef = objPtr; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} + +void* wolfSSL_get_jobject(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_jobject"); + if (ssl != NULL) + return ssl->jObjectRef; + return NULL; +} + +#endif /* WOLFSSL_JNI */ + + +#ifdef WOLFSSL_ASYNC_CRYPT +int wolfSSL_CTX_AsyncPoll(WOLFSSL_CTX* ctx, WOLF_EVENT** events, int maxEvents, + WOLF_EVENT_FLAG flags, int* eventCount) +{ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + return wolfAsync_EventQueuePoll(&ctx->event_queue, NULL, + events, maxEvents, flags, eventCount); +} + +int wolfSSL_AsyncPoll(WOLFSSL* ssl, WOLF_EVENT_FLAG flags) +{ + int ret, eventCount = 0; + WOLF_EVENT* events[1]; + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ret = wolfAsync_EventQueuePoll(&ssl->ctx->event_queue, ssl, + events, sizeof(events)/sizeof(*events), flags, &eventCount); + if (ret == 0) { + ret = eventCount; + } + + return ret; +} +#endif /* WOLFSSL_ASYNC_CRYPT */ + +#ifdef OPENSSL_EXTRA +unsigned long wolfSSL_ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_error_line_data"); + + (void)line; + (void)file; + + /* No data or flags stored - error display only in Nginx. */ + if (data != NULL) { + *data = ""; + } + if (flags != NULL) { + *flags = 0; + } + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_OPENSSH) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) + { + int ret = 0; + + while (1) { + if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) { + WOLFSSL_MSG("Issue peeking at error node in queue"); + return 0; + } + /* OpenSSL uses positive error codes */ + if (ret < 0) { + ret = -ret; + } + + if (ret == -ASN_NO_PEM_HEADER) + return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; + if (ret != WANT_READ && ret != WANT_WRITE && + ret != ZERO_RETURN && ret != WOLFSSL_ERROR_ZERO_RETURN && + ret != SOCKET_PEER_CLOSED_E && ret != SOCKET_ERROR_E) + break; + + wc_RemoveErrorNode(-1); + } + + return (unsigned long)ret; + } +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif +} +#endif + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + +/* returns a pointer to internal cipher suite list. Should not be free'd by + * caller. + */ +WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl) +{ + WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL; + Suites* suites; + + WOLFSSL_ENTER("wolfSSL_get_ciphers_compat"); + if (ssl == NULL || (ssl->suites == NULL && ssl->ctx->suites == NULL)) { + return NULL; + } + + if (ssl->suites != NULL) { + suites = ssl->suites; + } + else { + suites = ssl->ctx->suites; + } + + /* check if stack needs populated */ + if (suites->stack == NULL) { + int i; + for (i = 0; i < suites->suiteSz; i+=2) { + WOLFSSL_STACK* add = wolfSSL_sk_new_node(ssl->heap); + if (add != NULL) { + add->type = STACK_TYPE_CIPHER; + add->data.cipher.cipherSuite0 = suites->suites[i]; + add->data.cipher.cipherSuite = suites->suites[i+1]; + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + /* in_stack is checked in wolfSSL_CIPHER_description */ + add->data.cipher.in_stack = 1; + #endif + + add->next = ret; + if (ret != NULL) { + add->num = ret->num + 1; + } + else { + add->num = 1; + } + ret = add; + } + } + suites->stack = ret; + } + return suites->stack; +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_OPENSSL_config(char *config_name) +{ + (void)config_name; + WOLFSSL_STUB("OPENSSL_config"); +} +#endif /* !NO_WOLFSSL_STUB */ +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) +int wolfSSL_X509_get_ex_new_index(int idx, void *arg, void *a, void *b, void *c) +{ + static int x509_idx = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_ex_new_index"); + (void)idx; + (void)arg; + (void)a; + (void)b; + (void)c; + + return x509_idx++; +} + +#if defined(HAVE_EX_DATA) || defined(FORTRESS) +void* wolfSSL_CRYPTO_get_ex_data(const WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data"); +#ifdef MAX_EX_DATA + if(ex_data && idx < MAX_EX_DATA && idx >= 0) { + return ex_data->ex_data[idx]; + } +#else + (void)ex_data; + (void)idx; +#endif + return NULL; +} + +int wolfSSL_CRYPTO_set_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data"); +#ifdef MAX_EX_DATA + if (ex_data && idx < MAX_EX_DATA && idx >= 0) { + ex_data->ex_data[idx] = data; + return WOLFSSL_SUCCESS; + } +#else + (void)ex_data; + (void)idx; + (void)data; +#endif + return WOLFSSL_FAILURE; +} +#endif /* defined(HAVE_EX_DATA) || defined(FORTRESS) */ + +void *wolfSSL_X509_get_ex_data(X509 *x509, int idx) +{ + WOLFSSL_ENTER("wolfSSL_X509_get_ex_data"); + #ifdef HAVE_EX_DATA + if (x509 != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&x509->ex_data, idx); + } + #else + (void)x509; + (void)idx; + #endif + return NULL; +} + +int wolfSSL_X509_set_ex_data(X509 *x509, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_X509_set_ex_data"); + #ifdef HAVE_EX_DATA + if (x509 != NULL) + { + return wolfSSL_CRYPTO_set_ex_data(&x509->ex_data, idx, data); + } + #else + (void)x509; + (void)idx; + (void)data; + #endif + return WOLFSSL_FAILURE; +} + +int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *name, + const WOLFSSL_EVP_MD *type, unsigned char *md, unsigned int *len) +{ + WOLFSSL_ENTER("wolfSSL_X509_NAME_digest"); + + if (name == NULL || type == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_FILESYSTEM) && !defined(NO_PWDBASED) + return wolfSSL_EVP_Digest((unsigned char*)name->fullName.fullName, + name->fullName.fullNameLen, md, len, type, NULL); +#else + (void)md; + (void)len; + return NOT_COMPILED_IN; +#endif +} + +long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx) +{ + WOLFSSL_ENTER("wolfSSL_SSL_CTX_get_timeout"); + + if (ctx == NULL) + return 0; + + return ctx->timeout; +} + + +/* returns the time in seconds of the current timeout */ +long wolfSSL_get_timeout(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_timeout"); + + if (ssl == NULL) + return 0; + return ssl->timeout; +} + +#ifdef HAVE_ECC +int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) +{ + WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_tmp_ecdh"); + + if (ctx == NULL || ecdh == NULL) + return BAD_FUNC_ARG; + + ctx->ecdhCurveOID = ecdh->group->curve_oid; + + return WOLFSSL_SUCCESS; +} +#endif + +/* Assumes that the session passed in is from the cache. */ +int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s) +{ + WOLFSSL_ENTER("wolfSSL_SSL_CTX_remove_session"); + + if (ctx == NULL || s == NULL) + return BAD_FUNC_ARG; + +#ifdef HAVE_EXT_CACHE + if (!ctx->internalCacheOff) +#endif + { + /* Don't remove session just timeout session. */ + s->timeout = 0; + } + +#ifdef HAVE_EXT_CACHE + if (ctx->rem_sess_cb != NULL) + ctx->rem_sess_cb(ctx, s); +#endif + + return 0; +} + +BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get_rbio"); + /* Nginx sets the buffer size if the read BIO is different to write BIO. + * The setting buffer size doesn't do anything so return NULL for both. + */ + if (s == NULL) + return NULL; + + return s->biord; +} +BIO *wolfSSL_SSL_get_wbio(const WOLFSSL *s) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get_wbio"); + (void)s; + /* Nginx sets the buffer size if the read BIO is different to write BIO. + * The setting buffer size doesn't do anything so return NULL for both. + */ + if (s == NULL) + return NULL; + + return s->biowr; +} + +int wolfSSL_SSL_do_handshake(WOLFSSL *s) +{ + WOLFSSL_ENTER("wolfSSL_SSL_do_handshake"); + + if (s == NULL) + return WOLFSSL_FAILURE; + + if (s->options.side == WOLFSSL_CLIENT_END) { + #ifndef NO_WOLFSSL_CLIENT + return wolfSSL_connect(s); + #else + WOLFSSL_MSG("Client not compiled in"); + return WOLFSSL_FAILURE; + #endif + } + +#ifndef NO_WOLFSSL_SERVER + return wolfSSL_accept(s); +#else + WOLFSSL_MSG("Server not compiled in"); + return WOLFSSL_FAILURE; +#endif +} + +int wolfSSL_SSL_in_init(WOLFSSL *ssl) +{ + WOLFSSL_ENTER("SSL_in_init"); + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + return ssl->options.connectState < SECOND_REPLY_DONE; + } + return ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; +} + +int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("SSL_connect_init"); + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + return ssl->options.connectState > CONNECT_BEGIN && + ssl->options.connectState < SECOND_REPLY_DONE; + } + + return ssl->options.acceptState > ACCEPT_BEGIN && + ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; +} + +#ifndef NO_SESSION_CACHE + +WOLFSSL_SESSION *wolfSSL_SSL_get0_session(const WOLFSSL *ssl) +{ + WOLFSSL_SESSION *session; + + WOLFSSL_ENTER("wolfSSL_SSL_get0_session"); + + if (ssl == NULL) { + return NULL; + } + + session = wolfSSL_get_session((WOLFSSL*)ssl); + +#ifdef HAVE_EXT_CACHE + ((WOLFSSL*)ssl)->extSession = session; +#endif + + return session; +} + +#endif /* NO_SESSION_CACHE */ + +int wolfSSL_X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername) +{ + int ret; + DecodedCert dCert; + + WOLFSSL_ENTER("wolfSSL_X509_check_host"); + + /* flags and peername not needed for Nginx. */ + (void)flags; + (void)peername; + + if (flags == WOLFSSL_NO_WILDCARDS) { + WOLFSSL_MSG("X509_CHECK_FLAG_NO_WILDCARDS not yet implemented"); + return WOLFSSL_FAILURE; + } + + InitDecodedCert(&dCert, x->derCert->buffer, x->derCert->length, NULL); + ret = ParseCertRelative(&dCert, CERT_TYPE, 0, NULL); + if (ret != 0) { + FreeDecodedCert(&dCert); + return WOLFSSL_FAILURE; + } + + ret = CheckHostName(&dCert, (char *)chk, chklen); + FreeDecodedCert(&dCert); + if (ret != 0) + return WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; +} + +int wolfSSL_i2a_ASN1_INTEGER(BIO *bp, const WOLFSSL_ASN1_INTEGER *a) +{ + static char num[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + int i; + word32 j; + word32 len = 0; + + WOLFSSL_ENTER("wolfSSL_i2a_ASN1_INTEGER"); + + if (bp == NULL || a == NULL) + return WOLFSSL_FAILURE; + + /* Skip ASN.1 INTEGER (type) byte. */ + i = 1; + /* When indefinite length, can't determine length with data available. */ + if (a->data[i] == 0x80) + return 0; + /* One length byte if less than 0x80. */ + if (a->data[i] < 0x80) + len = a->data[i++]; + /* Multiple length byte if greater than 0x80. */ + else if (a->data[i] > 0x80) { + switch (a->data[i++] - 0x80) { + case 4: + len |= a->data[i++] << 24; + FALL_THROUGH; + case 3: + len |= a->data[i++] << 16; + FALL_THROUGH; + case 2: + len |= a->data[i++] << 8; + FALL_THROUGH; + case 1: + len |= a->data[i++]; + break; + default: + /* Not supporting greater than 4 bytes of length. */ + return 0; + } + } + + /* Zero length integer is the value zero. */ + if (len == 0) { + wolfSSL_BIO_write(bp, "00", 2); + return 2; + } + + /* Don't do negative - just write out every byte. */ + for (j = 0; j < len; i++,j++) { + wolfSSL_BIO_write(bp, &num[a->data[i] >> 4], 1); + wolfSSL_BIO_write(bp, &num[a->data[i] & 0xf], 1); + } + + /* Two nibbles written for each byte. */ + return len * 2; +} + + +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) +/* Expected return values from implementations of OpenSSL ticket key callback. + */ +#define TICKET_KEY_CB_RET_FAILURE -1 +#define TICKET_KEY_CB_RET_NOT_FOUND 0 +#define TICKET_KEY_CB_RET_OK 1 +#define TICKET_KEY_CB_RET_RENEW 2 + +/* The ticket key callback as used in OpenSSL is stored here. */ +static int (*ticketKeyCb)(WOLFSSL *ssl, unsigned char *name, unsigned char *iv, + WOLFSSL_EVP_CIPHER_CTX *ectx, WOLFSSL_HMAC_CTX *hctx, int enc) = NULL; + +/* Implementation of session ticket encryption/decryption using OpenSSL + * callback to initialize the cipher and HMAC. + * + * ssl The SSL/TLS object. + * keyName The key name - used to identify the key to be used. + * iv The IV to use. + * mac The MAC of the encrypted data. + * enc Encrypt ticket. + * encTicket The ticket data. + * encTicketLen The length of the ticket data. + * encLen The encrypted/decrypted ticket length - output length. + * ctx Ignored. Application specific data. + * returns WOLFSSL_TICKET_RET_OK to indicate success, + * WOLFSSL_TICKET_RET_CREATE if a new ticket is required and + * WOLFSSL_TICKET_RET_FATAL on error. + */ +static int wolfSSL_TicketKeyCb(WOLFSSL* ssl, + unsigned char keyName[WOLFSSL_TICKET_NAME_SZ], + unsigned char iv[WOLFSSL_TICKET_IV_SZ], + unsigned char mac[WOLFSSL_TICKET_MAC_SZ], + int enc, unsigned char* encTicket, + int encTicketLen, int* encLen, void* ctx) +{ + byte digest[WC_MAX_DIGEST_SIZE]; + WOLFSSL_EVP_CIPHER_CTX evpCtx; + WOLFSSL_HMAC_CTX hmacCtx; + unsigned int mdSz = 0; + int len = 0; + int ret = WOLFSSL_TICKET_RET_FATAL; + int res; + + (void)ctx; + + if (ticketKeyCb == NULL) + return WOLFSSL_TICKET_RET_FATAL; + + wolfSSL_EVP_CIPHER_CTX_init(&evpCtx); + /* Initialize the cipher and HMAC. */ + res = ticketKeyCb(ssl, keyName, iv, &evpCtx, &hmacCtx, enc); + if (res != TICKET_KEY_CB_RET_OK && res != TICKET_KEY_CB_RET_RENEW) + return WOLFSSL_TICKET_RET_FATAL; + + if (enc) + { + /* Encrypt in place. */ + if (!wolfSSL_EVP_CipherUpdate(&evpCtx, encTicket, &len, + encTicket, encTicketLen)) + goto end; + encTicketLen = len; + if (!wolfSSL_EVP_EncryptFinal(&evpCtx, &encTicket[encTicketLen], &len)) + goto end; + /* Total length of encrypted data. */ + encTicketLen += len; + *encLen = encTicketLen; + + /* HMAC the encrypted data into the parameter 'mac'. */ + if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen)) + goto end; +#ifdef WOLFSSL_SHA512 + /* Check for SHA512, which would overrun the mac buffer */ + if (hmacCtx.hmac.macType == WC_SHA512) + goto end; +#endif + if (!wolfSSL_HMAC_Final(&hmacCtx, mac, &mdSz)) + goto end; + } + else + { + /* HMAC the encrypted data and compare it to the passed in data. */ + if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen)) + goto end; + if (!wolfSSL_HMAC_Final(&hmacCtx, digest, &mdSz)) + goto end; + if (XMEMCMP(mac, digest, mdSz) != 0) + goto end; + + /* Decrypt the ticket data in place. */ + if (!wolfSSL_EVP_CipherUpdate(&evpCtx, encTicket, &len, + encTicket, encTicketLen)) + goto end; + encTicketLen = len; + if (!wolfSSL_EVP_DecryptFinal(&evpCtx, &encTicket[encTicketLen], &len)) + goto end; + /* Total length of decrypted data. */ + *encLen = encTicketLen + len; + } + + ret = (res == TICKET_KEY_CB_RET_RENEW) ? WOLFSSL_TICKET_RET_CREATE : + WOLFSSL_TICKET_RET_OK; +end: + return ret; +} + +/* Set the callback to use when encrypting/decrypting tickets. + * + * ctx The SSL/TLS context object. + * cb The OpenSSL session ticket callback. + * returns WOLFSSL_SUCCESS to indicate success. + */ +int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, int (*cb)( + WOLFSSL *ssl, unsigned char *name, unsigned char *iv, + WOLFSSL_EVP_CIPHER_CTX *ectx, WOLFSSL_HMAC_CTX *hctx, int enc)) +{ + /* Store callback in a global. */ + ticketKeyCb = cb; + /* Set the ticket encryption callback to be a wrapper around OpenSSL + * callback. + */ + ctx->ticketEncCb = wolfSSL_TicketKeyCb; + + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_SESSION_TICKET */ + +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA || HAVE_LIGHTY */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) +#ifdef HAVE_OCSP +/* Not an OpenSSL API. */ +int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response) +{ + *response = ssl->ocspResp; + return ssl->ocspRespSz; +} + +/* Not an OpenSSL API. */ +char* wolfSSL_get_ocsp_url(WOLFSSL* ssl) +{ + return ssl->url; +} + +/* Not an OpenSSL API. */ +int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url) +{ + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->url = url; + return WOLFSSL_SUCCESS; +} +#endif /* OCSP */ +#endif /* OPENSSL_ALL / WOLFSSL_NGINX / WOLFSSL_HAPROXY */ + +#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) +int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, WOLF_STACK_OF(X509)** chain) +{ + word32 idx; + word32 length; + WOLFSSL_STACK* node; + WOLFSSL_STACK* last = NULL; + + if (ctx == NULL || chain == NULL) { + chain = NULL; + return WOLFSSL_FAILURE; + } + if (ctx->x509Chain != NULL) { + *chain = ctx->x509Chain; + return WOLFSSL_SUCCESS; + } + + /* If there are no chains then success! */ + *chain = NULL; + if (ctx->certChain == NULL || ctx->certChain->length == 0) { + return WOLFSSL_SUCCESS; + } + + /* Create a new stack of WOLFSSL_X509 object from chain buffer. */ + for (idx = 0; idx < ctx->certChain->length; ) { + node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_OPENSSL); + if (node == NULL) + return WOLFSSL_FAILURE; + node->next = NULL; + + /* 3 byte length | X509 DER data */ + ato24(ctx->certChain->buffer + idx, &length); + idx += 3; + + /* Create a new X509 from DER encoded data. */ + node->data.x509 = wolfSSL_X509_d2i(NULL, ctx->certChain->buffer + idx, + length); + if (node->data.x509 == NULL) { + XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); + /* Return as much of the chain as we created. */ + ctx->x509Chain = *chain; + return WOLFSSL_FAILURE; + } + idx += length; + + /* Add object to the end of the stack. */ + if (last == NULL) { + node->num = 1; + *chain = node; + } + else { + (*chain)->num++; + last->next = node; + } + + last = node; + } + + ctx->x509Chain = *chain; + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_CTX_set_tlsext_status_cb(WOLFSSL_CTX* ctx, + int(*cb)(WOLFSSL*, void*)) +{ + if (ctx == NULL || ctx->cm == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + /* Ensure stapling is on for callback to be used. */ + wolfSSL_CTX_EnableOCSPStapling(ctx); + + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + ctx->cm->ocsp_stapling->statusCb = cb; +#else + (void)cb; +#endif + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, + WOLFSSL_X509_STORE_CTX *ctx, WOLFSSL_X509 *x) +{ + WOLFSSL_STACK* node; + Signer* ca = NULL; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; +#else + DecodedCert cert[1]; +#endif + + if (issuer == NULL || ctx == NULL || x == NULL) + return WOLFSSL_FATAL_ERROR; + + if (ctx->chain != NULL) { + for (node = ctx->chain; node != NULL; node = node->next) { + if (wolfSSL_X509_check_issued(node->data.x509, x) == X509_V_OK) { + *issuer = x; + return WOLFSSL_SUCCESS; + } + } + } + + +#ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + if (cert == NULL) + return WOLFSSL_FAILURE; +#endif + + /* Use existing CA retrieval APIs that use DecodedCert. */ + InitDecodedCert(cert, x->derCert->buffer, x->derCert->length, NULL); + if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) { + #ifndef NO_SKID + if (cert->extAuthKeyIdSet) + ca = GetCA(ctx->store->cm, cert->extAuthKeyId); + if (ca == NULL) + ca = GetCAByName(ctx->store->cm, cert->issuerHash); + #else /* NO_SKID */ + ca = GetCA(ctx->store->cm, cert->issuerHash); + #endif /* NO SKID */ + } + FreeDecodedCert(cert); +#ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); +#endif + + if (ca == NULL) + return WOLFSSL_FAILURE; + +#ifdef WOLFSSL_SIGNER_DER_CERT + /* populate issuer with Signer DER */ + *issuer = wolfSSL_X509_d2i(issuer, ca->derCert->buffer, + ca->derCert->length); + if (*issuer == NULL) + return WOLFSSL_FAILURE; +#else + /* Create an empty certificate as CA doesn't have a certificate. */ + *issuer = (WOLFSSL_X509 *)XMALLOC(sizeof(WOLFSSL_X509), 0, + DYNAMIC_TYPE_OPENSSL); + if (*issuer == NULL) + return WOLFSSL_FAILURE; + + InitX509((*issuer), 1, NULL); +#endif + + /* Result is ignored when passed to wolfSSL_OCSP_cert_to_id(). */ + + return WOLFSSL_SUCCESS; +} + +void wolfSSL_X509_email_free(WOLF_STACK_OF(WOLFSSL_STRING) *sk) +{ + WOLFSSL_STACK *curr; + + while (sk != NULL) { + curr = sk; + sk = sk->next; + + XFREE(curr, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ocsp(WOLFSSL_X509 *x) +{ + WOLFSSL_STACK* list = NULL; + char* url; + + if (x->authInfoSz == 0) + return NULL; + + list = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK) + x->authInfoSz + 1, + NULL, DYNAMIC_TYPE_OPENSSL); + if (list == NULL) + return NULL; + + url = (char*)list; + url += sizeof(WOLFSSL_STACK); + XMEMCPY(url, x->authInfo, x->authInfoSz); + url[x->authInfoSz] = '\0'; + + list->data.string = url; + list->next = NULL; + + return list; +} + +int wolfSSL_X509_check_issued(WOLFSSL_X509 *issuer, WOLFSSL_X509 *subject) +{ + WOLFSSL_X509_NAME *issuerName = wolfSSL_X509_get_issuer_name(subject); + WOLFSSL_X509_NAME *subjectName = wolfSSL_X509_get_subject_name(issuer); + + if (issuerName == NULL || subjectName == NULL) + return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; + + /* Literal matching of encoded names and key ids. */ + if (issuerName->sz != subjectName->sz || + XMEMCMP(issuerName->name, subjectName->name, subjectName->sz) != 0) { + return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; + } + + if (subject->authKeyId != NULL && issuer->subjKeyId != NULL) { + if (subject->authKeyIdSz != issuer->subjKeyIdSz || + XMEMCMP(subject->authKeyId, issuer->subjKeyId, + issuer->subjKeyIdSz) != 0) { + return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; + } + } + + return X509_V_OK; +} + +WOLFSSL_X509* wolfSSL_X509_dup(WOLFSSL_X509 *x) +{ + return wolfSSL_X509_d2i(NULL, x->derCert->buffer, x->derCert->length); +} + +char* wolfSSL_sk_WOLFSSL_STRING_value(WOLF_STACK_OF(WOLFSSL_STRING)* strings, + int idx) +{ + for (; idx > 0 && strings != NULL; idx--) + strings = strings->next; + if (strings == NULL) + return NULL; + return strings->data.string; +} +#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) +#ifdef HAVE_ALPN +void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data, + unsigned int *len) +{ + word16 nameLen; + + if (ssl != NULL && data != NULL && len != NULL) { + TLSX_ALPN_GetRequest(ssl->extensions, (void **)data, &nameLen); + *len = nameLen; + } +} + +int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, + const unsigned char *in, unsigned int inLen, + const unsigned char *clientNames, + unsigned int clientLen) +{ + unsigned int i, j; + byte lenIn, lenClient; + + if (out == NULL || outLen == NULL || in == NULL || clientNames == NULL) + return OPENSSL_NPN_UNSUPPORTED; + + for (i = 0; i < inLen; i += lenIn) { + lenIn = in[i++]; + for (j = 0; j < clientLen; j += lenClient) { + lenClient = clientNames[j++]; + + if (lenIn != lenClient) + continue; + + if (XMEMCMP(in + i, clientNames + j, lenIn) == 0) { + *out = (unsigned char *)(in + i); + *outLen = lenIn; + return OPENSSL_NPN_NEGOTIATED; + } + } + } + + *out = (unsigned char *)clientNames + 1; + *outLen = clientNames[0]; + return OPENSSL_NPN_NO_OVERLAP; +} + +void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, + int (*cb) (WOLFSSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg) +{ + if (ctx != NULL) { + ctx->alpnSelect = cb; + ctx->alpnSelectArg = arg; + } +} + +void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s, + int (*cb) (WOLFSSL *ssl, + const unsigned char + **out, + unsigned int *outlen, + void *arg), void *arg) +{ + (void)s; + (void)cb; + (void)arg; + WOLFSSL_STUB("wolfSSL_CTX_set_next_protos_advertised_cb"); +} + +void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, + int (*cb) (WOLFSSL *ssl, + unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg) +{ + (void)s; + (void)cb; + (void)arg; + WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); +} + +void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, const unsigned char **data, + unsigned *len) +{ + (void)s; + (void)data; + (void)len; + WOLFSSL_STUB("wolfSSL_get0_next_proto_negotiated"); +} +#endif /* HAVE_ALPN */ + +#endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */ + +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names) +{ + int idx, start = 0, len; + word16 curve; + char name[MAX_CURVE_NAME_SZ]; + + /* Disable all curves so that only the ones the user wants are enabled. */ + ctx->disabledCurves = 0xFFFFFFFFUL; + for (idx = 1; names[idx-1] != '\0'; idx++) { + if (names[idx] != ':' && names[idx] != '\0') + continue; + + len = idx - 1 - start; + if (len > MAX_CURVE_NAME_SZ - 1) + return WOLFSSL_FAILURE; + + XMEMCPY(name, names + start, len); + name[len] = 0; + + if ((XSTRNCMP(name, "prime256v1", len) == 0) || + (XSTRNCMP(name, "secp256r1", len) == 0) || + (XSTRNCMP(name, "P-256", len) == 0)) { + curve = WOLFSSL_ECC_SECP256R1; + } + else if ((XSTRNCMP(name, "secp384r1", len) == 0) || + (XSTRNCMP(name, "P-384", len) == 0)) { + curve = WOLFSSL_ECC_SECP384R1; + } + else if ((XSTRNCMP(name, "secp521r1", len) == 0) || + (XSTRNCMP(name, "P-521", len) == 0)) { + curve = WOLFSSL_ECC_SECP521R1; + } + else if (XSTRNCMP(name, "X25519", len) == 0) { + curve = WOLFSSL_ECC_X25519; + } + else if (XSTRNCMP(name, "X448", len) == 0) { + curve = WOLFSSL_ECC_X448; + } + else { + #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) + int ret; + const ecc_set_type *eccSet; + + ret = wc_ecc_get_curve_idx_from_name(name); + if (ret < 0) { + WOLFSSL_MSG("Could not find name in set"); + return WOLFSSL_FAILURE; + } + + eccSet = wc_ecc_get_curve_params(ret); + if (eccSet == NULL) { + WOLFSSL_MSG("NULL set returned"); + return WOLFSSL_FAILURE; + } + + curve = GetCurveByOID(eccSet->oidSum); + #else + WOLFSSL_MSG("API not present to search farther using name"); + return WOLFSSL_FAILURE; + #endif + } + + if (curve > (sizeof(word32) * WOLFSSL_BIT_SIZE)) { + /* shift left more than size of ctx->disabledCurves causes static + * analysis report */ + WOLFSSL_MSG("curve value is too large for upcoming shift"); + return WOLFSSL_FAILURE; + } + + #if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT) + /* set the supported curve so client TLS extension contains only the + * desired curves */ + if (wolfSSL_CTX_UseSupportedCurve(ctx, curve) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Unable to set supported curve"); + return WOLFSSL_FAILURE; + } + #endif + + /* Switch the bit to off and therefore is enabled. */ + ctx->disabledCurves &= ~(1U << curve); + start = idx + 1; + } + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_set1_curves_list(WOLFSSL* ssl, const char* names) +{ + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + return wolfSSL_CTX_set1_curves_list(ssl->ctx, names); +} +#endif /* OPENSSL_EXTRA && HAVE_ECC */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_WOLFSSL_STUB +int wolfSSL_CTX_set_msg_callback(WOLFSSL_CTX *ctx, SSL_Msg_Cb cb) +{ + WOLFSSL_STUB("SSL_CTX_set_msg_callback"); + (void)ctx; + (void)cb; + return WOLFSSL_FAILURE; +} +#endif + + +/* Sets a callback for when sending and receiving protocol messages. + * + * ssl WOLFSSL structure to set callback in + * cb callback to use + * + * return SSL_SUCCESS on success and SSL_FAILURE with error case + */ +int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb) +{ + WOLFSSL_ENTER("wolfSSL_set_msg_callback"); + + if (ssl == NULL) { + return SSL_FAILURE; + } + + if (cb != NULL) { + ssl->toInfoOn = 1; + } + + ssl->protoMsgCb = cb; + return SSL_SUCCESS; +} +#ifndef NO_WOLFSSL_STUB +int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg) +{ + WOLFSSL_STUB("SSL_CTX_set_msg_callback_arg"); + (void)ctx; + (void)arg; + return WOLFSSL_FAILURE; +} +#endif + +int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg) +{ + WOLFSSL_ENTER("wolfSSL_set_msg_callback_arg"); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->protoMsgCtx = arg; + return WOLFSSL_SUCCESS; +} + +void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, int line) +{ + void *ret; + (void)file; + (void)line; + + if (data == NULL || siz >= INT_MAX) + return NULL; + + ret = OPENSSL_malloc(siz); + if (ret == NULL) { + return NULL; + } + return XMEMCPY(ret, data, siz); +} + +int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, + unsigned int p_len) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); + if(ctx == NULL) + return BAD_FUNC_ARG; + if((void *)ctx->alpn_cli_protos != NULL) + wolfSSL_OPENSSL_free((void *)ctx->alpn_cli_protos); + ctx->alpn_cli_protos = + (const unsigned char *)wolfSSL_OPENSSL_memdup(p, p_len, NULL, 0); + if (ctx->alpn_cli_protos == NULL) { + return SSL_FAILURE; + } + ctx->alpn_cli_protos_len = p_len; + + return SSL_SUCCESS; +} + + +#ifdef HAVE_ALPN +/* Sets the ALPN extension protos + * + * example format is + * unsigned char p[] = { + * 8, 'h', 't', 't', 'p', '/', '1', '.', '1' + * }; + * + * returns WOLFSSL_SUCCESS on success */ +int wolfSSL_set_alpn_protos(WOLFSSL* ssl, + const unsigned char* p, unsigned int p_len) +{ + WOLFSSL_BIO* bio; + char* pt; + + unsigned int sz; + unsigned int idx = 0; + int alpn_opt = WOLFSSL_ALPN_CONTINUE_ON_MISMATCH; + WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); + + if (ssl == NULL || p_len <= 1) { + return WOLFSSL_FAILURE; + } + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); + if (bio == NULL) { + return WOLFSSL_FAILURE; + } + + /* convert into comma separated list */ + while (idx < p_len - 1) { + unsigned int i; + + sz = p[idx++]; + if (idx + sz > p_len) { + WOLFSSL_MSG("Bad list format"); + wolfSSL_BIO_free(bio); + return WOLFSSL_FAILURE; + } + if (sz > 0) { + for (i = 0; i < sz; i++) { + wolfSSL_BIO_write(bio, &p[idx++], 1); + } + if (idx < p_len - 1) + wolfSSL_BIO_write(bio, ",", 1); + } + } + wolfSSL_BIO_write(bio, "\0", 1); + + /* clears out all current ALPN extensions set */ + TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, ssl->heap); + + if ((sz = wolfSSL_BIO_get_mem_data(bio, &pt)) > 0) { + wolfSSL_UseALPN(ssl, pt, sz, alpn_opt); + } + wolfSSL_BIO_free(bio); + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_ALPN */ +#endif + +#endif /* WOLFCRYPT_ONLY */ + +#if defined(OPENSSL_EXTRA) + +#define WOLFSSL_BIO_INCLUDED +#include "src/bio.c" + +int oid2nid(word32 oid, int grp) +{ + /* get OID type */ + switch (grp) { + /* oidHashType */ + case oidHashType: + switch (oid) { + #ifdef WOLFSSL_MD2 + case MD2h: + return NID_md2; + #endif + #ifndef NO_MD5 + case MD5h: + return NID_md5; + #endif + #ifndef NO_SHA + case SHAh: + return NID_sha1; + #endif + case SHA224h: + return NID_sha224; + #ifndef NO_SHA256 + case SHA256h: + return NID_sha256; + #endif + #ifdef WOLFSSL_SHA384 + case SHA384h: + return NID_sha384; + #endif + #ifdef WOLFSSL_SHA512 + case SHA512h: + return NID_sha512; + #endif + } + break; + + /* oidSigType */ + case oidSigType: + switch (oid) { + #ifndef NO_DSA + case CTC_SHAwDSA: + return CTC_SHAwDSA; + #endif /* NO_DSA */ + #ifndef NO_RSA + case CTC_MD2wRSA: + return CTC_MD2wRSA; + case CTC_MD5wRSA: + return CTC_MD5wRSA; + case CTC_SHAwRSA: + return CTC_SHAwRSA; + case CTC_SHA224wRSA: + return CTC_SHA224wRSA; + case CTC_SHA256wRSA: + return CTC_SHA256wRSA; + case CTC_SHA384wRSA: + return CTC_SHA384wRSA; + case CTC_SHA512wRSA: + return CTC_SHA512wRSA; + #endif /* NO_RSA */ + #ifdef HAVE_ECC + case CTC_SHAwECDSA: + return CTC_SHAwECDSA; + case CTC_SHA224wECDSA: + return CTC_SHA224wECDSA; + case CTC_SHA256wECDSA: + return CTC_SHA256wECDSA; + case CTC_SHA384wECDSA: + return CTC_SHA384wECDSA; + case CTC_SHA512wECDSA: + return CTC_SHA512wECDSA; + #endif /* HAVE_ECC */ + } + break; + + /* oidKeyType */ + case oidKeyType: + switch (oid) { + #ifndef NO_DSA + case DSAk: + return DSAk; + #endif /* NO_DSA */ + #ifndef NO_RSA + case RSAk: + return RSAk; + #endif /* NO_RSA */ + #ifdef HAVE_NTRU + case NTRUk: + return NTRUk; + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ECDSAk: + return ECDSAk; + #endif /* HAVE_ECC */ + } + break; + + + #ifdef HAVE_ECC + case oidCurveType: + switch (oid) { + case ECC_SECP192R1_OID: + return NID_X9_62_prime192v1; + case ECC_PRIME192V2_OID: + return NID_X9_62_prime192v2; + case ECC_PRIME192V3_OID: + return NID_X9_62_prime192v3; + case ECC_PRIME239V1_OID: + return NID_X9_62_prime239v1; + case ECC_PRIME239V2_OID: + return NID_X9_62_prime239v2; + case ECC_PRIME239V3_OID: + return NID_X9_62_prime239v3; + case ECC_SECP256R1_OID: + return NID_X9_62_prime256v1; + case ECC_SECP112R1_OID: + return NID_secp112r1; + case ECC_SECP112R2_OID: + return NID_secp112r2; + case ECC_SECP128R1_OID: + return NID_secp128r1; + case ECC_SECP128R2_OID: + return NID_secp128r2; + case ECC_SECP160R1_OID: + return NID_secp160r1; + case ECC_SECP160R2_OID: + return NID_secp160r2; + case ECC_SECP224R1_OID: + return NID_secp224r1; + case ECC_SECP384R1_OID: + return NID_secp384r1; + case ECC_SECP521R1_OID: + return NID_secp521r1; + case ECC_SECP160K1_OID: + return NID_secp160k1; + case ECC_SECP192K1_OID: + return NID_secp192k1; + case ECC_SECP224K1_OID: + return NID_secp224k1; + case ECC_SECP256K1_OID: + return NID_secp256k1; + case ECC_BRAINPOOLP160R1_OID: + return NID_brainpoolP160r1; + case ECC_BRAINPOOLP192R1_OID: + return NID_brainpoolP192r1; + case ECC_BRAINPOOLP224R1_OID: + return NID_brainpoolP224r1; + case ECC_BRAINPOOLP256R1_OID: + return NID_brainpoolP256r1; + case ECC_BRAINPOOLP320R1_OID: + return NID_brainpoolP320r1; + case ECC_BRAINPOOLP384R1_OID: + return NID_brainpoolP384r1; + case ECC_BRAINPOOLP512R1_OID: + return NID_brainpoolP512r1; + } + break; + #endif /* HAVE_ECC */ + + /* oidBlkType */ + case oidBlkType: + switch (oid) { + #ifdef WOLFSSL_AES_128 + case AES128CBCb: + return AES128CBCb; + #endif + #ifdef WOLFSSL_AES_192 + case AES192CBCb: + return AES192CBCb; + #endif + #ifdef WOLFSSL_AES_256 + case AES256CBCb: + return AES256CBCb; + #endif + #ifndef NO_DES3 + case DESb: + return NID_des; + case DES3b: + return NID_des3; + #endif + } + break; + + #ifdef HAVE_OCSP + case oidOcspType: + switch (oid) { + case OCSP_BASIC_OID: + return NID_id_pkix_OCSP_basic; + case OCSP_NONCE_OID: + return OCSP_NONCE_OID; + } + break; + #endif /* HAVE_OCSP */ + + /* oidCertExtType */ + case oidCertExtType: + switch (oid) { + case BASIC_CA_OID: + return BASIC_CA_OID; + case ALT_NAMES_OID: + return ALT_NAMES_OID; + case CRL_DIST_OID: + return CRL_DIST_OID; + case AUTH_INFO_OID: + return AUTH_INFO_OID; + case AUTH_KEY_OID: + return AUTH_KEY_OID; + case SUBJ_KEY_OID: + return SUBJ_KEY_OID; + case INHIBIT_ANY_OID: + return INHIBIT_ANY_OID; + case KEY_USAGE_OID: + return NID_key_usage; + case NAME_CONS_OID: + return NID_name_constraints; + case CERT_POLICY_OID: + return NID_certificate_policies; + } + break; + + /* oidCertAuthInfoType */ + case oidCertAuthInfoType: + switch (oid) { + case AIA_OCSP_OID: + return AIA_OCSP_OID; + case AIA_CA_ISSUER_OID: + return AIA_CA_ISSUER_OID; + } + break; + + /* oidCertPolicyType */ + case oidCertPolicyType: + switch (oid) { + case CP_ANY_OID: + return NID_any_policy; + } + break; + + /* oidCertAltNameType */ + case oidCertAltNameType: + switch (oid) { + case HW_NAME_OID: + return NID_hw_name_oid; + } + break; + + /* oidCertKeyUseType */ + case oidCertKeyUseType: + switch (oid) { + case EKU_ANY_OID: + return NID_anyExtendedKeyUsage; + case EKU_SERVER_AUTH_OID: + return EKU_SERVER_AUTH_OID; + case EKU_CLIENT_AUTH_OID: + return EKU_CLIENT_AUTH_OID; + case EKU_OCSP_SIGN_OID: + return EKU_OCSP_SIGN_OID; + } + break; + + /* oidKdfType */ + case oidKdfType: + switch (oid) { + case PBKDF2_OID: + return PBKDF2_OID; + } + break; + + /* oidPBEType */ + case oidPBEType: + switch (oid) { + case PBE_SHA1_RC4_128: + return PBE_SHA1_RC4_128; + case PBE_SHA1_DES: + return PBE_SHA1_DES; + case PBE_SHA1_DES3: + return PBE_SHA1_DES3; + } + break; + + /* oidKeyWrapType */ + case oidKeyWrapType: + switch (oid) { + #ifdef WOLFSSL_AES_128 + case AES128_WRAP: + return AES128_WRAP; + #endif + #ifdef WOLFSSL_AES_192 + case AES192_WRAP: + return AES192_WRAP; + #endif + #ifdef WOLFSSL_AES_256 + case AES256_WRAP: + return AES256_WRAP; + #endif + } + break; + + /* oidCmsKeyAgreeType */ + case oidCmsKeyAgreeType: + switch (oid) { + #ifndef NO_SHA + case dhSinglePass_stdDH_sha1kdf_scheme: + return dhSinglePass_stdDH_sha1kdf_scheme; + #endif + #ifdef WOLFSSL_SHA224 + case dhSinglePass_stdDH_sha224kdf_scheme: + return dhSinglePass_stdDH_sha224kdf_scheme; + #endif + #ifndef NO_SHA256 + case dhSinglePass_stdDH_sha256kdf_scheme: + return dhSinglePass_stdDH_sha256kdf_scheme; + #endif + #ifdef WOLFSSL_SHA384 + case dhSinglePass_stdDH_sha384kdf_scheme: + return dhSinglePass_stdDH_sha384kdf_scheme; + #endif + #ifdef WOLFSSL_SHA512 + case dhSinglePass_stdDH_sha512kdf_scheme: + return dhSinglePass_stdDH_sha512kdf_scheme; + #endif + } + break; + + default: + WOLFSSL_MSG("NID not in table"); + return -1; + } + + return -1; +} + + +/* when calling SetIndividualInternal, mpi should be cleared by caller if no + * longer used. ie mp_free(mpi). This is to free data when fastmath is + * disabled since a copy of mpi is made by this function and placed into bn. + */ +int SetIndividualInternal(WOLFSSL_BIGNUM* bn, mp_int* mpi) +{ + WOLFSSL_MSG("Entering SetIndividualInternal"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + if (mpi == NULL || (mp_init(mpi) != MP_OKAY)) { + WOLFSSL_MSG("mpi NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + if (mp_copy((mp_int*)bn->internal, mpi) != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + return WOLFSSL_FATAL_ERROR; + } + + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_ASN +WOLFSSL_BIGNUM *wolfSSL_ASN1_INTEGER_to_BN(const WOLFSSL_ASN1_INTEGER *ai, + WOLFSSL_BIGNUM *bn) +{ + mp_int mpi; + word32 idx = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_ASN1_INTEGER_to_BN"); + + if (ai == NULL) { + return NULL; + } + + ret = GetInt(&mpi, ai->data, &idx, ai->dataMax); + if (ret != 0) { + #ifdef WOLFSSL_QT + mp_init(&mpi); /* must init mpi */ + /* Serial number in QT starts at index 0 of data */ + if (mp_read_unsigned_bin(&mpi, (byte*)ai->data, ai->length) != 0) { + mp_clear(&mpi); + return NULL; + } + #else + /* expecting ASN1 format for INTEGER */ + WOLFSSL_LEAVE("wolfSSL_ASN1_INTEGER_to_BN", ret); + return NULL; + #endif + } + + /* mp_clear needs called because mpi is copied and causes memory leak with + * --disable-fastmath */ + ret = SetIndividualExternal(&bn, &mpi); + mp_clear(&mpi); + + if (ret != WOLFSSL_SUCCESS) { + return NULL; + } + return bn; +} +#endif /* !NO_ASN */ + +#if !defined(NO_DSA) && !defined(NO_DH) +WOLFSSL_DH *wolfSSL_DSA_dup_DH(const WOLFSSL_DSA *dsa) +{ + WOLFSSL_DH* dh; + DhKey* key; + + WOLFSSL_ENTER("wolfSSL_DSA_dup_DH"); + + if (dsa == NULL) { + return NULL; + } + + dh = wolfSSL_DH_new(); + if (dh == NULL) { + return NULL; + } + key = (DhKey*)dh->internal; + + if (dsa->p != NULL && + SetIndividualInternal(((WOLFSSL_DSA*)dsa)->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa p key error"); + wolfSSL_DH_free(dh); + return NULL; + } + if (dsa->g != NULL && + SetIndividualInternal(((WOLFSSL_DSA*)dsa)->g, &key->g) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa g key error"); + wolfSSL_DH_free(dh); + return NULL; + } + + if (SetIndividualExternal(&dh->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa p key error"); + wolfSSL_DH_free(dh); + return NULL; + } + if (SetIndividualExternal(&dh->g, &key->g) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("dsa g key error"); + wolfSSL_DH_free(dh); + return NULL; + } + + return dh; +} +#endif /* !NO_DSA && !NO_DH */ + + +#ifndef NO_RSA +#if !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) +/* Openssl -> WolfSSL */ +int SetRsaInternal(WOLFSSL_RSA* rsa) +{ + RsaKey* key; + WOLFSSL_MSG("Entering SetRsaInternal"); + + if (rsa == NULL || rsa->internal == NULL) { + WOLFSSL_MSG("rsa key NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + key = (RsaKey*)rsa->internal; + + if (SetIndividualInternal(rsa->n, &key->n) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa n key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualInternal(rsa->e, &key->e) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa e key error"); + return WOLFSSL_FATAL_ERROR; + } + + /* public key */ + key->type = RSA_PUBLIC; + + if (rsa->d != NULL) { + if (SetIndividualInternal(rsa->d, &key->d) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa d key error"); + return WOLFSSL_FATAL_ERROR; + } + + /* private key */ + key->type = RSA_PRIVATE; + } + + if (rsa->p != NULL && + SetIndividualInternal(rsa->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa p key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (rsa->q != NULL && + SetIndividualInternal(rsa->q, &key->q) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa q key error"); + return WOLFSSL_FATAL_ERROR; + } + +#ifndef RSA_LOW_MEM + if (rsa->dmp1 != NULL && + SetIndividualInternal(rsa->dmp1, &key->dP) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa dP key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (rsa->dmq1 != NULL && + SetIndividualInternal(rsa->dmq1, &key->dQ) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa dQ key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (rsa->iqmp != NULL && + SetIndividualInternal(rsa->iqmp, &key->u) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa u key error"); + return WOLFSSL_FATAL_ERROR; + } +#endif /* !RSA_LOW_MEM */ + + rsa->inSet = 1; + + return WOLFSSL_SUCCESS; +} + + +/* SSL_SUCCESS on ok */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bn) +{ + (void)rsa; + (void)bn; + WOLFSSL_STUB("RSA_blinding_on"); + WOLFSSL_MSG("wolfSSL_RSA_blinding_on"); + + return WOLFSSL_SUCCESS; /* on by default */ +} +#endif + +/* return compliant with OpenSSL + * size of encrypted data if success , -1 if error + */ +int wolfSSL_RSA_public_encrypt(int len, const unsigned char* fr, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int initTmpRng = 0; + WC_RNG *rng = NULL; + int outLen; + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG _tmpRNG[1]; + WC_RNG* tmpRNG = _tmpRNG; +#endif +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) + int mgf = WC_MGF1NONE; + enum wc_HashType hash = WC_HASH_TYPE_NONE; +#endif + + WOLFSSL_MSG("wolfSSL_RSA_public_encrypt"); + + /* Check and remap the padding to internal values, if needed. */ +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) + if (padding == RSA_PKCS1_PADDING) + padding = WC_RSA_PKCSV15_PAD; + else if (padding == RSA_PKCS1_OAEP_PADDING) { + padding = WC_RSA_OAEP_PAD; + hash = WC_HASH_TYPE_SHA; + mgf = WC_MGF1SHA1; + } + else if (padding == RSA_PKCS1_PSS_PADDING) { + padding = WC_RSA_PSS_PAD; + hash = WC_HASH_TYPE_SHA256; + mgf = WC_MGF1SHA256; + } + else if (padding == RSA_NO_PADDING) { + padding = WC_RSA_NO_PAD; + } +#else + if (padding == RSA_PKCS1_PADDING) + ; +#endif + else { + WOLFSSL_MSG("wolfSSL_RSA_public_encrypt unsupported padding"); + return 0; + } + + if (rsa->inSet == 0) + { + if (SetRsaInternal(rsa) != SSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return 0; + } + } + + outLen = wolfSSL_RSA_size(rsa); + + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRNG, &initTmpRng); + + if (outLen == 0) { + WOLFSSL_MSG("Bad RSA size"); + } + + if (rng) { +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) + ret = wc_RsaPublicEncrypt_ex(fr, len, to, outLen, + (RsaKey*)rsa->internal, rng, padding, + hash, mgf, NULL, 0); +#else + ret = wc_RsaPublicEncrypt(fr, len, to, outLen, + (RsaKey*)rsa->internal, rng); +#endif + if (ret <= 0) { + WOLFSSL_MSG("Bad Rsa Encrypt"); + } + if (len <= 0) { + WOLFSSL_MSG("Bad Rsa Encrypt"); + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + if (tmpRNG) + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (ret >= 0) + WOLFSSL_MSG("wolfSSL_RSA_public_encrypt success"); + else { + WOLFSSL_MSG("wolfSSL_RSA_public_encrypt failed"); + ret = WOLFSSL_FATAL_ERROR; /* return -1 on error case */ + } + return ret; +} + + + + +/* return compliant with OpenSSL + * size of plain recovered data if success , -1 if error + */ +int wolfSSL_RSA_private_decrypt(int len, const unsigned char* fr, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int outLen; + int ret = 0; + #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) + int mgf = WC_MGF1NONE; + enum wc_HashType hash = WC_HASH_TYPE_NONE; + #endif + + WOLFSSL_MSG("wolfSSL_RSA_private_decrypt"); + +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) + if (padding == RSA_PKCS1_PADDING) + padding = WC_RSA_PKCSV15_PAD; + else if (padding == RSA_PKCS1_OAEP_PADDING) { + padding = WC_RSA_OAEP_PAD; + hash = WC_HASH_TYPE_SHA; + mgf = WC_MGF1SHA1; + } + else if (padding == RSA_PKCS1_PSS_PADDING) { + padding = WC_RSA_PSS_PAD; + hash = WC_HASH_TYPE_SHA256; + mgf = WC_MGF1SHA256; + } + else if (padding == RSA_NO_PADDING) { + padding = WC_RSA_NO_PAD; + } +#else + if (padding == RSA_PKCS1_PADDING) + ; +#endif + else { + WOLFSSL_MSG("wolfSSL_RSA_private_decrypt unsupported padding"); + return 0; + } + + if (rsa->inSet == 0) + { + if (SetRsaInternal(rsa) != SSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return 0; + } + } + + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_MSG("Bad RSA size"); + } + + /* size of 'to' buffer must be size of RSA key */ +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) + ret = wc_RsaPrivateDecrypt_ex(fr, len, to, outLen, + (RsaKey*)rsa->internal, padding, + hash, mgf, NULL, 0); +#else + ret = wc_RsaPrivateDecrypt(fr, len, to, outLen, + (RsaKey*)rsa->internal); +#endif + + if (len <= 0) { + WOLFSSL_MSG("Bad Rsa Decrypt"); + } + + if (ret > 0) + WOLFSSL_MSG("wolfSSL_RSA_private_decrypt success"); + else { + WOLFSSL_MSG("wolfSSL_RSA_private_decrypt failed"); + ret = WOLFSSL_FATAL_ERROR; + } + return ret; +} + +#if !defined(_WIN32) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int tlen = 0; + int pad_type; + + WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt"); + + if (rsa == NULL || rsa->internal == NULL || from == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FAILURE; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case RSA_PKCS1_OAEP_PADDING: + pad_type = WC_RSA_OAEP_PAD; + break; + case RSA_PKCS1_PSS_PADDING: + pad_type = WC_RSA_PSS_PAD; + break; + case RSA_NO_PADDING: + pad_type = WC_RSA_NO_PAD; + break; + default: + WOLFSSL_MSG("wolfSSL_RSA_public_decrypt unsupported padding"); + return WOLFSSL_FAILURE; + } + + if (rsa->inSet == 0) + { + WOLFSSL_MSG("No RSA internal set, do it"); + + if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return WOLFSSL_FAILURE; + } + } + + /* size of 'to' buffer must be size of RSA key */ + tlen = wc_RsaSSL_Verify_ex(from, flen, to, wolfSSL_RSA_size(rsa), + (RsaKey*)rsa->internal, pad_type); + if (tlen <= 0) + WOLFSSL_MSG("wolfSSL_RSA_public_decrypt failed"); + else { + WOLFSSL_MSG("wolfSSL_RSA_public_decrypt success"); + } + return tlen; +} +#endif /* !defined(_WIN32) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) */ + +/* RSA private encrypt calls wc_RsaSSL_Sign. Similar function set up as RSA + * public decrypt. + * + * len Length of input buffer + * in Input buffer to sign + * out Output buffer (expected to be greater than or equal to RSA key size) + * rsa Key to use for encryption + * padding Type of RSA padding to use. + */ +int wolfSSL_RSA_private_encrypt(int len, unsigned char* in, + unsigned char* out, WOLFSSL_RSA* rsa, int padding) +{ + int sz = 0; + WC_RNG* rng = NULL; +#if !defined(WC_RSA_BLINDING) || defined(HAVE_USER_RSA) + WC_RNG rng_lcl; +#endif + RsaKey* key; + + WOLFSSL_MSG("wolfSSL_RSA_private_encrypt"); + + if (len < 0 || rsa == NULL || rsa->internal == NULL || in == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return 0; + } + + if (padding != RSA_PKCS1_PADDING && padding != RSA_PKCS1_PSS_PADDING) { + WOLFSSL_MSG("wolfSSL_RSA_private_encrypt unsupported padding"); + return 0; + } + + if (rsa->inSet == 0) + { + WOLFSSL_MSG("Setting internal RSA structure"); + + if (SetRsaInternal(rsa) != SSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return 0; + } + } + + key = (RsaKey*)rsa->internal; +#if defined(WC_RSA_BLINDING) && !defined(HAVE_USER_RSA) + rng = key->rng; +#else + rng = &rng_lcl; + #ifndef HAVE_FIPS + if (wc_InitRng_ex(rng, key->heap, INVALID_DEVID) != 0) + #else + if (wc_InitRng(rng) != 0) + #endif + { + WOLFSSL_MSG("Error with random number"); + return SSL_FATAL_ERROR; + } +#endif + + /* size of output buffer must be size of RSA key */ + sz = wc_RsaSSL_Sign(in, (word32)len, out, wolfSSL_RSA_size(rsa), key, rng); + #if !defined(WC_RSA_BLINDING) || defined(HAVE_USER_RSA) + if (wc_FreeRng(rng) != 0) { + WOLFSSL_MSG("Error freeing random number generator"); + return SSL_FATAL_ERROR; + } + #endif + if (sz <= 0) { + WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", sz); + return 0; + } + + return sz; +} +#endif /* HAVE_USER_RSA */ +#endif + + +/* frees all nodes in the current threads error queue + * + * id thread id. ERR_remove_state is depreciated and id is ignored. The + * current threads queue will be free'd. + */ +void wolfSSL_ERR_remove_state(unsigned long id) +{ + WOLFSSL_ENTER("wolfSSL_ERR_remove_state"); + (void)id; + if (wc_ERR_remove_state() != 0) { + WOLFSSL_MSG("Error with removing the state"); + } +} + + +WOLFSSL_BN_CTX* wolfSSL_BN_CTX_new(void) +{ + static int ctx; /* wolfcrypt doesn't now need ctx */ + + WOLFSSL_MSG("wolfSSL_BN_CTX_new"); + return (WOLFSSL_BN_CTX*)&ctx; + +} + +void wolfSSL_BN_CTX_init(WOLFSSL_BN_CTX* ctx) +{ + (void)ctx; + WOLFSSL_MSG("wolfSSL_BN_CTX_init"); +} + + +void wolfSSL_BN_CTX_free(WOLFSSL_BN_CTX* ctx) +{ + (void)ctx; + WOLFSSL_MSG("wolfSSL_BN_CTX_free"); + /* do free since static ctx that does nothing */ +} + +/* WOLFSSL_SUCCESS on ok */ +int wolfSSL_BN_sub(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a, + const WOLFSSL_BIGNUM* b) +{ + WOLFSSL_MSG("wolfSSL_BN_sub"); + + if (r == NULL || a == NULL || b == NULL) + return 0; + + if (mp_sub((mp_int*)a->internal,(mp_int*)b->internal, + (mp_int*)r->internal) == MP_OKAY) + return WOLFSSL_SUCCESS; + + WOLFSSL_MSG("wolfSSL_BN_sub mp_sub failed"); + return 0; +} + +/* WOLFSSL_SUCCESS on ok */ +int wolfSSL_BN_mod(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a, + const WOLFSSL_BIGNUM* b, const WOLFSSL_BN_CTX* c) +{ + (void)c; + WOLFSSL_MSG("wolfSSL_BN_mod"); + + if (r == NULL || a == NULL || b == NULL) + return 0; + + if (mp_mod((mp_int*)a->internal,(mp_int*)b->internal, + (mp_int*)r->internal) == MP_OKAY) + return WOLFSSL_SUCCESS; + + WOLFSSL_MSG("wolfSSL_BN_mod mp_mod failed"); + return 0; +} + + +/* r = (a^p) % m */ +int wolfSSL_BN_mod_exp(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a, + const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_BN_mod_exp"); + + (void) ctx; + if (r == NULL || a == NULL || p == NULL || m == NULL) { + WOLFSSL_MSG("Bad Argument"); + return WOLFSSL_FAILURE; + } + + if ((ret = mp_exptmod((mp_int*)a->internal,(mp_int*)p->internal, + (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) { + return WOLFSSL_SUCCESS; + } + + WOLFSSL_LEAVE("wolfSSL_BN_mod_exp", ret); + (void)ret; + + return WOLFSSL_FAILURE; +} + +/* r = (a * p) % m */ +int wolfSSL_BN_mod_mul(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a, + const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_BN_mod_mul"); + + (void) ctx; + if (r == NULL || a == NULL || p == NULL || m == NULL) { + WOLFSSL_MSG("Bad Argument"); + return SSL_FAILURE; + } + + if ((ret = mp_mulmod((mp_int*)a->internal,(mp_int*)p->internal, + (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) { + return SSL_SUCCESS; + } + + WOLFSSL_LEAVE("wolfSSL_BN_mod_mul", ret); + (void)ret; + + return SSL_FAILURE; +} + +#ifdef OPENSSL_EXTRA +const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void) +{ + WOLFSSL_MSG("wolfSSL_BN_value_one"); + + if (bn_one == NULL) { + bn_one = wolfSSL_BN_new(); + if (bn_one) { + if (mp_set_int((mp_int*)bn_one->internal, 1) != MP_OKAY) { + /* handle error by freeing BN and returning NULL */ + wolfSSL_BN_free(bn_one); + bn_one = NULL; + } + } + } + + return bn_one; +} +#endif + +/* return compliant with OpenSSL + * size of BIGNUM in bytes, 0 if error */ +int wolfSSL_BN_num_bytes(const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_ENTER("wolfSSL_BN_num_bytes"); + + if (bn == NULL || bn->internal == NULL) + return WOLFSSL_FAILURE; + + return mp_unsigned_bin_size((mp_int*)bn->internal); +} + +/* return compliant with OpenSSL + * size of BIGNUM in bits, 0 if error */ +int wolfSSL_BN_num_bits(const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_ENTER("wolfSSL_BN_num_bits"); + + if (bn == NULL || bn->internal == NULL) + return WOLFSSL_FAILURE; + + return mp_count_bits((mp_int*)bn->internal); +} + +int wolfSSL_BN_is_negative(const WOLFSSL_BIGNUM* bn) +{ + if (bn == NULL) + return WOLFSSL_FAILURE; + + return mp_isneg((mp_int*)bn->internal); +} + +/* return compliant with OpenSSL + * 1 if BIGNUM is zero, 0 else */ +int wolfSSL_BN_is_zero(const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_is_zero"); + + if (bn == NULL || bn->internal == NULL) + return WOLFSSL_FAILURE; + + if (mp_iszero((mp_int*)bn->internal) == MP_YES) + return WOLFSSL_SUCCESS; + + return WOLFSSL_FAILURE; +} + +/* return compliant with OpenSSL + * 1 if BIGNUM is one, 0 else */ +int wolfSSL_BN_is_one(const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_is_one"); + + if (bn == NULL || bn->internal == NULL) + return WOLFSSL_FAILURE; + + if (mp_cmp_d((mp_int*)bn->internal, 1) == MP_EQ) + return WOLFSSL_SUCCESS; + + return WOLFSSL_FAILURE; +} + +/* return compliant with OpenSSL + * 1 if BIGNUM is odd, 0 else */ +int wolfSSL_BN_is_odd(const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_is_odd"); + + if (bn == NULL || bn->internal == NULL) + return WOLFSSL_FAILURE; + + if (mp_isodd((mp_int*)bn->internal) == MP_YES) + return WOLFSSL_SUCCESS; + + return WOLFSSL_FAILURE; +} + +/* return compliant with OpenSSL + * 1 if BIGNUM is word, 0 else */ +int wolfSSL_BN_is_word(const WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w) +{ + WOLFSSL_ENTER("wolfSSL_BN_is_word"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_isword((mp_int*)bn->internal, w) == MP_YES) { + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + +/* return compliant with OpenSSL + * -1 if a < b, 0 if a == b and 1 if a > b + */ +int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_BN_cmp"); + + if (a == NULL || a->internal == NULL || b == NULL || b->internal == NULL) + return WOLFSSL_FATAL_ERROR; + + ret = mp_cmp((mp_int*)a->internal, (mp_int*)b->internal); + + return (ret == MP_EQ ? 0 : (ret == MP_GT ? 1 : -1)); +} + +/* return compliant with OpenSSL + * length of BIGNUM in bytes, -1 if error */ +int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r) +{ + WOLFSSL_MSG("wolfSSL_BN_bn2bin"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("NULL bn error"); + return WOLFSSL_FATAL_ERROR; + } + + if (r == NULL) + return mp_unsigned_bin_size((mp_int*)bn->internal); + + if (mp_to_unsigned_bin((mp_int*)bn->internal, r) != MP_OKAY) { + WOLFSSL_MSG("mp_to_unsigned_bin error"); + return WOLFSSL_FATAL_ERROR; + } + + return mp_unsigned_bin_size((mp_int*)bn->internal); +} + + +WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* str, int len, + WOLFSSL_BIGNUM* ret) +{ + int weOwn = 0; + + WOLFSSL_MSG("wolfSSL_BN_bin2bn"); + + /* if ret is null create a BN */ + if (ret == NULL) { + ret = wolfSSL_BN_new(); + weOwn = 1; + if (ret == NULL) + return NULL; + } + + /* check ret and ret->internal then read in value */ + if (ret && ret->internal) { + if (mp_read_unsigned_bin((mp_int*)ret->internal, str, len) != 0) { + WOLFSSL_MSG("mp_read_unsigned_bin failure"); + if (weOwn) + wolfSSL_BN_free(ret); + return NULL; + } + } else { + return NULL; + } + + return ret; +} + +/* return compliant with OpenSSL + * 1 if success, 0 if error */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_mask_bits(WOLFSSL_BIGNUM* bn, int n) +{ + (void)bn; + (void)n; + WOLFSSL_ENTER("wolfSSL_BN_mask_bits"); + WOLFSSL_STUB("BN_mask_bits"); + return SSL_FAILURE; +} +#endif + + +/* WOLFSSL_SUCCESS on ok */ +int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom) +{ + int ret = 0; + int len = bits / 8; + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; + byte* buff = NULL; +#else + WC_RNG tmpRNG[1]; + byte buff[1024]; +#endif + + (void)top; + (void)bottom; + WOLFSSL_MSG("wolfSSL_BN_rand"); + + if (bits % 8) + len++; + +#ifdef WOLFSSL_SMALL_STACK + buff = (byte*)XMALLOC(1024, NULL, DYNAMIC_TYPE_TMP_BUFFER); + tmpRNG = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (buff == NULL || tmpRNG == NULL) { + XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); + return ret; + } +#endif + + if (bn == NULL || bn->internal == NULL) + WOLFSSL_MSG("Bad function arguments"); + else if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else if (initGlobalRNG) + rng = &globalRNG; + + if (rng) { + if (wc_RNG_GenerateBlock(rng, buff, len) != 0) + WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); + else { + buff[0] |= 0x80 | 0x40; + buff[len-1] |= 0x01; + + if (mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY) + WOLFSSL_MSG("mp read bin failed"); + else + ret = WOLFSSL_SUCCESS; + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + return ret; +} + + +/* WOLFSSL_SUCCESS on ok + * code is same as wolfSSL_BN_rand except for how top and bottom is handled. + * top -1 then leave most sig bit alone + * top 0 then most sig is set to 1 + * top is 1 then first two most sig bits are 1 + * + * bottom is hot then odd number */ +int wolfSSL_BN_pseudo_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom) +{ + int ret = 0; + int len = bits / 8; + int initTmpRng = 0; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; + byte* buff = NULL; +#else + WC_RNG tmpRNG[1]; + byte buff[1024]; +#endif + + WOLFSSL_MSG("wolfSSL_BN_rand"); + + if (bits % 8) + len++; + +#ifdef WOLFSSL_SMALL_STACK + buff = (byte*)XMALLOC(1024, NULL, DYNAMIC_TYPE_TMP_BUFFER); + tmpRNG = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buff == NULL || tmpRNG == NULL) { + XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } +#endif + + if (bn == NULL || bn->internal == NULL) + WOLFSSL_MSG("Bad function arguments"); + else if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else if (initGlobalRNG) + rng = &globalRNG; + + if (rng) { + if (wc_RNG_GenerateBlock(rng, buff, len) != 0) + WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); + else { + switch (top) { + case -1: + break; + + case 0: + buff[0] |= 0x80; + break; + + case 1: + buff[0] |= 0x80 | 0x40; + break; + } + + if (bottom == 1) { + buff[len-1] |= 0x01; + } + + if (mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY) + WOLFSSL_MSG("mp read bin failed"); + else + ret = WOLFSSL_SUCCESS; + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +/* return code compliant with OpenSSL : + * 1 if bit set, 0 else + */ +int wolfSSL_BN_is_bit_set(const WOLFSSL_BIGNUM* bn, int n) +{ + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + return mp_is_bit_set((mp_int*)bn->internal, (mp_digit)n); +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 else + */ +int wolfSSL_BN_set_bit(WOLFSSL_BIGNUM* bn, int n) +{ + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_set_bit((mp_int*)bn->internal, n) != MP_OKAY) { + WOLFSSL_MSG("mp_set_bit error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_BN_clear_bit(WOLFSSL_BIGNUM* bn, int n) +{ + int ret = WOLFSSL_FAILURE; +#ifndef WOLFSSL_SMALL_STACK + mp_int tmp[1]; +#else + mp_int* tmp = NULL; +#endif + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + goto cleanup; + } + if (mp_is_bit_set((mp_int*)bn->internal, n)) { +#ifdef WOLFSSL_SMALL_STACK + tmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (tmp == NULL) { + goto cleanup; + } +#endif + if (mp_init(tmp) != MP_OKAY) { + goto cleanup; + } + if (mp_set_bit(tmp, n) != MP_OKAY) { + goto cleanup; + } + if (mp_sub((mp_int*)bn->internal, tmp, (mp_int*)bn->internal) != MP_OKAY) { + goto cleanup; + } + } + + ret = WOLFSSL_SUCCESS; +cleanup: + mp_clear(tmp); +#ifdef WOLFSSL_SMALL_STACK + if (tmp) + XFREE(tmp, NULL, DYNAMIC_TYPE_BIGINT); +#endif + return ret; +} + + +/* WOLFSSL_SUCCESS on ok */ +/* Note on use: this function expects str to be an even length. It is + * converting pairs of bytes into 8-bit values. As an example, the RSA + * public exponent is commonly 0x010001. To get it to convert, you need + * to pass in the string "010001", it will fail if you use "10001". This + * is an affect of how Base16_Decode() works. + */ +int wolfSSL_BN_hex2bn(WOLFSSL_BIGNUM** bn, const char* str) +{ + int ret = 0; + word32 decSz = 1024; +#ifdef WOLFSSL_SMALL_STACK + byte* decoded; +#else + byte decoded[1024]; +#endif + int weOwn = 0; + int strLen; + + WOLFSSL_MSG("wolfSSL_BN_hex2bn"); + +#ifdef WOLFSSL_SMALL_STACK + decoded = (byte*)XMALLOC(decSz, NULL, DYNAMIC_TYPE_DER); + if (decoded == NULL) + return ret; +#endif + + if (str == NULL || str[0] == '\0') { + WOLFSSL_MSG("Bad function argument"); + ret = WOLFSSL_FAILURE; + } else { + strLen = (int)XSTRLEN(str); + /* ignore trailing new lines */ + while (str[strLen-1] == '\n' && strLen > 0) strLen--; + + if (Base16_Decode((byte*)str, strLen, decoded, &decSz) < 0) + WOLFSSL_MSG("Bad Base16_Decode error"); + else if (bn == NULL) + ret = decSz; + else { + if (*bn == NULL) { + *bn = wolfSSL_BN_new(); + if (*bn != NULL) { + weOwn = 1; + } + } + + if (*bn == NULL) + WOLFSSL_MSG("BN new failed"); + else if (wolfSSL_BN_bin2bn(decoded, decSz, *bn) == NULL) { + WOLFSSL_MSG("Bad bin2bn error"); + if (weOwn == 1) { + wolfSSL_BN_free(*bn); /* Free new BN */ + } + } + else + ret = WOLFSSL_SUCCESS; + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(decoded, NULL, DYNAMIC_TYPE_DER); +#endif + + return ret; +} + + +WOLFSSL_BIGNUM* wolfSSL_BN_dup(const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_BIGNUM* ret; + + WOLFSSL_MSG("wolfSSL_BN_dup"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return NULL; + } + + ret = wolfSSL_BN_new(); + if (ret == NULL) { + WOLFSSL_MSG("bn new error"); + return NULL; + } + + if (mp_copy((mp_int*)bn->internal, (mp_int*)ret->internal) != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + wolfSSL_BN_free(ret); + return NULL; + } + + ret->neg = bn->neg; + + return ret; +} + + +WOLFSSL_BIGNUM* wolfSSL_BN_copy(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_copy"); + + if (r == NULL || bn == NULL) { + WOLFSSL_MSG("r or bn NULL error"); + return NULL; + } + + if (mp_copy((mp_int*)bn->internal, (mp_int*)r->internal) != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + return NULL; + } + + r->neg = bn->neg; + + return r; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 else + */ +int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w) +{ + WOLFSSL_MSG("wolfSSL_BN_set_word"); + + if (bn == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_set_int((mp_int*)bn->internal, w) != MP_OKAY) { + WOLFSSL_MSG("mp_init_set_int error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + + +/* Returns the big number as an unsigned long if possible. + * + * bn big number structure to get value from + * + * Returns value or 0xFFFFFFFFL if bigger than unsigned long. + */ +unsigned long wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn) +{ + mp_int* mp; + + WOLFSSL_MSG("wolfSSL_BN_get_word"); + + if (bn == NULL) { + WOLFSSL_MSG("Invalid argument"); + return 0; + } + + if (wolfSSL_BN_num_bytes(bn) > (int)sizeof(unsigned long)) { + WOLFSSL_MSG("bignum is larger than unsigned long"); + return 0xFFFFFFFFL; + } + mp = (mp_int*)bn->internal; + + return (unsigned long)(mp->dp[0]); +} + +/* return code compliant with OpenSSL : + * number length in decimal if success, 0 if error + */ +#ifndef NO_WOLFSSL_STUB +int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str) +{ + (void)bn; + (void)str; + + WOLFSSL_MSG("wolfSSL_BN_dec2bn"); + WOLFSSL_STUB("BN_dec2bn"); + return SSL_FAILURE; +} +#endif + +#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) +char *wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM *bn) +{ + int len = 0; + char *buf; + + WOLFSSL_MSG("wolfSSL_BN_bn2dec"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return NULL; + } + + if (mp_radix_size((mp_int*)bn->internal, MP_RADIX_DEC, &len) != MP_OKAY) { + WOLFSSL_MSG("mp_radix_size failure"); + return NULL; + } + + buf = (char*) XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (buf == NULL) { + WOLFSSL_MSG("BN_bn2dec malloc buffer failure"); + return NULL; + } + + if (mp_todecimal((mp_int*)bn->internal, buf) != MP_OKAY) { + XFREE(buf, NULL, DYNAMIC_TYPE_ECC); + return NULL; + } + + return buf; +} +#else +char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM* bn) +{ + (void)bn; + + WOLFSSL_MSG("wolfSSL_BN_bn2dec"); + + return NULL; +} +#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */ + +/* return code compliant with OpenSSL : + * 1 if success, 0 else + */ +int wolfSSL_BN_lshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n) +{ + WOLFSSL_MSG("wolfSSL_BN_lshift"); + + if (r == NULL || r->internal == NULL || bn == NULL || bn->internal == NULL){ + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_mul_2d((mp_int*)bn->internal, n, (mp_int*)r->internal) != MP_OKAY) { + WOLFSSL_MSG("mp_mul_2d error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 else + */ +int wolfSSL_BN_rshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n) +{ + WOLFSSL_MSG("wolfSSL_BN_rshift"); + + if (r == NULL || r->internal == NULL || bn == NULL || bn->internal == NULL){ + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_div_2d((mp_int*)bn->internal, n, + (mp_int*)r->internal, NULL) != MP_OKAY) { + WOLFSSL_MSG("mp_mul_2d error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 else + */ +int wolfSSL_BN_add_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w) +{ + WOLFSSL_MSG("wolfSSL_BN_add_word"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_add_d((mp_int*)bn->internal, w, (mp_int*)bn->internal) != MP_OKAY) { + WOLFSSL_MSG("mp_add_d error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* return code compliant with OpenSSL : + * 1 if success, 0 else + */ +int wolfSSL_BN_add(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b) +{ + WOLFSSL_MSG("wolfSSL_BN_add"); + + if (r == NULL || r->internal == NULL || a == NULL || a->internal == NULL || + b == NULL || b->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_add((mp_int*)a->internal, (mp_int*)b->internal, + (mp_int*)r->internal) != MP_OKAY) { + WOLFSSL_MSG("mp_add_d error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* r = a + b (mod m) */ +int wolfSSL_BN_mod_add(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a, + const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, + WOLFSSL_BN_CTX *ctx) +{ + (void)ctx; + WOLFSSL_MSG("wolfSSL_BN_add"); + + if (r == NULL || r->internal == NULL || + a == NULL || a->internal == NULL || + b == NULL || b->internal == NULL || + m == NULL || m->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + if (mp_addmod((mp_int*)a->internal, (mp_int*)b->internal, + (mp_int*)m->internal, (mp_int*)r->internal) != MP_OKAY) { + WOLFSSL_MSG("mp_add_d error"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +#ifdef WOLFSSL_KEY_GEN + +/* return code compliant with OpenSSL : + * 1 if prime, 0 if not, -1 if error + */ +int wolfSSL_BN_is_prime_ex(const WOLFSSL_BIGNUM *bn, int nbchecks, + WOLFSSL_BN_CTX *ctx, WOLFSSL_BN_GENCB *cb) +{ + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + int initTmpRng = 0; + int res = MP_NO; + + (void)ctx; + (void)cb; + + WOLFSSL_MSG("wolfSSL_BN_is_prime_ex"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FAILURE; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) { + WOLFSSL_MSG("Global RNG no Init"); + } + else + rng = &globalRNG; + } + + if (rng) { + if (mp_prime_is_prime_ex((mp_int*)bn->internal, + nbchecks, &res, rng) != MP_OKAY) { + WOLFSSL_MSG("mp_prime_is_prime_ex error"); + res = MP_NO; + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + + if (res != MP_YES) { + WOLFSSL_MSG("mp_prime_is_prime_ex not prime"); + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} + +/* return code compliant with OpenSSL : + * (bn mod w) if success, -1 if error + */ +WOLFSSL_BN_ULONG wolfSSL_BN_mod_word(const WOLFSSL_BIGNUM *bn, + WOLFSSL_BN_ULONG w) +{ + WOLFSSL_BN_ULONG ret = 0; + + WOLFSSL_MSG("wolfSSL_BN_mod_word"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR; + } + + if (mp_mod_d((mp_int*)bn->internal, w, &ret) != MP_OKAY) { + WOLFSSL_MSG("mp_add_d error"); + return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR; + } + + return ret; +} +#endif /* #ifdef WOLFSSL_KEY_GEN */ + +char *wolfSSL_BN_bn2hex(const WOLFSSL_BIGNUM *bn) +{ + int len = 0; + char *buf; + + WOLFSSL_ENTER("wolfSSL_BN_bn2hex"); + + if (bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return NULL; + } + + if (mp_radix_size((mp_int*)bn->internal, MP_RADIX_HEX, &len) != MP_OKAY) { + WOLFSSL_MSG("mp_radix_size failure"); + return NULL; + } + len += 1; /* add one for null terminator */ + + buf = (char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (buf == NULL) { + WOLFSSL_MSG("BN_bn2hex malloc buffer failure"); + return NULL; + } + + if (mp_tohex((mp_int*)bn->internal, buf) != MP_OKAY) { + XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + return buf; +} + +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error + */ +int wolfSSL_BN_print_fp(XFILE fp, const WOLFSSL_BIGNUM *bn) +{ + char *buf; + + WOLFSSL_ENTER("wolfSSL_BN_print_fp"); + + if (fp == XBADFILE || bn == NULL || bn->internal == NULL) { + WOLFSSL_MSG("bn NULL error"); + return WOLFSSL_FAILURE; + } + + buf = wolfSSL_BN_bn2hex(bn); + if (buf == NULL) { + WOLFSSL_MSG("wolfSSL_BN_bn2hex failure"); + return WOLFSSL_FAILURE; + } + + fprintf(fp, "%s", buf); + XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); + + return WOLFSSL_SUCCESS; +} +#endif /* !NO_FILESYSTEM */ + + +WOLFSSL_BIGNUM *wolfSSL_BN_CTX_get(WOLFSSL_BN_CTX *ctx) +{ + /* ctx is not used, return new Bignum */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_BN_CTX_get"); + + return wolfSSL_BN_new(); +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_BN_CTX_start(WOLFSSL_BN_CTX *ctx) +{ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_BN_CTX_start"); + WOLFSSL_STUB("BN_CTX_start"); + WOLFSSL_MSG("wolfSSL_BN_CTX_start TBD"); +} +#endif + + +WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM *r, + WOLFSSL_BIGNUM *a, + const WOLFSSL_BIGNUM *n, + WOLFSSL_BN_CTX *ctx) +{ + int dynamic = 0; + + /* ctx is not used */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_BN_mod_inverse"); + + /* check parameter */ + if (r == NULL) { + r = wolfSSL_BN_new(); + if (r == NULL){ + WOLFSSL_MSG("WolfSSL_BN_new() failed"); + return NULL; + } + dynamic = 1; + } + + if (a == NULL) { + WOLFSSL_MSG("a NULL error"); + if (dynamic == 1) { + wolfSSL_BN_free(r); + } + return NULL; + } + + if (n == NULL) { + WOLFSSL_MSG("n NULL error"); + if (dynamic == 1) { + wolfSSL_BN_free(r); + } + return NULL; + } + + /* Compute inverse of a modulo n and return r */ + if (mp_invmod((mp_int *)a->internal,(mp_int *)n->internal, + (mp_int*)r->internal) == MP_VAL){ + WOLFSSL_MSG("mp_invmod() error"); + if (dynamic == 1) { + wolfSSL_BN_free(r); + } + return NULL; + } + + return r; +} +#endif /* OPENSSL_EXTRA */ +#if (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) && !defined(NO_ASN) +static int unprintable_char(char c) +{ + const unsigned char last_unprintable = 31; + const unsigned char LF = 10; + const unsigned char CR = 13; + + if (c <= last_unprintable && c != LF && c != CR) { + return 1; + } + return 0; +} + +int wolfSSL_ASN1_STRING_print(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str) +{ + int i; + + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_print"); + if (out == NULL || str == NULL) + return WOLFSSL_FAILURE; + + for (i=0; i < str->length; i++) { + if (unprintable_char(str->data[i])) { + str->data[i] = '.'; + } + } + + if (wolfSSL_BIO_write(out, str->data, str->length) != str->length){ + return WOLFSSL_FAILURE; + } + + return str->length; +} +#endif /* (WOLFSSL_QT || OPENSSL_ALL) && !NO_ASN */ + +#if defined(OPENSSL_EXTRA) +int wolfSSL_X509_check_ca(WOLFSSL_X509 *x509) +{ + WOLFSSL_ENTER("X509_check_ca"); + + if (x509 == NULL) + return WOLFSSL_FAILURE; + if (x509->isCa) + return 1; + if (x509->extKeyUsageCrit) + return 4; + + return 0; +} + + +const char *wolfSSL_ASN1_tag2str(int tag) +{ + static const char *const tag_label[31] = { + "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", "NULL", + "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", "ENUMERATED", + "", "UTF8STRING", "", "", "", + "SEQUENCE", "SET", "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", + "VIDEOTEXTSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME", + "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", "UNIVERSALSTRING", + "", "BMPSTRING" + }; + + if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED)) + tag &= ~0x100; + if (tag < 0 || tag > 30) + return "(unknown)"; + return tag_label[tag]; +} + +static int check_esc_char(char c, char *esc) +{ + char *ptr; + + ptr = esc; + while(*ptr != 0){ + if (c == *ptr) + return 1; + ptr++; + } + return 0; +} + +int wolfSSL_ASN1_STRING_print_ex(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str, + unsigned long flags) +{ + size_t str_len = 0, type_len = 0; + unsigned char *typebuf = NULL; + const char *hash="#"; + + WOLFSSL_ENTER("wolfSSL_ASN1_STRING_PRINT_ex"); + if (out == NULL || str == NULL) + return WOLFSSL_FAILURE; + + /* add ASN1 type tag */ + if (flags & ASN1_STRFLGS_SHOW_TYPE){ + const char *tag = wolfSSL_ASN1_tag2str(str->type); + /* colon len + tag len + null*/ + type_len = XSTRLEN(tag) + 2; + typebuf = (unsigned char *)XMALLOC(type_len , NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (typebuf == NULL){ + WOLFSSL_MSG("memory alloc failed."); + return WOLFSSL_FAILURE; + } + XMEMSET(typebuf, 0, type_len); + XSNPRINTF((char*)typebuf, (size_t)type_len , "%s:", tag); + type_len--; + } + + /* dump hex */ + if (flags & ASN1_STRFLGS_DUMP_ALL){ + static const char hex_char[] = { '0', '1', '2', '3', '4', '5', '6', + '7','8', '9', 'A', 'B', 'C', 'D', + 'E', 'F' }; + char hex_tmp[4]; + char *str_ptr, *str_end; + + if (type_len > 0){ + if (wolfSSL_BIO_write(out, typebuf, (int)type_len) != (int)type_len){ + XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + str_len += type_len; + } + if (wolfSSL_BIO_write(out, hash, 1) != 1){ + goto err_exit; + } + str_len++; + if (flags & ASN1_STRFLGS_DUMP_DER){ + hex_tmp[0] = hex_char[str->type >> 4]; + hex_tmp[1] = hex_char[str->type & 0xf]; + hex_tmp[2] = hex_char[str->length >> 4]; + hex_tmp[3] = hex_char[str->length & 0xf]; + if (wolfSSL_BIO_write(out, hex_tmp, 4) != 4){ + goto err_exit; + } + str_len += 4; + XMEMSET(hex_tmp, 0, 4); + } + + str_ptr = str->data; + str_end = str->data + str->length; + while (str_ptr < str_end){ + hex_tmp[0] = hex_char[*str_ptr >> 4]; + hex_tmp[1] = hex_char[*str_ptr & 0xf]; + if (wolfSSL_BIO_write(out, hex_tmp, 2) != 2){ + goto err_exit; + } + str_ptr++; + str_len += 2; + } + if (type_len > 0) + XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return (int)str_len; + } + + if (type_len > 0){ + if (wolfSSL_BIO_write(out, typebuf, (int)type_len) != (int)type_len){ + XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + str_len += type_len; + } + + if (flags & ASN1_STRFLGS_ESC_2253){ + char esc_ch[] = "+;<>\\"; + char* esc_ptr; + + esc_ptr = str->data; + while (*esc_ptr != 0){ + if (check_esc_char(*esc_ptr, esc_ch)){ + if (wolfSSL_BIO_write(out,"\\", 1) != 1) + goto err_exit; + str_len++; + } + if (wolfSSL_BIO_write(out, esc_ptr, 1) != 1) + goto err_exit; + str_len++; + esc_ptr++; + } + if (type_len > 0) + XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return (int)str_len; + } + + if (wolfSSL_BIO_write(out, str->data, str->length) != str->length){ + goto err_exit; + } + str_len += str->length; + if (type_len > 0) + XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return (int)str_len; + +err_exit: + if (type_len > 0) + XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; +} + +#if !defined(NO_ASN_TIME) && !defined(USER_TIME) && !defined(TIME_OVERRIDES) +WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_new(void) +{ + WOLFSSL_ASN1_TIME* ret = (WOLFSSL_ASN1_TIME*) + XMALLOC(sizeof(WOLFSSL_ASN1_TIME), NULL, DYNAMIC_TYPE_OPENSSL); + if (!ret) + return NULL; + XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TIME)); + return ret; +} + +void wolfSSL_ASN1_TIME_free(WOLFSSL_ASN1_TIME* t) +{ + if (t) { + XFREE(t, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME *s, time_t t, + int offset_day, long offset_sec) +{ + const time_t sec_per_day = 24*60*60; + struct tm* ts = NULL; + struct tm* tmpTime; + time_t t_adj = 0; + time_t offset_day_sec = 0; +#if defined(NEED_TMP_TIME) + struct tm tmpTimeStorage; + + tmpTime = &tmpTimeStorage; +#else + tmpTime = NULL; +#endif + (void)tmpTime; + + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_adj"); + + if (s == NULL){ + s = wolfSSL_ASN1_TIME_new(); + if (s == NULL){ + return NULL; + } + } + + /* compute GMT time with offset */ + offset_day_sec = offset_day * sec_per_day; + t_adj = t + offset_day_sec + offset_sec; + ts = (struct tm *)XGMTIME(&t_adj, tmpTime); + if (ts == NULL){ + WOLFSSL_MSG("failed to get time data."); + XFREE(s, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + /* create ASN1 time notation */ + /* UTC Time */ + if (ts->tm_year >= 50 && ts->tm_year < 150){ + char utc_str[ASN_UTC_TIME_SIZE]; + int utc_year = 0,utc_mon,utc_day,utc_hour,utc_min,utc_sec; + + s->type = V_ASN1_UTCTIME; + s->length = ASN_UTC_TIME_SIZE; + + if (ts->tm_year >= 50 && ts->tm_year < 100){ + utc_year = ts->tm_year; + } else if (ts->tm_year >= 100 && ts->tm_year < 150){ + utc_year = ts->tm_year - 100; + } + utc_mon = ts->tm_mon + 1; + utc_day = ts->tm_mday; + utc_hour = ts->tm_hour; + utc_min = ts->tm_min; + utc_sec = ts->tm_sec; + XSNPRINTF((char *)utc_str, sizeof(utc_str), + "%02d%02d%02d%02d%02d%02dZ", + utc_year, utc_mon, utc_day, utc_hour, utc_min, utc_sec); + XMEMCPY(s->data, (byte *)utc_str, s->length); + /* GeneralizedTime */ + } else { + char gt_str[ASN_GENERALIZED_TIME_MAX]; + int gt_year,gt_mon,gt_day,gt_hour,gt_min,gt_sec; + + s->type = V_ASN1_GENERALIZEDTIME; + s->length = ASN_GENERALIZED_TIME_SIZE; + + gt_year = ts->tm_year + 1900; + gt_mon = ts->tm_mon + 1; + gt_day = ts->tm_mday; + gt_hour = ts->tm_hour; + gt_min = ts->tm_min; + gt_sec = ts->tm_sec; + XSNPRINTF((char *)gt_str, sizeof(gt_str), + "%4d%02d%02d%02d%02d%02dZ", + gt_year, gt_mon, gt_day, gt_hour, gt_min,gt_sec); + XMEMCPY(s->data, (byte *)gt_str, s->length); + } + + return s; +} +#endif /* !NO_ASN_TIME && !USER_TIME && !TIME_OVERRIDES */ + +#ifndef NO_ASN_TIME +/* not a compatibility function - length getter for opaque type */ +int wolfSSL_ASN1_TIME_get_length(WOLFSSL_ASN1_TIME *t) +{ + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_get_length"); + if (t == NULL) + return WOLFSSL_FAILURE; + return t->length; +} +/* not a compatibility function - data getter for opaque type */ +unsigned char* wolfSSL_ASN1_TIME_get_data(WOLFSSL_ASN1_TIME *t) +{ + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_get_data"); + if (t == NULL) + return NULL; + return t->data; +} + +WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t, + WOLFSSL_ASN1_TIME **out) +{ + int time_type = 0; + WOLFSSL_ASN1_TIME *ret = NULL; + + WOLFSSL_ENTER("wolfSSL_ASN1_TIME_to_generalizedtime"); + if (t == NULL) { + WOLFSSL_MSG("Invalid ASN_TIME value"); + } else { + time_type = t->type; + if (time_type != ASN_UTC_TIME && time_type != ASN_GENERALIZED_TIME){ + WOLFSSL_MSG("Invalid ASN_TIME type."); + } else { + if (out == NULL || *out == NULL) { + ret = wolfSSL_ASN1_TIME_new(); + if (ret == NULL){ + WOLFSSL_MSG("memory alloc failed."); + } + } else { + ret = *out; + } + } + } + + if (ret != NULL) { + if (time_type == ASN_GENERALIZED_TIME){ + XMEMCPY(ret->data, t->data, ASN_GENERALIZED_TIME_SIZE); + } else { /* ASN_UTC_TIME */ + /* convert UTC to generalized time */ + ret->type = ASN_GENERALIZED_TIME; + ret->length = ASN_GENERALIZED_TIME_SIZE; + if (t->data[0] >= '5') { + ret->data[0] = '1'; ret->data[1] = '9'; + } else { + ret->data[0] = '2'; ret->data[1] = '0'; + } + XMEMCPY(&ret->data[2], t->data, ASN_UTC_TIME_SIZE); + } + } + + return ret; +} +#endif /* !NO_ASN_TIME */ + +#ifndef NO_ASN +int wolfSSL_i2c_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER *a, unsigned char **pp) +{ + unsigned char *pptr = NULL; + char pad = 0 ; + unsigned char pad_val = 0; + int ret_size = 0; + unsigned char data1 = 0; + unsigned char neg = 0; + int i = 0; + + WOLFSSL_ENTER("wolfSSL_i2c_ASN1_INTEGER"); + if (a == NULL) + return WOLFSSL_FAILURE; + + ret_size = a->intData[1]; + if (ret_size == 0) + ret_size = 1; + else{ + ret_size = (int)a->intData[1]; + neg = a->negative; + data1 = a->intData[2]; + if (ret_size == 1 && data1 == 0) + neg = 0; + /* 0x80 or greater positive number in first byte */ + if (!neg && (data1 > 127)){ + pad = 1; + pad_val = 0; + } else if (neg){ + /* negative number */ + if (data1 > 128){ + pad = 1; + pad_val = 0xff; + } else if (data1 == 128){ + for (i = 3; i < a->intData[1] + 2; i++){ + if (a->intData[i]){ + pad = 1; + pad_val = 0xff; + break; + } + } + } + } + ret_size += (int)pad; + } + if (pp == NULL) + return ret_size; + + pptr = *pp; + if (pad) + *(pptr++) = pad_val; + if (a->intData[1] == 0) + *(pptr++) = 0; + else if (!neg){ + /* positive number */ + for (i=0; i < a->intData[1]; i++){ + *pptr = a->intData[i+2]; + pptr++; + } + } else { + /* negative number */ + int str_len = 0; + + /* 0 padding from end of buffer */ + str_len = (int)a->intData[1]; + pptr += a->intData[1] - 1; + while (!a->intData[str_len + 2] && str_len > 1){ + *(pptr--) = 0; + str_len--; + } + /* 2's complement next octet */ + *(pptr--) = ((a->intData[str_len + 1]) ^ 0xff) + 1; + str_len--; + /* Complement any octets left */ + while (str_len > 0){ + *(pptr--) = a->intData[str_len + 1] ^ 0xff; + str_len--; + } + } + *pp += ret_size; + return ret_size; +} +#endif /* !NO_ASN */ + + +#ifndef NO_CERTS +int wolfSSL_X509_CA_num(WOLFSSL_X509_STORE* store) +{ + int i = 0; + int cnt_ret = 0; + Signer **table; + + WOLFSSL_ENTER("wolfSSL_X509_CA_num"); + if (store == NULL || store->cm == NULL){ + WOLFSSL_MSG("invalid parameter"); + return WOLFSSL_FAILURE; + } + + table = store->cm->caTable; + if (table){ + if (wc_LockMutex(&store->cm->caLock) == 0){ + for (i = 0; i < CA_TABLE_SIZE; i++) { + Signer* signer = table[i]; + while (signer) { + Signer* next = signer->next; + cnt_ret++; + signer = next; + } + } + wc_UnLockMutex(&store->cm->caLock); + } + } + + return cnt_ret; +} +#endif /* !NO_CERTS */ + +long wolfSSL_X509_get_version(const WOLFSSL_X509 *x509) +{ + int version = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_version"); + + if (x509 == NULL){ + WOLFSSL_MSG("invalid parameter"); + return 0L; + } + version = x509->version; + if (version != 0) + return (long)version - 1L; + + return 0L; +} + + +int wolfSSL_X509_get_signature_nid(const WOLFSSL_X509 *x) +{ + if (x == NULL) + return 0; + + return oid2nid(x->sigOID, oidSigType); +} +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) +/* return compliant with OpenSSL + * RSA modulus size in bytes, -1 if error + */ +int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa) +{ + WOLFSSL_ENTER("wolfSSL_RSA_size"); + + if (rsa == NULL) + return WOLFSSL_FATAL_ERROR; + if (rsa->inSet == 0) + { + if (SetRsaInternal((WOLFSSL_RSA*)rsa) != SSL_SUCCESS) { + WOLFSSL_MSG("SetRsaInternal failed"); + return 0; + } + } + return wc_RsaEncryptSize((RsaKey*)rsa->internal); +} +#endif + +#if !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) && \ + !defined(NO_RSA) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +/* WolfSSL -> OpenSSL */ +int SetRsaExternal(WOLFSSL_RSA* rsa) +{ + RsaKey* key; + WOLFSSL_MSG("Entering SetRsaExternal"); + + if (rsa == NULL || rsa->internal == NULL) { + WOLFSSL_MSG("rsa key NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + key = (RsaKey*)rsa->internal; + + if (SetIndividualExternal(&rsa->n, &key->n) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa n key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&rsa->e, &key->e) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa e key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (key->type == RSA_PRIVATE) { + if (SetIndividualExternal(&rsa->d, &key->d) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa d key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&rsa->p, &key->p) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa p key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&rsa->q, &key->q) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa q key error"); + return WOLFSSL_FATAL_ERROR; + } + + #ifndef RSA_LOW_MEM + if (SetIndividualExternal(&rsa->dmp1, &key->dP) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa dP key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&rsa->dmq1, &key->dQ) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa dQ key error"); + return WOLFSSL_FATAL_ERROR; + } + + if (SetIndividualExternal(&rsa->iqmp, &key->u) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("rsa u key error"); + return WOLFSSL_FATAL_ERROR; + } + #endif /* !RSA_LOW_MEM */ + } + rsa->exSet = 1; + + return WOLFSSL_SUCCESS; +} +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* when calling SetIndividualExternal, mpi should be cleared by caller if no + * longer used. ie mp_free(mpi). This is to free data when fastmath is + * disabled since a copy of mpi is made by this function and placed into bn. + */ +int SetIndividualExternal(WOLFSSL_BIGNUM** bn, mp_int* mpi) +{ + byte dynamic = 0; + + WOLFSSL_MSG("Entering SetIndividualExternal"); + + if (mpi == NULL || bn == NULL) { + WOLFSSL_MSG("mpi NULL error"); + return WOLFSSL_FATAL_ERROR; + } + + if (*bn == NULL) { + *bn = wolfSSL_BN_new(); + if (*bn == NULL) { + WOLFSSL_MSG("SetIndividualExternal alloc failed"); + return WOLFSSL_FATAL_ERROR; + } + dynamic = 1; + } + + if (mp_copy(mpi, (mp_int*)((*bn)->internal)) != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + if (dynamic == 1) { + wolfSSL_BN_free(*bn); + } + return WOLFSSL_FATAL_ERROR; + } + + return WOLFSSL_SUCCESS; +} + + +static void InitwolfSSL_BigNum(WOLFSSL_BIGNUM* bn) +{ + if (bn) { + XMEMSET(bn, 0, sizeof(WOLFSSL_BIGNUM)); + bn->neg = 0; + bn->internal = NULL; + } +} + + +WOLFSSL_BIGNUM* wolfSSL_BN_new(void) +{ + WOLFSSL_BIGNUM* external; + mp_int* mpi; + + WOLFSSL_MSG("wolfSSL_BN_new"); + +#if !defined(USE_FAST_MATH) || defined(HAVE_WOLF_BIGINT) + mpi = (mp_int*) XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (mpi == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new malloc mpi failure"); + return NULL; + } +#endif + + external = (WOLFSSL_BIGNUM*) XMALLOC(sizeof(WOLFSSL_BIGNUM), NULL, + DYNAMIC_TYPE_BIGINT); + if (external == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new malloc WOLFSSL_BIGNUM failure"); +#if !defined(USE_FAST_MATH) || defined(HAVE_WOLF_BIGINT) + XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT); +#endif + return NULL; + } + +#if defined(USE_FAST_MATH) && !defined(HAVE_WOLF_BIGINT) + mpi = &external->fp; +#endif + + InitwolfSSL_BigNum(external); + if (mp_init(mpi) != MP_OKAY) { + wolfSSL_BN_free(external); + return NULL; + } + external->internal = mpi; + + return external; +} + + +#if defined(USE_FAST_MATH) && !defined(HAVE_WOLF_BIGINT) +/* This function works without BN_free only with TFM */ +void wolfSSL_BN_init(WOLFSSL_BIGNUM* bn) +{ + if(bn == NULL)return; + WOLFSSL_MSG("wolfSSL_BN_init"); + InitwolfSSL_BigNum(bn); + if (mp_init(&bn->fp) != MP_OKAY) + return; + bn->internal = (void *)&bn->fp; +} +#endif + +void wolfSSL_BN_free(WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_free"); + if (bn) { + if (bn->internal) { + mp_int* bni = (mp_int*)bn->internal; + mp_free(bni); +#if !defined(USE_FAST_MATH) || defined(HAVE_WOLF_BIGINT) + XFREE(bn->internal, NULL, DYNAMIC_TYPE_BIGINT); +#endif + bn->internal = NULL; + } + XFREE(bn, NULL, DYNAMIC_TYPE_BIGINT); + /* bn = NULL, don't try to access or double free it */ + } +} + +void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_clear_free"); + if (bn) { + if (bn->internal) { + mp_int* bni = (mp_int*)bn->internal; + mp_forcezero(bni); + } + wolfSSL_BN_free(bn); + } +} + +void wolfSSL_BN_clear(WOLFSSL_BIGNUM* bn) +{ + WOLFSSL_MSG("wolfSSL_BN_clear"); + if (bn && bn->internal) { + mp_forcezero((mp_int*)bn->internal); + } +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if !defined(NO_RSA) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +static void InitwolfSSL_Rsa(WOLFSSL_RSA* rsa) +{ + if (rsa) { + XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA)); + } +} + + +void wolfSSL_RSA_free(WOLFSSL_RSA* rsa) +{ + WOLFSSL_ENTER("wolfSSL_RSA_free"); + + if (rsa) { +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + int doFree = 0; + if (wc_LockMutex(&rsa->refMutex) != 0) { + WOLFSSL_MSG("Couldn't lock rsa mutex"); + } + + /* only free if all references to it are done */ + rsa->refCount--; + if (rsa->refCount == 0) { + doFree = 1; + } + wc_UnLockMutex(&rsa->refMutex); + + if (!doFree) { + return; + } + + wc_FreeMutex(&rsa->refMutex); +#endif + + if (rsa->internal) { +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \ + !defined(HAVE_FAST_RSA) && defined(WC_RSA_BLINDING) + WC_RNG* rng; + + /* check if RNG is owned before freeing it */ + if (rsa->ownRng) { + rng = ((RsaKey*)rsa->internal)->rng; + if (rng != NULL && rng != &globalRNG) { + wc_FreeRng(rng); + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + } + } +#endif /* WC_RSA_BLINDING */ + wc_FreeRsaKey((RsaKey*)rsa->internal); + XFREE(rsa->internal, NULL, DYNAMIC_TYPE_RSA); + rsa->internal = NULL; + } + wolfSSL_BN_free(rsa->iqmp); + wolfSSL_BN_free(rsa->dmq1); + wolfSSL_BN_free(rsa->dmp1); + wolfSSL_BN_free(rsa->q); + wolfSSL_BN_free(rsa->p); + wolfSSL_BN_free(rsa->d); + wolfSSL_BN_free(rsa->e); + wolfSSL_BN_free(rsa->n); + + #ifdef WC_RSA_BLINDING + if (rsa->rng && wc_FreeRng(rsa->rng) != 0) { + WOLFSSL_MSG("Issue freeing rng"); + } + XFREE(rsa->rng, NULL, DYNAMIC_TYPE_RNG); + #endif + +#if defined(OPENSSL_EXTRA) && !defined(WOLFCRYPT_ONLY) + if (rsa->meth) { + wolfSSL_RSA_meth_free(rsa->meth); + } +#endif + + InitwolfSSL_Rsa(rsa); /* set back to NULLs for safety */ + + XFREE(rsa, NULL, DYNAMIC_TYPE_RSA); + + /* rsa = NULL, don't try to access or double free it */ + } +} + +WOLFSSL_RSA* wolfSSL_RSA_new(void) +{ + WOLFSSL_RSA* external; + RsaKey* key; + + WOLFSSL_ENTER("wolfSSL_RSA_new"); + + key = (RsaKey*) XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_RSA_new malloc RsaKey failure"); + return NULL; + } + + external = (WOLFSSL_RSA*) XMALLOC(sizeof(WOLFSSL_RSA), NULL, + DYNAMIC_TYPE_RSA); + if (external == NULL) { + WOLFSSL_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure"); + XFREE(key, NULL, DYNAMIC_TYPE_RSA); + return NULL; + } + + InitwolfSSL_Rsa(external); + if (wc_InitRsaKey(key, NULL) != 0) { + WOLFSSL_MSG("InitRsaKey WOLFSSL_RSA failure"); + XFREE(external, NULL, DYNAMIC_TYPE_RSA); + XFREE(key, NULL, DYNAMIC_TYPE_RSA); + return NULL; + } + +#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \ + !defined(HAVE_FAST_RSA) && defined(WC_RSA_BLINDING) + { + WC_RNG* rng; + + rng = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (rng != NULL && wc_InitRng(rng) != 0) { + WOLFSSL_MSG("InitRng failure, attempting to use global RNG"); + XFREE(rng, NULL, DYNAMIC_TYPE_RNG); + rng = NULL; + } + + external->ownRng = 1; + if (rng == NULL && initGlobalRNG) { + external->ownRng = 0; + rng = &globalRNG; + } + + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_RSA_new no WC_RNG for blinding"); + XFREE(external, NULL, DYNAMIC_TYPE_RSA); + XFREE(key, NULL, DYNAMIC_TYPE_RSA); + return NULL; + } + + wc_RsaSetRNG(key, rng); + } +#else + XMEMSET(key, 0, sizeof(RsaKey)); +#endif /* WC_RSA_BLINDING */ + + external->internal = key; + external->inSet = 0; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + external->refCount = 1; + wc_InitMutex(&external->refMutex); +#endif + return external; +} +#endif /* !NO_RSA && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ + +#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) +PKCS7* wolfSSL_PKCS7_new(void) +{ + WOLFSSL_PKCS7* pkcs7; + int ret = 0; + + pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(*pkcs7), NULL, DYNAMIC_TYPE_PKCS7); + if (pkcs7 != NULL) { + XMEMSET(pkcs7, 0, sizeof(*pkcs7)); + ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID); + } + + if (ret != 0 && pkcs7 != NULL) + XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7); + + return (PKCS7*)pkcs7; +} +/****************************************************************************** +* wolfSSL_PKCS7_SIGNED_new - allocates PKCS7 and initialize it for a signed data +* +* RETURNS: +* returns pointer to the PKCS7 structure on success, otherwise returns NULL +*/ +PKCS7_SIGNED* wolfSSL_PKCS7_SIGNED_new(void) +{ + byte signedData[]= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}; + PKCS7* pkcs7 = NULL; + + if ((pkcs7 = wolfSSL_PKCS7_new()) == NULL) + return NULL; + pkcs7->contentOID = SIGNED_DATA; + if ((wc_PKCS7_SetContentType(pkcs7, signedData, sizeof(signedData))) < 0) { + if (pkcs7) { + wolfSSL_PKCS7_free(pkcs7); + return NULL; + } + } + return pkcs7; +} + +void wolfSSL_PKCS7_free(PKCS7* pkcs7) +{ + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + + if (p7 != NULL) { + if (p7->data != NULL) + XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); + wc_PKCS7_Free(&p7->pkcs7); + XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7); + } +} +void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7) +{ + wolfSSL_PKCS7_free(p7); + return; +} +PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len) +{ + WOLFSSL_PKCS7* pkcs7 = NULL; + word32 idx = 0; + + if (in == NULL) + return NULL; + + if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) + return NULL; + + if (GetSequence(*in, &idx, &pkcs7->len, len) < 0) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + pkcs7->len += idx; + + pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); + if (pkcs7->data == NULL) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + XMEMCPY(pkcs7->data, *in, pkcs7->len); + *in += pkcs7->len; + + if (p7 != NULL) + *p7 = (PKCS7*)pkcs7; + return (PKCS7*)pkcs7; +} + +PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7) +{ + WOLFSSL_PKCS7* pkcs7; + + if (bio == NULL) + return NULL; + + if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) + return NULL; + + pkcs7->len = wolfSSL_BIO_pending(bio); + pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); + if (pkcs7->data == NULL) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + + if (wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len) != pkcs7->len) { + wolfSSL_PKCS7_free((PKCS7*)pkcs7); + return NULL; + } + + if (p7 != NULL) + *p7 = (PKCS7*)pkcs7; + return (PKCS7*)pkcs7; +} + +int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs, + WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, + WOLFSSL_BIO* out, int flags) +{ + int ret = 0; + unsigned char* mem = NULL; + int memSz = 0; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + + if (pkcs7 == NULL) + return WOLFSSL_FAILURE; + + if (in != NULL) { + if ((memSz = wolfSSL_BIO_get_mem_data(in, &mem)) < 0) + return WOLFSSL_FAILURE; + + p7->pkcs7.content = mem; + p7->pkcs7.contentSz = memSz; + } + + /* certs is the list of certificates to find the cert with issuer/serial. */ + (void)certs; + /* store is the certificate store to use to verify signer certificate + * associated with the signers. + */ + (void)store; + + ret = wc_PKCS7_VerifySignedData_ex(&p7->pkcs7, NULL, 0, p7->data, p7->len, + NULL, 0); + if (ret != 0) + return WOLFSSL_FAILURE; + + if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) { + /* All signer certificates are verified. */ + return WOLFSSL_FAILURE; + } + + if (out != NULL) + wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz); + + return WOLFSSL_SUCCESS; +} + +WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs, + int flags) +{ + WOLFSSL_STACK* signers = NULL; + WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + + if (p7 == NULL) + return NULL; + /* Only PKCS#7 messages with a single cert that is the verifying certificate + * is supported. + */ + if ((flags | PKCS7_NOINTERN) == PKCS7_NOINTERN) + return NULL; + + signers = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_X509); + if (signers == NULL) + return NULL; + + signers->num = 1; + signers->data.x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + if (signers->data.x509 == NULL) { + XFREE(signers, NULL, DYNAMIC_TYPE_X509); + return NULL; + } + + if (DecodeToX509(signers->data.x509, p7->pkcs7.singleCert, + p7->pkcs7.singleCertSz) != 0) { + XFREE(signers->data.x509, NULL, DYNAMIC_TYPE_X509); + XFREE(signers, NULL, DYNAMIC_TYPE_X509); + return NULL; + } + + (void)certs; + + return signers; +} + +/****************************************************************************** +* wolfSSL_PEM_write_bio_PKCS7 - writes the PKCS7 data to BIO +* +* RETURNS: +* returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE +*/ + +int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) +{ +#ifdef WOLFSSL_SMALL_STACK + byte* outputHead; + byte* outputFoot; +#else + byte outputHead[2048]; + byte outputFoot[2048]; +#endif + word32 outputHeadSz = 2048; + word32 outputFootSz = 2048; + word32 outputSz = 0; + byte* output = NULL; + byte* pem = NULL; + int pemSz = -1; + enum wc_HashType hashType; + byte hashBuf[WC_MAX_DIGEST_SIZE]; + word32 hashSz = -1; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PKCS7()"); + + if (bio == NULL || p7 == NULL) + return WOLFSSL_FAILURE; + +#ifdef WOLFSSL_SMALL_STACK + outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (outputHead == NULL) + return MEMORY_E; + + outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (outputFoot == NULL) + goto error; + +#endif + + XMEMSET(hashBuf, 0, WC_MAX_DIGEST_SIZE); + XMEMSET(outputHead, 0, outputHeadSz); + XMEMSET(outputFoot, 0, outputFootSz); + + hashType = wc_OidGetHash(p7->hashOID); + hashSz = wc_HashGetDigestSize(hashType); + if (hashSz > WC_MAX_DIGEST_SIZE) + return WOLFSSL_FAILURE; + + /* only SIGNED_DATA is supported */ + switch (p7->contentOID) { + case SIGNED_DATA: + break; + default: + WOLFSSL_MSG("Unknown PKCS#7 Type"); + return WOLFSSL_FAILURE; + }; + + if ((wc_PKCS7_EncodeSignedData_ex(p7, hashBuf, hashSz, + outputHead, &outputHeadSz, outputFoot, &outputFootSz)) != 0) + return WOLFSSL_FAILURE; + + outputSz = outputHeadSz + p7->contentSz + outputFootSz; + output = (byte*)XMALLOC(outputSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + + if (!output) + return WOLFSSL_FAILURE; + + XMEMSET(output, 0, outputSz); + outputSz = 0; + XMEMCPY(&output[outputSz], outputHead, outputHeadSz); + outputSz += outputHeadSz; + XMEMCPY(&output[outputSz], p7->content, p7->contentSz); + outputSz += p7->contentSz; + XMEMCPY(&output[outputSz], outputFoot, outputFootSz); + outputSz += outputFootSz; + + /* get PEM size */ + pemSz = wc_DerToPemEx(output, outputSz, NULL, 0, NULL, CERT_TYPE); + if (pemSz < 0) + goto error; + + pemSz++; /* for '\0'*/ + + /* create PEM buffer and convert from DER to PEM*/ + if ((pem = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) + goto error; + + XMEMSET(pem, 0, pemSz); + + if (wc_DerToPemEx(output, outputSz, pem, pemSz, NULL, CERT_TYPE) < 0) { + goto error; + } + if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { + XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); +#ifdef WOLFSSL_SMALL_STACK + XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return WOLFSSL_SUCCESS; + } + +error: +#ifdef WOLFSSL_SMALL_STACK + if (outputHead) { + XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + if (outputFoot) { + XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + if (output) { + XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + if (pem) { + XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + return WOLFSSL_FAILURE; +} +#endif /* OPENSSL_ALL && HAVE_PKCS7 */ + +#if defined(OPENSSL_EXTRA) +WOLFSSL_STACK* wolfSSL_sk_X509_new(void) +{ + WOLFSSL_STACK* s = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, + DYNAMIC_TYPE_X509); + if (s != NULL) { + XMEMSET(s, 0, sizeof(*s)); + s->type = STACK_TYPE_X509; + } + + return s; +} +#endif + +#ifdef OPENSSL_ALL +int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY* pkey, + const WOLFSSL_EVP_CIPHER* enc, + char* passwd, int passwdSz, + pem_password_cb* cb, void* ctx) +{ + int ret = 0; + char password[NAME_SZ]; + byte* key = NULL; + word32 keySz; + byte* pem = NULL; + int pemSz; + int type = PKCS8_PRIVATEKEY_TYPE; + int algId; + const byte* curveOid; + word32 oidSz; + int encAlgId; + + if (bio == NULL || pkey == NULL) + return -1; + + keySz = pkey->pkey_sz + 128; + key = (byte*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (key == NULL) + ret = MEMORY_E; + + if (ret == 0 && enc != NULL && passwd == NULL) { + passwdSz = cb(password, sizeof(password), 1, ctx); + if (passwdSz < 0) + ret = WOLFSSL_FAILURE; + passwd = password; + } + + if (ret == 0 && enc != NULL) { + WC_RNG rng; + ret = wc_InitRng(&rng); + if (ret == 0) { + #ifndef NO_DES3 + if (enc == EVP_DES_CBC) + encAlgId = DESb; + else if (enc == EVP_DES_EDE3_CBC) + encAlgId = DES3b; + else + #endif + #if !defined(NO_AES) && defined(HAVE_AES_CBC) + #ifdef WOLFSSL_AES_256 + if (enc == EVP_AES_256_CBC) + encAlgId = AES256CBCb; + else + #endif + #endif + ret = -1; + if (ret == 0) { + ret = TraditionalEnc((byte*)pkey->pkey.ptr, pkey->pkey_sz, key, + &keySz, passwd, passwdSz, PKCS5, PBES2, + encAlgId, NULL, 0, WC_PKCS12_ITT_DEFAULT, + &rng, NULL); + if (ret > 0) { + keySz = ret; + ret = 0; + } + } + wc_FreeRng(&rng); + } + type = PKCS8_ENC_PRIVATEKEY_TYPE; + } + if (ret == 0 && enc == NULL) { + type = PKCS8_PRIVATEKEY_TYPE; + if (pkey->type == EVP_PKEY_EC) { + algId = ECDSAk; + ret = wc_ecc_get_oid(pkey->ecc->group->curve_oid, &curveOid, + &oidSz); + } + else { + algId = RSAk; + curveOid = NULL; + oidSz = 0; + } + + if (ret >= 0) { + ret = wc_CreatePKCS8Key(key, &keySz, (byte*)pkey->pkey.ptr, + pkey->pkey_sz, algId, curveOid, oidSz); + keySz = ret; + } + } + + if (password == passwd) + XMEMSET(password, 0, passwdSz); + + if (ret >= 0) { + pemSz = 2 * keySz + 2 * 64; + pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) + ret = MEMORY_E; + } + + if (ret >= 0) + ret = wc_DerToPemEx(key, keySz, pem, pemSz, NULL, type); + + if (key != NULL) + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret >= 0) { + if (wolfSSL_BIO_write(bio, pem, ret) != ret) + ret = -1; + } + + if (pem != NULL) + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret < 0 ? 0 : ret; + +} + +static int bio_get_data(WOLFSSL_BIO* bio, byte** data) +{ + int ret = 0; + byte* mem = NULL; +#ifndef NO_FILESYSTEM + long memSz; + XFILE file; + long curr; +#endif + + if ((ret = wolfSSL_BIO_pending(bio)) > 0) { + } +#ifndef NO_FILESYSTEM + else if (bio->type == WOLFSSL_BIO_FILE) { + if (wolfSSL_BIO_get_fp(bio, &file) != WOLFSSL_SUCCESS) + ret = BAD_FUNC_ARG; + if (ret == 0) { + curr = XFTELL(file); + if (curr < 0) { + ret = WOLFSSL_BAD_FILE; + } + if (XFSEEK(file, 0, XSEEK_END) != 0) + ret = WOLFSSL_BAD_FILE; + } + if (ret == 0) { + memSz = XFTELL(file); + if (memSz > MAX_WOLFSSL_FILE_SIZE || memSz < 0) { + ret = WOLFSSL_BAD_FILE; + } + } + if (ret == 0) { + memSz -= curr; + ret = (int)memSz; + if (XFSEEK(file, curr, SEEK_SET) != 0) + ret = WOLFSSL_BAD_FILE; + } + } +#endif + + if (ret > 0) { + mem = (byte*)XMALLOC(ret, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (mem == NULL) { + WOLFSSL_MSG("Memory error"); + ret = MEMORY_E; + } + if (ret >= 0) { + if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) { + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + ret = MEMORY_E; + mem = NULL; + } + } + } + + *data = mem; + + return ret; +} + +#ifndef NO_WOLFSSL_STUB +void wolfSSL_BIO_set_init(WOLFSSL_BIO* bio, int init) +{ + WOLFSSL_STUB("wolfSSL_BIO_set_init"); + (void)bio; + (void)init; +} + +void wolfSSL_BIO_set_shutdown(WOLFSSL_BIO* bio, int shut) +{ + WOLFSSL_STUB("wolfSSL_BIO_set_shutdown"); + (void)bio; + (void)shut; + +} +int wolfSSL_BIO_get_shutdown(WOLFSSL_BIO* bio) +{ + WOLFSSL_STUB("wolfSSL_BIO_get_shutdown"); + (void)bio; + return 0; +} +#endif /* NO_WOLFSSL_STUB */ + +void wolfSSL_BIO_clear_retry_flags(WOLFSSL_BIO* bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_clear_retry_flags"); + + if (bio) + bio->flags &= ~(WOLFSSL_BIO_FLAG_READ|WOLFSSL_BIO_FLAG_RETRY); +} + +int wolfSSL_BIO_should_retry(WOLFSSL_BIO *bio) +{ + int ret = 0; + if (bio != NULL) { + ret = (int)(bio->flags & WOLFSSL_BIO_FLAG_RETRY); + } + + return ret; +} + +/* DER data is PKCS#8 encrypted. */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** pkey, + pem_password_cb* cb, + void* ctx) +{ + int ret; + byte* der; + int len; + byte* p; + char password[NAME_SZ]; + int passwordSz; + word32 algId; + WOLFSSL_EVP_PKEY* key; + + if ((len = bio_get_data(bio, &der)) < 0) + return NULL; + + if (cb != NULL) { + passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); + if (passwordSz < 0) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + ret = ToTraditionalEnc(der, len, password, passwordSz, &algId); + if (ret < 0) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + XMEMSET(password, 0, passwordSz); + } + + p = der; + key = wolfSSL_d2i_PrivateKey_EVP(pkey, &p, len); + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return key; +} + +/* Detect which type of key it is before decoding. */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, + const unsigned char** pp, + long length) +{ + int ret; + WOLFSSL_EVP_PKEY* key = NULL; + const byte* der = *pp; + word32 idx = 0; + int len = 0; + word32 end = 0; + int cnt = 0; + int type; + word32 algId; + word32 keyLen = (word32)length; + + /* Take off PKCS#8 wrapper if found. */ + if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { + der += idx; + keyLen = len; + } + idx = 0; + len = 0; + + /* Use the number of elements in the outer sequence to determine key type. + */ + ret = GetSequence(der, &idx, &len, keyLen); + if (ret >= 0) { + end = idx + len; + while (ret >= 0 && idx < end) { + /* Skip type */ + idx++; + /* Get length and skip over - keeping count */ + len = 0; + ret = GetLength(der, &idx, &len, keyLen); + if (ret >= 0) { + if (idx + len > end) + ret = ASN_PARSE_E; + else { + idx += len; + cnt++; + } + } + } + } + + if (ret >= 0) { + /* ECC includes version, private[, curve][, public key] */ + if (cnt >= 2 && cnt <= 4) + type = EVP_PKEY_EC; + else + type = EVP_PKEY_RSA; + + key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen); + *pp = der; + } + + return key; +} +#endif + +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) +int wolfSSL_X509_set_subject_name(WOLFSSL_X509 *cert, WOLFSSL_X509_NAME *name) +{ + int i; + WOLFSSL_X509_NAME_ENTRY* ne; + + WOLFSSL_ENTER("X509_set_subject_name"); + if (cert == NULL || name == NULL) + return WOLFSSL_FAILURE; + + FreeX509Name(&cert->subject, cert->heap); + InitX509Name(&cert->subject, 0); + if (name->dynamicName) { + cert->subject.name = (char*)XMALLOC(name->sz, cert->heap, + DYNAMIC_TYPE_SUBJECT_CN); + if (cert->subject.name == NULL) + return WOLFSSL_FAILURE; + } + XMEMCPY(cert->subject.name, name->name, name->sz); + cert->subject.sz = name->sz; + + for (i = 0; i < 10; i++) { + ne = wolfSSL_X509_NAME_get_entry(name, i); + if (ne != NULL) + wolfSSL_X509_NAME_add_entry(&cert->subject, ne, i, 1); + } + cert->subject.x509 = cert; + cert->subject.name = cert->subject.fullName.fullName; + cert->subject.sz = cert->subject.fullName.fullNameLen; + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_X509_set_issuer_name(WOLFSSL_X509 *cert, WOLFSSL_X509_NAME *name) +{ + int i; + WOLFSSL_X509_NAME_ENTRY* ne; + + WOLFSSL_ENTER("X509_set_issuer_name"); + if (cert == NULL || name == NULL) + return WOLFSSL_FAILURE; + + FreeX509Name(&cert->issuer, cert->heap); + InitX509Name(&cert->issuer, 0); + if (name->dynamicName) { + cert->issuer.name = (char*)XMALLOC(name->sz, cert->heap, + DYNAMIC_TYPE_SUBJECT_CN); + if (cert->issuer.name == NULL) + return WOLFSSL_FAILURE; + } + XMEMCPY(cert->issuer.name, name->name, name->sz); + cert->issuer.sz = name->sz; + + for (i = 0; i < 10; i++) { + ne = wolfSSL_X509_NAME_get_entry(name, i); + if (ne != NULL) + wolfSSL_X509_NAME_add_entry(&cert->issuer, ne, i, 1); + } + cert->issuer.x509 = cert; + cert->issuer.name = cert->issuer.fullName.fullName; + cert->issuer.sz = cert->issuer.fullName.fullNameLen; + cert->issuerSet = 1; + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_X509_set_notAfter(WOLFSSL_X509* x509, const WOLFSSL_ASN1_TIME* t) +{ + if (x509 == NULL || t == NULL) { + return WOLFSSL_FAILURE; + } + + XMEMCPY(&x509->notAfter, t, sizeof(WOLFSSL_ASN1_TIME)); + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_X509_set_notBefore(WOLFSSL_X509* x509, const WOLFSSL_ASN1_TIME* t) +{ + if (x509 == NULL || t == NULL) { + return WOLFSSL_FAILURE; + } + + XMEMCPY(&x509->notBefore, t, sizeof(WOLFSSL_ASN1_TIME)); + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_X509_set_serialNumber(WOLFSSL_X509* x509, WOLFSSL_ASN1_INTEGER* s) +{ + WOLFSSL_ENTER("wolfSSL_X509_set_serialNumber"); + if (!x509 || !s || s->dataMax >= EXTERNAL_SERIAL_SIZE) + return WOLFSSL_FAILURE; + + if (s->isDynamic) + XSTRNCPY((char*)x509->serial,(char*)s->data,s->dataMax); + else + XSTRNCPY((char*)x509->serial,(char*)s->intData,s->dataMax); + + x509->serial[s->dataMax] = 0; + x509->serialSz = s->dataMax; + + return WOLFSSL_SUCCESS; +} + + +int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey) +{ + byte* p; + WOLFSSL_ENTER("wolfSSL_X509_set_pubkey"); + + if (cert == NULL || pkey == NULL) + return WOLFSSL_FAILURE; + + if (pkey->type == EVP_PKEY_RSA) + cert->pubKeyOID = RSAk; + else if (pkey->type == EVP_PKEY_EC) + cert->pubKeyOID = ECDSAk; + else + return WOLFSSL_FAILURE; + + p = (byte*)XMALLOC(pkey->pkey_sz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (p == NULL) + return WOLFSSL_FAILURE; + + if (cert->pubKey.buffer != NULL) + XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + cert->pubKey.buffer = p; + XMEMCPY(cert->pubKey.buffer, pkey->pkey.ptr, pkey->pkey_sz); + cert->pubKey.length = pkey->pkey_sz; + + return WOLFSSL_SUCCESS; +} + +int wolfSSL_X509_set_version(WOLFSSL_X509* x509, long v) +{ + WOLFSSL_ENTER("wolfSSL_X509_set_version"); + if ((x509 == NULL) || (v < 0) || (v > INT_MAX)) { + return WOLFSSL_FAILURE; + } + x509->version = (int) v + 1; + + return WOLFSSL_SUCCESS; +} + +#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */ + +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) + +void wolfSSL_X509V3_set_ctx(WOLFSSL_X509V3_CTX* ctx, WOLFSSL_X509* issuer, + WOLFSSL_X509* subject, WOLFSSL_X509* req, WOLFSSL_X509_CRL* crl, + int flag) +{ + int ret = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_X509V3_set_ctx"); + if (!ctx || !ctx->x509) + return; + + /* Set parameters in ctx as long as ret == WOLFSSL_SUCCESS */ + if (issuer) + ret = wolfSSL_X509_set_issuer_name(ctx->x509,&issuer->issuer); + + if (subject && ret == WOLFSSL_SUCCESS) + ret = wolfSSL_X509_set_subject_name(ctx->x509,&subject->subject); + + if (req && ret == WOLFSSL_SUCCESS) { + WOLFSSL_MSG("req not implemented."); + } + + if (crl && ret == WOLFSSL_SUCCESS) { + WOLFSSL_MSG("crl not implemented."); + } + + if (flag && ret == WOLFSSL_SUCCESS) { + WOLFSSL_MSG("flag not implemented."); + } + + if (!ret) { + WOLFSSL_MSG("Error setting WOLFSSL_X509V3_CTX parameters."); + } +} + +int wolfSSL_i2d_X509_REQ(WOLFSSL_X509* req, unsigned char** out) +{ + const unsigned char* der; + int derSz = 0; + WOLFSSL_ENTER("wolfSSL_i2d_X509_REQ"); + + if (req == NULL || out == NULL) { + return BAD_FUNC_ARG; + } + + der = wolfSSL_X509_get_der(req, &derSz); + if (der == NULL) { + return MEMORY_E; + } + + if (*out == NULL) { + *out = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); + if (*out == NULL) { + return MEMORY_E; + } + } + + XMEMCPY(*out, der, derSz); + + return derSz; +} + +WOLFSSL_X509* wolfSSL_X509_REQ_new(void) +{ + return wolfSSL_X509_new(); +} + +void wolfSSL_X509_REQ_free(WOLFSSL_X509* req) +{ + wolfSSL_X509_free(req); +} + +int wolfSSL_X509_REQ_sign(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey, + const WOLFSSL_EVP_MD *md) +{ + byte der[2048]; + int derSz = sizeof(der); + + if (req == NULL || pkey == NULL || md == NULL) + return WOLFSSL_FAILURE; + + /* Create a Cert that has the certificate request fields. */ + req->sigOID = wolfSSL_sigTypeFromPKEY((WOLFSSL_EVP_MD*)md, pkey); + if (wolfSSL_X509_make_der(req, 1, der, &derSz) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + if (wolfSSL_X509_resign_cert(req, 1, der, sizeof(der), derSz, + (WOLFSSL_EVP_MD*)md, pkey) <= 0) { + return WOLFSSL_FAILURE; + } + return WOLFSSL_SUCCESS; +} + + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_X509_REQ_add_extensions(WOLFSSL_X509* req, + WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)* ext) +{ + (void)req; + (void)ext; + return WOLFSSL_FATAL_ERROR; +} +#endif + +int wolfSSL_X509_REQ_set_subject_name(WOLFSSL_X509 *req, + WOLFSSL_X509_NAME *name) +{ + return wolfSSL_X509_set_subject_name(req, name); +} + +int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey) +{ + return wolfSSL_X509_set_pubkey(req, pkey); +} +#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */ + + diff --git a/client/wolfssl/src/tls.c b/client/wolfssl/src/tls.c new file mode 100644 index 0000000..1b9858a --- /dev/null +++ b/client/wolfssl/src/tls.c @@ -0,0 +1,11755 @@ +/* tls.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY + +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#ifdef HAVE_CURVE25519 + #include +#endif +#ifdef HAVE_CURVE448 + #include +#endif +#ifdef HAVE_NTRU + #include "libntruencrypt/ntru_crypto.h" + #include +#endif + +#ifdef HAVE_QSH + static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key); + static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name); +#if defined(HAVE_NTRU) + static int TLSX_CreateNtruKey(WOLFSSL* ssl, int type); +#endif +#endif /* HAVE_QSH */ + +#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)) +static int TLSX_KeyShare_IsSupported(int namedGroup); +#endif + +#if ((!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \ + (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \ + && !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \ + ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES))) && \ + defined(HAVE_TLS_EXTENSIONS) +static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions); +#endif + + +#ifndef NO_TLS + +/* Digest enable checks */ +#ifdef NO_OLD_TLS /* TLS 1.2 only */ + #if defined(NO_SHA256) && !defined(WOLFSSL_SHA384) && \ + !defined(WOLFSSL_SHA512) + #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2 + #endif +#else /* TLS 1.1 or older */ + #if defined(NO_MD5) && defined(NO_SHA) + #error Must have SHA1 and MD5 enabled for old TLS + #endif +#endif + +#ifdef WOLFSSL_TLS13 + #if !defined(NO_DH) && \ + !defined(HAVE_FFDHE_2048) && !defined(HAVE_FFDHE_3072) && \ + !defined(HAVE_FFDHE_4096) && !defined(HAVE_FFDHE_6144) && \ + !defined(HAVE_FFDHE_8192) + #error Please configure your TLS 1.3 DH key size using either: HAVE_FFDHE_2048, HAVE_FFDHE_3072, HAVE_FFDHE_4096, HAVE_FFDHE_6144 or HAVE_FFDHE_8192 + #endif + #if !defined(NO_RSA) && !defined(WC_RSA_PSS) + #error The build option WC_RSA_PSS is required for TLS 1.3 with RSA + #endif + #ifndef HAVE_TLS_EXTENSIONS + #ifndef _MSC_VER + #error "The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3" + #else + #pragma message("Error: The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3") + #endif + #endif +#endif + +/* Warn if secrets logging is enabled */ +#if defined(SHOW_SECRETS) || defined(WOLFSSL_SSLKEYLOGFILE) + #ifndef _MSC_VER + #warning The SHOW_SECRETS and WOLFSSL_SSLKEYLOGFILE options should only be used for debugging and never in a production environment + #else + #pragma message("Warning: The SHOW_SECRETS and WOLFSSL_SSLKEYLOGFILE options should only be used for debugging and never in a production environment") + #endif +#endif + +/* Optional Pre-Master-Secret logging for Wireshark */ +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE) +#ifndef WOLFSSL_SSLKEYLOGFILE_OUTPUT + #define WOLFSSL_SSLKEYLOGFILE_OUTPUT "sslkeylog.log" +#endif +#endif + +#ifndef WOLFSSL_NO_TLS12 + +#ifdef WOLFSSL_SHA384 + #define HSHASH_SZ WC_SHA384_DIGEST_SIZE +#else + #define HSHASH_SZ FINISHED_SZ +#endif + +#ifdef WOLFSSL_RENESAS_TSIP_TLS + int tsip_useable(const WOLFSSL *ssl); + int tsip_generateMasterSecret(const byte *pre, + const byte *cr,const byte *sr, + byte *ms/* out */); + int tsip_generateSeesionKey(WOLFSSL *ssl); + int tsip_generateVerifyData(const byte *ms, const byte *side, + const byte *handshake_hash, + byte *hashes /* out */); +#endif + +int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen) +{ + int ret = 0; + word32 hashSz = FINISHED_SZ; + + if (ssl == NULL || hash == NULL || hashLen == NULL || *hashLen < HSHASH_SZ) + return BAD_FUNC_ARG; + + /* for constant timing perform these even if error */ +#ifndef NO_OLD_TLS + ret |= wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash); + ret |= wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]); +#endif + + if (IsAtLeastTLSv1_2(ssl)) { +#ifndef NO_SHA256 + if (ssl->specs.mac_algorithm <= sha256_mac || + ssl->specs.mac_algorithm == blake2b_mac) { + ret |= wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + hashSz = WC_SHA256_DIGEST_SIZE; + } +#endif +#ifdef WOLFSSL_SHA384 + if (ssl->specs.mac_algorithm == sha384_mac) { + ret |= wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + hashSz = WC_SHA384_DIGEST_SIZE; + } +#endif + } + + *hashLen = hashSz; + + if (ret != 0) + ret = BUILD_MSG_ERROR; + + return ret; +} + + +int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) +{ + int ret; + const byte* side; + word32 hashSz = HSHASH_SZ; +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + DECLARE_VAR(handshake_hash, byte, HSHASH_SZ, ssl->heap); + if (handshake_hash == NULL) + return MEMORY_E; +#else + byte handshake_hash[HSHASH_SZ]; +#endif + + ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz); + if (ret == 0) { + if (XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) + side = tls_client; + else + side = tls_server; + +#ifdef WOLFSSL_HAVE_PRF +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) { + ret = tsip_generateVerifyData(ssl->arrays->tsip_masterSecret, + side, handshake_hash, (byte*)hashes /* out */); + } else +#endif + ret = wc_PRF_TLS((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret, + SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, + ssl->heap, ssl->devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)side; + (void)hashes; +#endif + } + +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(handshake_hash, ssl->heap); +#endif + + return ret; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifndef NO_OLD_TLS + +#ifdef WOLFSSL_ALLOW_TLSV10 +ProtocolVersion MakeTLSv1(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_MINOR; + + return pv; +} +#endif /* WOLFSSL_ALLOW_TLSV10 */ + + +ProtocolVersion MakeTLSv1_1(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_1_MINOR; + + return pv; +} + +#endif /* !NO_OLD_TLS */ + + +#ifndef WOLFSSL_NO_TLS12 + +ProtocolVersion MakeTLSv1_2(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_2_MINOR; + + return pv; +} + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef WOLFSSL_TLS13 +/* The TLS v1.3 protocol version. + * + * returns the protocol version data for TLS v1.3. + */ +ProtocolVersion MakeTLSv1_3(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_3_MINOR; + + return pv; +} +#endif + +#ifndef WOLFSSL_NO_TLS12 + +#ifdef HAVE_EXTENDED_MASTER +static const byte ext_master_label[EXT_MASTER_LABEL_SZ + 1] = + "extended master secret"; +#endif +static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret"; +static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion"; + +static int _DeriveTlsKeys(byte* key_dig, word32 key_dig_len, + const byte* ms, word32 msLen, + const byte* sr, const byte* cr, + int tls1_2, int hash_type, + void* heap, int devId) +{ + int ret; +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + DECLARE_VAR(seed, byte, SEED_LEN, heap); + if (seed == NULL) + return MEMORY_E; +#else + byte seed[SEED_LEN]; +#endif + + XMEMCPY(seed, sr, RAN_LEN); + XMEMCPY(seed + RAN_LEN, cr, RAN_LEN); + +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ, + seed, SEED_LEN, tls1_2, hash_type, heap, devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)key_dig; + (void)key_dig_len; + (void)ms; + (void)msLen; + (void)tls1_2; + (void)hash_type; + (void)heap; + (void)devId; + (void)key_label; + (void)master_label; +#ifdef HAVE_EXTENDED_MASTER + (void)ext_master_label; +#endif +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(seed, heap); +#endif + + return ret; +} + +/* External facing wrapper so user can call as well, 0 on success */ +int wolfSSL_DeriveTlsKeys(byte* key_dig, word32 key_dig_len, + const byte* ms, word32 msLen, + const byte* sr, const byte* cr, + int tls1_2, int hash_type) +{ + return _DeriveTlsKeys(key_dig, key_dig_len, ms, msLen, sr, cr, tls1_2, + hash_type, NULL, INVALID_DEVID); +} + + +int DeriveTlsKeys(WOLFSSL* ssl) +{ + int ret; + int key_dig_len = 2 * ssl->specs.hash_size + + 2 * ssl->specs.key_size + + 2 * ssl->specs.iv_size; +#ifdef WOLFSSL_SMALL_STACK + byte* key_dig; +#else + byte key_dig[MAX_PRF_DIG]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + key_dig = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST); + if (key_dig == NULL) { + return MEMORY_E; + } +#endif +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) + ret = tsip_generateSeesionKey(ssl); + else { +#endif + ret = _DeriveTlsKeys(key_dig, key_dig_len, + ssl->arrays->masterSecret, SECRET_LEN, + ssl->arrays->serverRandom, ssl->arrays->clientRandom, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, + ssl->heap, ssl->devId); + if (ret == 0) + ret = StoreKeys(ssl, key_dig, PROVISION_CLIENT_SERVER); +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + } +#endif + +#ifdef WOLFSSL_SMALL_STACK + XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); +#endif + + return ret; +} + +static int _MakeTlsMasterSecret(byte* ms, word32 msLen, + const byte* pms, word32 pmsLen, + const byte* cr, const byte* sr, + int tls1_2, int hash_type, + void* heap, int devId) +{ + int ret; +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + DECLARE_VAR(seed, byte, SEED_LEN, heap); + if (seed == NULL) + return MEMORY_E; +#else + byte seed[SEED_LEN]; +#endif + + XMEMCPY(seed, cr, RAN_LEN); + XMEMCPY(seed + RAN_LEN, sr, RAN_LEN); + +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ, + seed, SEED_LEN, tls1_2, hash_type, heap, devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)ms; + (void)msLen; + (void)pms; + (void)pmsLen; + (void)tls1_2; + (void)hash_type; + (void)heap; + (void)devId; +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(seed, heap); +#endif + + return ret; +} + +/* External facing wrapper so user can call as well, 0 on success */ +int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen, + const byte* pms, word32 pmsLen, + const byte* cr, const byte* sr, + int tls1_2, int hash_type) +{ + return _MakeTlsMasterSecret(ms, msLen, pms, pmsLen, cr, sr, tls1_2, + hash_type, NULL, INVALID_DEVID); +} + + +#ifdef HAVE_EXTENDED_MASTER + +static int _MakeTlsExtendedMasterSecret(byte* ms, word32 msLen, + const byte* pms, word32 pmsLen, + const byte* sHash, word32 sHashLen, + int tls1_2, int hash_type, + void* heap, int devId) +{ + int ret; + +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, ext_master_label, EXT_MASTER_LABEL_SZ, + sHash, sHashLen, tls1_2, hash_type, heap, devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)ms; + (void)msLen; + (void)pms; + (void)pmsLen; + (void)sHash; + (void)sHashLen; + (void)tls1_2; + (void)hash_type; + (void)heap; + (void)devId; +#endif + return ret; +} + +/* External facing wrapper so user can call as well, 0 on success */ +int wolfSSL_MakeTlsExtendedMasterSecret(byte* ms, word32 msLen, + const byte* pms, word32 pmsLen, + const byte* sHash, word32 sHashLen, + int tls1_2, int hash_type) +{ + return _MakeTlsExtendedMasterSecret(ms, msLen, pms, pmsLen, sHash, sHashLen, + tls1_2, hash_type, NULL, INVALID_DEVID); +} + +#endif /* HAVE_EXTENDED_MASTER */ + + +int MakeTlsMasterSecret(WOLFSSL* ssl) +{ + int ret; + +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + word32 hashSz = HSHASH_SZ; + #ifdef WOLFSSL_SMALL_STACK + byte* handshake_hash = (byte*)XMALLOC(HSHASH_SZ, ssl->heap, + DYNAMIC_TYPE_DIGEST); + if (handshake_hash == NULL) + return MEMORY_E; + #else + byte handshake_hash[HSHASH_SZ]; + #endif + + ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz); + if (ret == 0) { + ret = _MakeTlsExtendedMasterSecret( + ssl->arrays->masterSecret, SECRET_LEN, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + handshake_hash, hashSz, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, + ssl->heap, ssl->devId); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST); + #endif + } + else +#endif /* HAVE_EXTENDED_MASTER */ + { +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) { + ret = tsip_generateMasterSecret( + &ssl->arrays->preMasterSecret[VERSION_SZ], + ssl->arrays->clientRandom, + ssl->arrays->serverRandom, + ssl->arrays->tsip_masterSecret); + } else +#endif + ret = _MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + ssl->arrays->clientRandom, ssl->arrays->serverRandom, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, + ssl->heap, ssl->devId); + } + if (ret == 0) { + #ifdef SHOW_SECRETS + /* Wireshark Pre-Master-Secret Format: + * CLIENT_RANDOM + */ + const char* CLIENT_RANDOM_LABEL = "CLIENT_RANDOM"; + int i, pmsPos = 0; + char pmsBuf[13 + 1 + 64 + 1 + 96 + 1 + 1]; + + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%s ", + CLIENT_RANDOM_LABEL); + pmsPos += XSTRLEN(CLIENT_RANDOM_LABEL) + 1; + for (i = 0; i < RAN_LEN; i++) { + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x", + ssl->arrays->clientRandom[i]); + pmsPos += 2; + } + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, " "); + pmsPos += 1; + for (i = 0; i < SECRET_LEN; i++) { + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x", + ssl->arrays->masterSecret[i]); + pmsPos += 2; + } + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "\n"); + pmsPos += 1; + + /* print master secret */ + puts(pmsBuf); + + #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE) + { + FILE* f = XFOPEN(WOLFSSL_SSLKEYLOGFILE_OUTPUT, "a"); + if (f != XBADFILE) { + XFWRITE(pmsBuf, 1, pmsPos, f); + XFCLOSE(f); + } + } + #endif + #endif /* SHOW_SECRETS */ + + ret = DeriveTlsKeys(ssl); + } + + return ret; +} + + +/* Used by EAP-TLS and EAP-TTLS to derive keying material from + * the master_secret. */ +int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len, + const char* label) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + byte* seed; +#else + byte seed[SEED_LEN]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + seed = (byte*)XMALLOC(SEED_LEN, ssl->heap, DYNAMIC_TYPE_SEED); + if (seed == NULL) + return MEMORY_E; +#endif + + /* + * As per RFC-5281, the order of the client and server randoms is reversed + * from that used by the TLS protocol to derive keys. + */ + XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); + XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); + +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN, + (const byte *)label, (word32)XSTRLEN(label), seed, SEED_LEN, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, + ssl->heap, ssl->devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)msk; + (void)len; + (void)label; +#endif + +#ifdef WOLFSSL_SMALL_STACK + XFREE(seed, ssl->heap, DYNAMIC_TYPE_SEED); +#endif + + return ret; +} + + +static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2]) +{ + if (verify) { + seq[0] = ssl->keys.peer_sequence_number_hi; + seq[1] = ssl->keys.peer_sequence_number_lo++; + if (seq[1] > ssl->keys.peer_sequence_number_lo) { + /* handle rollover */ + ssl->keys.peer_sequence_number_hi++; + } + } + else { + seq[0] = ssl->keys.sequence_number_hi; + seq[1] = ssl->keys.sequence_number_lo++; + if (seq[1] > ssl->keys.sequence_number_lo) { + /* handle rollover */ + ssl->keys.sequence_number_hi++; + } + } +} + + +#ifdef WOLFSSL_DTLS +static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2]) +{ + if (order == PREV_ORDER) { + /* Previous epoch case */ + seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) | + (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF); + seq[1] = ssl->keys.dtls_prev_sequence_number_lo; + } + else if (order == PEER_ORDER) { + seq[0] = ((word32)ssl->keys.curEpoch << 16) | + (ssl->keys.curSeq_hi & 0xFFFF); + seq[1] = ssl->keys.curSeq_lo; /* explicit from peer */ + } + else { + seq[0] = ((word32)ssl->keys.dtls_epoch << 16) | + (ssl->keys.dtls_sequence_number_hi & 0xFFFF); + seq[1] = ssl->keys.dtls_sequence_number_lo; + } +} +#endif /* WOLFSSL_DTLS */ + + +static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) +{ + word32 seq[2] = {0, 0}; + + if (!ssl->options.dtls) { + GetSEQIncrement(ssl, verifyOrder, seq); + } + else { +#ifdef WOLFSSL_DTLS + DtlsGetSEQ(ssl, verifyOrder, seq); +#endif + } + + c32toa(seq[0], out); + c32toa(seq[1], out + OPAQUE32_LEN); +} + + +/*** end copy ***/ + + +/* return HMAC digest type in wolfSSL format */ +int wolfSSL_GetHmacType(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (ssl->specs.mac_algorithm) { + #ifndef NO_MD5 + case md5_mac: + { + return WC_MD5; + } + #endif + #ifndef NO_SHA256 + case sha256_mac: + { + return WC_SHA256; + } + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + { + return WC_SHA384; + } + + #endif + #ifndef NO_SHA + case sha_mac: + { + return WC_SHA; + } + #endif + #ifdef HAVE_BLAKE2 + case blake2b_mac: + { + return BLAKE2B_ID; + } + #endif + default: + { + return WOLFSSL_FATAL_ERROR; + } + } +} + + +int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content, + int verify) +{ + if (ssl == NULL || inner == NULL) + return BAD_FUNC_ARG; + + XMEMSET(inner, 0, WOLFSSL_TLS_HMAC_INNER_SZ); + + WriteSEQ(ssl, verify, inner); + inner[SEQ_SZ] = (byte)content; + inner[SEQ_SZ + ENUM_LEN] = ssl->version.major; + inner[SEQ_SZ + ENUM_LEN + ENUM_LEN] = ssl->version.minor; + c16toa((word16)sz, inner + SEQ_SZ + ENUM_LEN + VERSION_SZ); + + return 0; +} + + +#ifndef WOLFSSL_AEAD_ONLY +#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + +/* Update the hash in the HMAC. + * + * hmac HMAC object. + * data Data to be hashed. + * sz Size of data to hash. + * returns 0 on success, otherwise failure. + */ +static int Hmac_HashUpdate(Hmac* hmac, const byte* data, word32 sz) +{ + int ret = BAD_FUNC_ARG; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_ShaUpdate(&hmac->hash.sha, data, sz); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_Sha256Update(&hmac->hash.sha256, data, sz); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_Sha384Update(&hmac->hash.sha384, data, sz); + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_Sha512Update(&hmac->hash.sha512, data, sz); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +/* Finalize the hash but don't put the EOC, padding or length in. + * + * hmac HMAC object. + * hash Hash result. + * returns 0 on success, otherwise failure. + */ +static int Hmac_HashFinalRaw(Hmac* hmac, unsigned char* hash) +{ + int ret = BAD_FUNC_ARG; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_ShaFinalRaw(&hmac->hash.sha, hash); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_Sha256FinalRaw(&hmac->hash.sha256, hash); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_Sha384FinalRaw(&hmac->hash.sha384, hash); + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_Sha512FinalRaw(&hmac->hash.sha512, hash); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +/* Finalize the HMAC by performing outer hash. + * + * hmac HMAC object. + * mac MAC result. + * returns 0 on success, otherwise failure. + */ +static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac) +{ + int ret = BAD_FUNC_ARG; + wc_HashAlg hash; + enum wc_HashType hashType = (enum wc_HashType)hmac->macType; + int digestSz = wc_HashGetDigestSize(hashType); + int blockSz = wc_HashGetBlockSize(hashType); + + if ((digestSz >= 0) && (blockSz >= 0)) { + ret = wc_HashInit(&hash, hashType); + } + if (ret == 0) { + ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->opad, + blockSz); + if (ret == 0) + ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->innerHash, + digestSz); + if (ret == 0) + ret = wc_HashFinal(&hash, hashType, mac); + wc_HashFree(&hash, hashType); + } + + return ret; +} + +/* Calculate the HMAC of the header + message data. + * Constant time implementation using wc_Sha*FinalRaw(). + * + * hmac HMAC object. + * digest MAC result. + * in Message data. + * sz Size of the message data. + * header Constructed record header with length of handshake data. + * returns 0 on success, otherwise failure. + */ +static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, + word32 sz, byte* header) +{ + byte lenBytes[8]; + int i, j, k; + int blockBits, blockMask; + int lastBlockLen, macLen, extraLen, eocIndex; + int blocks, safeBlocks, lenBlock, eocBlock; + int maxLen; + int blockSz, padSz; + int ret; + word32 realLen; + byte extraBlock; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + blockSz = WC_SHA_BLOCK_SIZE; + blockBits = 6; + macLen = WC_SHA_DIGEST_SIZE; + padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1; + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + blockSz = WC_SHA256_BLOCK_SIZE; + blockBits = 6; + macLen = WC_SHA256_DIGEST_SIZE; + padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1; + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + blockSz = WC_SHA384_BLOCK_SIZE; + blockBits = 7; + macLen = WC_SHA384_DIGEST_SIZE; + padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + blockSz = WC_SHA512_BLOCK_SIZE; + blockBits = 7; + macLen = WC_SHA512_DIGEST_SIZE; + padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA512 */ + + default: + return BAD_FUNC_ARG; + } + blockMask = blockSz - 1; + + /* Size of data to HMAC if padding length byte is zero. */ + maxLen = WOLFSSL_TLS_HMAC_INNER_SZ + sz - 1 - macLen; + /* Complete data (including padding) has block for EOC and/or length. */ + extraBlock = ctSetLTE((maxLen + padSz) & blockMask, padSz); + /* Total number of blocks for data including padding. */ + blocks = ((maxLen + blockSz - 1) >> blockBits) + extraBlock; + /* Up to last 6 blocks can be hashed safely. */ + safeBlocks = blocks - 6; + + /* Length of message data. */ + realLen = maxLen - in[sz - 1]; + /* Number of message bytes in last block. */ + lastBlockLen = realLen & blockMask; + /* Number of padding bytes in last block. */ + extraLen = ((blockSz * 2 - padSz - lastBlockLen) & blockMask) + 1; + /* Number of blocks to create for hash. */ + lenBlock = (realLen + extraLen) >> blockBits; + /* Block containing EOC byte. */ + eocBlock = realLen >> blockBits; + /* Index of EOC byte in block. */ + eocIndex = realLen & blockMask; + + /* Add length of hmac's ipad to total length. */ + realLen += blockSz; + /* Length as bits - 8 bytes bigendian. */ + c32toa(realLen >> ((sizeof(word32) * 8) - 3), lenBytes); + c32toa(realLen << 3, lenBytes + sizeof(word32)); + + ret = Hmac_HashUpdate(hmac, (unsigned char*)hmac->ipad, blockSz); + if (ret != 0) + return ret; + + XMEMSET(hmac->innerHash, 0, macLen); + + if (safeBlocks > 0) { + ret = Hmac_HashUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ); + if (ret != 0) + return ret; + ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz - + WOLFSSL_TLS_HMAC_INNER_SZ); + if (ret != 0) + return ret; + } + else + safeBlocks = 0; + + XMEMSET(digest, 0, macLen); + k = safeBlocks * blockSz; + for (i = safeBlocks; i < blocks; i++) { + unsigned char hashBlock[WC_MAX_BLOCK_SIZE]; + unsigned char isEocBlock = ctMaskEq(i, eocBlock); + unsigned char isOutBlock = ctMaskEq(i, lenBlock); + + for (j = 0; j < blockSz; j++, k++) { + unsigned char atEoc = ctMaskEq(j, eocIndex) & isEocBlock; + unsigned char pastEoc = ctMaskGT(j, eocIndex) & isEocBlock; + unsigned char b = 0; + + if (k < WOLFSSL_TLS_HMAC_INNER_SZ) + b = header[k]; + else if (k < maxLen) + b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ]; + + b = ctMaskSel(atEoc, 0x80, b); + b &= (unsigned char)~(word32)pastEoc; + b &= ((unsigned char)~(word32)isOutBlock) | isEocBlock; + + if (j >= blockSz - 8) { + b = ctMaskSel(isOutBlock, lenBytes[j - (blockSz - 8)], b); + } + + hashBlock[j] = b; + } + + ret = Hmac_HashUpdate(hmac, hashBlock, blockSz); + if (ret != 0) + return ret; + ret = Hmac_HashFinalRaw(hmac, hashBlock); + if (ret != 0) + return ret; + for (j = 0; j < macLen; j++) + ((unsigned char*)hmac->innerHash)[j] |= hashBlock[j] & isOutBlock; + } + + ret = Hmac_OuterHash(hmac, digest); + + return ret; +} + +#endif + +#if defined(WOLFSSL_NO_HASH_RAW) || defined(HAVE_FIPS) || \ + defined(HAVE_SELFTEST) || defined(HAVE_BLAKE2) + +/* Calculate the HMAC of the header + message data. + * Constant time implementation using normal hashing operations. + * Update-Final need to be constant time. + * + * hmac HMAC object. + * digest MAC result. + * in Message data. + * sz Size of the message data. + * header Constructed record header with length of handshake data. + * returns 0 on success, otherwise failure. + */ +static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in, + word32 sz, byte* header) +{ + byte dummy[WC_MAX_BLOCK_SIZE] = {0}; + int ret; + word32 msgSz, blockSz, macSz, padSz, maxSz, realSz; + word32 currSz, offset = 0; + int msgBlocks, blocks, blockBits; + int i; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + blockSz = WC_SHA_BLOCK_SIZE; + blockBits = 6; + macSz = WC_SHA_DIGEST_SIZE; + padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1; + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + blockSz = WC_SHA256_BLOCK_SIZE; + blockBits = 6; + macSz = WC_SHA256_DIGEST_SIZE; + padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1; + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + blockSz = WC_SHA384_BLOCK_SIZE; + blockBits = 7; + macSz = WC_SHA384_DIGEST_SIZE; + padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + blockSz = WC_SHA512_BLOCK_SIZE; + blockBits = 7; + macSz = WC_SHA512_DIGEST_SIZE; + padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA512 */ + + #ifdef HAVE_BLAKE2 + case WC_HASH_TYPE_BLAKE2B: + blockSz = BLAKE2B_BLOCKBYTES; + blockBits = 7; + macSz = BLAKE2B_256; + padSz = 0; + break; + #endif /* HAVE_BLAK2 */ + + default: + return BAD_FUNC_ARG; + } + + msgSz = sz - (1 + in[sz - 1] + macSz); + /* Make negative result 0 */ + msgSz &= ~(0 - (msgSz >> 31)); + realSz = WOLFSSL_TLS_HMAC_INNER_SZ + msgSz; + maxSz = WOLFSSL_TLS_HMAC_INNER_SZ + (sz - 1) - macSz; + + /* Calculate #blocks processed in HMAC for max and real data. */ + blocks = maxSz >> blockBits; + blocks += ((maxSz + padSz) % blockSz) < padSz; + msgBlocks = realSz >> blockBits; + /* #Extra blocks to process. */ + blocks -= msgBlocks + (((realSz + padSz) % blockSz) < padSz); + /* Calculate whole blocks. */ + msgBlocks--; + + ret = wc_HmacUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ); + if (ret == 0) { + /* Fill the rest of the block with any available data. */ + currSz = ctMaskLT(msgSz, blockSz) & msgSz; + currSz |= ctMaskGTE(msgSz, blockSz) & blockSz; + currSz -= WOLFSSL_TLS_HMAC_INNER_SZ; + currSz &= ~(0 - (currSz >> 31)); + ret = wc_HmacUpdate(hmac, in, currSz); + offset = currSz; + } + if (ret == 0) { + /* Do the hash operations on a block basis. */ + for (i = 0; i < msgBlocks; i++, offset += blockSz) { + ret = wc_HmacUpdate(hmac, in + offset, blockSz); + if (ret != 0) + break; + } + } + if (ret == 0) + ret = wc_HmacUpdate(hmac, in + offset, msgSz - offset); + if (ret == 0) + ret = wc_HmacFinal(hmac, digest); + if (ret == 0) { + /* Do the dummy hash operations. Do at least one. */ + for (i = 0; i < blocks + 1; i++) { + ret = wc_HmacUpdate(hmac, dummy, blockSz); + if (ret != 0) + break; + } + } + + return ret; +} + +#endif + +int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, + int content, int verify) +{ + Hmac hmac; + byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ]; + int ret = 0; +#ifdef HAVE_TRUNCATED_HMAC + word32 hashSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 hashSz = ssl->specs.hash_size; +#endif + + if (ssl == NULL) + return BAD_FUNC_ARG; + +#ifdef HAVE_FUZZER + /* Fuzz "in" buffer with sz to be used in HMAC algorithm */ + if (ssl->fuzzerCb) { + if (verify && padSz >= 0) { + ssl->fuzzerCb(ssl, in, sz + hashSz + padSz + 1, FUZZ_HMAC, + ssl->fuzzerCtx); + } + else { + ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx); + } + } +#endif + + wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify); +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ + !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION) + if (tsip_useable(ssl)) { + if (ssl->specs.hash_size == WC_SHA_DIGEST_SIZE) + ret = tsip_Sha1Hmac(ssl, myInner, WOLFSSL_TLS_HMAC_INNER_SZ, + in, sz, digest, verify); + else if (ssl->specs.hash_size == WC_SHA256_DIGEST_SIZE) + ret = tsip_Sha256Hmac(ssl, myInner, WOLFSSL_TLS_HMAC_INNER_SZ, + in, sz, digest, verify); + else + ret = TSIP_MAC_DIGSZ_E; + + return ret; + } +#endif + ret = wc_HmacInit(&hmac, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + + ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), + wolfSSL_GetMacSecret(ssl, verify), + ssl->specs.hash_size); + if (ret == 0) { + /* Constant time verification required. */ + if (verify && padSz >= 0) { +#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + #ifdef HAVE_BLAKE2 + if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) { + ret = Hmac_UpdateFinal(&hmac, digest, in, + sz + hashSz + padSz + 1, myInner); + } + else + #endif + { + ret = Hmac_UpdateFinal_CT(&hmac, digest, in, + sz + hashSz + padSz + 1, myInner); + } +#else + ret = Hmac_UpdateFinal(&hmac, digest, in, sz + hashSz + padSz + 1, + myInner); +#endif + } + else { + ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner)); + if (ret == 0) + ret = wc_HmacUpdate(&hmac, in, sz); /* content */ + if (ret == 0) + ret = wc_HmacFinal(&hmac, digest); + } + } + + wc_HmacFree(&hmac); + + return ret; +} +#endif /* WOLFSSL_AEAD_ONLY */ + +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef HAVE_TLS_EXTENSIONS + +/** + * The TLSX semaphore is used to calculate the size of the extensions to be sent + * from one peer to another. + */ + +/** Supports up to 64 flags. Increase as needed. */ +#define SEMAPHORE_SIZE 8 + +/** + * Converts the extension type (id) to an index in the semaphore. + * + * Official reference for TLS extension types: + * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml + * + * Motivation: + * Previously, we used the extension type itself as the index of that + * extension in the semaphore as the extension types were declared + * sequentially, but maintain a semaphore as big as the number of available + * extensions is no longer an option since the release of renegotiation_info. + * + * How to update: + * Assign extension types that extrapolate the number of available semaphores + * to the first available index going backwards in the semaphore array. + * When adding a new extension type that don't extrapolate the number of + * available semaphores, check for a possible collision with with a + * 'remapped' extension type. + */ +static WC_INLINE word16 TLSX_ToSemaphore(word16 type) +{ + switch (type) { + + case TLSX_RENEGOTIATION_INFO: /* 0xFF01 */ + return 63; + + default: + if (type > 62) { + /* This message SHOULD only happens during the adding of + new TLS extensions in which its IANA number overflows + the current semaphore's range, or if its number already + is assigned to be used by another extension. + Use this check value for the new extension and decrement + the check value by one. */ + WOLFSSL_MSG("### TLSX semaphore collision or overflow detected!"); + } + } + + return type; +} + +/** Checks if a specific light (tls extension) is not set in the semaphore. */ +#define IS_OFF(semaphore, light) \ + (!(((semaphore)[(light) / 8] & (byte) (0x01 << ((light) % 8))))) + +/** Turn on a specific light (tls extension) in the semaphore. */ +/* the semaphore marks the extensions already written to the message */ +#define TURN_ON(semaphore, light) \ + ((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8))) + +/** Turn off a specific light (tls extension) in the semaphore. */ +#define TURN_OFF(semaphore, light) \ + ((semaphore)[(light) / 8] &= (byte) ~(0x01 << ((light) % 8))) + +/** Creates a new extension. */ +static TLSX* TLSX_New(TLSX_Type type, void* data, void* heap) +{ + TLSX* extension = (TLSX*)XMALLOC(sizeof(TLSX), heap, DYNAMIC_TYPE_TLSX); + + (void)heap; + + if (extension) { + extension->type = type; + extension->data = data; + extension->resp = 0; + extension->next = NULL; + } + + return extension; +} + +/** + * Creates a new extension and pushes it to the provided list. + * Checks for duplicate extensions, keeps the newest. + */ +static int TLSX_Push(TLSX** list, TLSX_Type type, void* data, void* heap) +{ + TLSX* extension = TLSX_New(type, data, heap); + + if (extension == NULL) + return MEMORY_E; + + /* pushes the new extension on the list. */ + extension->next = *list; + *list = extension; + + /* remove duplicate extensions, there should be only one of each type. */ + do { + if (extension->next && extension->next->type == type) { + TLSX *next = extension->next; + + extension->next = next->next; + next->next = NULL; + + TLSX_FreeAll(next, heap); + + /* there is no way to occur more than + * two extensions of the same type. + */ + break; + } + } while ((extension = extension->next)); + + return 0; +} + +#ifndef NO_WOLFSSL_CLIENT + +int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type); + +int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type) +{ + TLSX *extension = TLSX_Find(ssl->extensions, type); + + if (!extension) + extension = TLSX_Find(ssl->ctx->extensions, type); + + return extension == NULL; +} + +int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl); + +int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl) +{ + SendAlert(ssl, alert_fatal, unsupported_extension); + return UNSUPPORTED_EXTENSION; +} + +#else + +#define TLSX_CheckUnsupportedExtension(ssl, type) 0 +#define TLSX_HandleUnsupportedExtension(ssl) 0 + +#endif + +/** Mark an extension to be sent back to the client. */ +void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type); + +void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type) +{ + TLSX *extension = TLSX_Find(ssl->extensions, type); + + if (extension) + extension->resp = 1; +} + +/******************************************************************************/ +/* Application-Layer Protocol Negotiation */ +/******************************************************************************/ + +#ifdef HAVE_ALPN +/** Creates a new ALPN object, providing protocol name to use. */ +static ALPN* TLSX_ALPN_New(char *protocol_name, word16 protocol_nameSz, + void* heap) +{ + ALPN *alpn; + + WOLFSSL_ENTER("TLSX_ALPN_New"); + + if (protocol_name == NULL || + protocol_nameSz > WOLFSSL_MAX_ALPN_PROTO_NAME_LEN) { + WOLFSSL_MSG("Invalid arguments"); + return NULL; + } + + alpn = (ALPN*)XMALLOC(sizeof(ALPN), heap, DYNAMIC_TYPE_TLSX); + if (alpn == NULL) { + WOLFSSL_MSG("Memory failure"); + return NULL; + } + + alpn->next = NULL; + alpn->negotiated = 0; + alpn->options = 0; + + alpn->protocol_name = (char*)XMALLOC(protocol_nameSz + 1, + heap, DYNAMIC_TYPE_TLSX); + if (alpn->protocol_name == NULL) { + WOLFSSL_MSG("Memory failure"); + XFREE(alpn, heap, DYNAMIC_TYPE_TLSX); + return NULL; + } + + XMEMCPY(alpn->protocol_name, protocol_name, protocol_nameSz); + alpn->protocol_name[protocol_nameSz] = 0; + + (void)heap; + + return alpn; +} + +/** Releases an ALPN object. */ +static void TLSX_ALPN_Free(ALPN *alpn, void* heap) +{ + (void)heap; + + if (alpn == NULL) + return; + + XFREE(alpn->protocol_name, heap, DYNAMIC_TYPE_TLSX); + XFREE(alpn, heap, DYNAMIC_TYPE_TLSX); +} + +/** Releases all ALPN objects in the provided list. */ +static void TLSX_ALPN_FreeAll(ALPN *list, void* heap) +{ + ALPN* alpn; + + while ((alpn = list)) { + list = alpn->next; + TLSX_ALPN_Free(alpn, heap); + } +} + +/** Tells the buffered size of the ALPN objects in a list. */ +static word16 TLSX_ALPN_GetSize(ALPN *list) +{ + ALPN* alpn; + word16 length = OPAQUE16_LEN; /* list length */ + + while ((alpn = list)) { + list = alpn->next; + + length++; /* protocol name length is on one byte */ + length += (word16)XSTRLEN(alpn->protocol_name); + } + + return length; +} + +/** Writes the ALPN objects of a list in a buffer. */ +static word16 TLSX_ALPN_Write(ALPN *list, byte *output) +{ + ALPN* alpn; + word16 length = 0; + word16 offset = OPAQUE16_LEN; /* list length offset */ + + while ((alpn = list)) { + list = alpn->next; + + length = (word16)XSTRLEN(alpn->protocol_name); + + /* protocol name length */ + output[offset++] = (byte)length; + + /* protocol name value */ + XMEMCPY(output + offset, alpn->protocol_name, length); + + offset += length; + } + + /* writing list length */ + c16toa(offset - OPAQUE16_LEN, output); + + return offset; +} + +/** Finds a protocol name in the provided ALPN list */ +static ALPN* TLSX_ALPN_Find(ALPN *list, char *protocol_name, word16 size) +{ + ALPN *alpn; + + if (list == NULL || protocol_name == NULL) + return NULL; + + alpn = list; + while (alpn != NULL && ( + (word16)XSTRLEN(alpn->protocol_name) != size || + XSTRNCMP(alpn->protocol_name, protocol_name, size))) + alpn = alpn->next; + + return alpn; +} + +/** Set the ALPN matching client and server requirements */ +static int TLSX_SetALPN(TLSX** extensions, const void* data, word16 size, + void* heap) +{ + ALPN *alpn; + int ret; + + if (extensions == NULL || data == NULL) + return BAD_FUNC_ARG; + + alpn = TLSX_ALPN_New((char *)data, size, heap); + if (alpn == NULL) { + WOLFSSL_MSG("Memory failure"); + return MEMORY_E; + } + + alpn->negotiated = 1; + + ret = TLSX_Push(extensions, TLSX_APPLICATION_LAYER_PROTOCOL, (void*)alpn, + heap); + if (ret != 0) { + TLSX_ALPN_Free(alpn, heap); + return ret; + } + + return WOLFSSL_SUCCESS; +} + +/** Parses a buffer of ALPN extensions and set the first one matching + * client and server requirements */ +static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, byte *input, word16 length, + byte isRequest) +{ + word16 size = 0, offset = 0, idx = 0; + int r = BUFFER_ERROR; + byte match = 0; + TLSX *extension; + ALPN *alpn = NULL, *list; + + if (OPAQUE16_LEN > length) + return BUFFER_ERROR; + + ato16(input, &size); + offset += OPAQUE16_LEN; + + if (size == 0) + return BUFFER_ERROR; + + extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL); + if (extension == NULL) + extension = TLSX_Find(ssl->ctx->extensions, + TLSX_APPLICATION_LAYER_PROTOCOL); + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + if (ssl->alpnSelect != NULL) { + const byte* out; + unsigned char outLen; + + if (ssl->alpnSelect(ssl, &out, &outLen, input + offset, size, + ssl->alpnSelectArg) == 0) { + WOLFSSL_MSG("ALPN protocol match"); + if (TLSX_UseALPN(&ssl->extensions, (char*)out, outLen, 0, ssl->heap) + == WOLFSSL_SUCCESS) { + if (extension == NULL) { + extension = TLSX_Find(ssl->extensions, + TLSX_APPLICATION_LAYER_PROTOCOL); + } + } + } + } +#endif + + if (extension == NULL || extension->data == NULL) { + return isRequest ? 0 + : TLSX_HandleUnsupportedExtension(ssl); + } + + /* validating alpn list length */ + if (length != OPAQUE16_LEN + size) + return BUFFER_ERROR; + + list = (ALPN*)extension->data; + + /* keep the list sent by client */ + if (isRequest) { + if (ssl->alpn_client_list != NULL) + XFREE(ssl->alpn_client_list, ssl->heap, DYNAMIC_TYPE_ALPN); + + ssl->alpn_client_list = (char *)XMALLOC(size, ssl->heap, + DYNAMIC_TYPE_ALPN); + if (ssl->alpn_client_list == NULL) + return MEMORY_ERROR; + } + + for (size = 0; offset < length; offset += size) { + + size = input[offset++]; + if (offset + size > length || size == 0) + return BUFFER_ERROR; + + if (isRequest) { + XMEMCPY(ssl->alpn_client_list+idx, (char*)input + offset, size); + idx += size; + ssl->alpn_client_list[idx++] = ','; + } + + if (!match) { + alpn = TLSX_ALPN_Find(list, (char*)input + offset, size); + if (alpn != NULL) { + WOLFSSL_MSG("ALPN protocol match"); + match = 1; + + /* skip reading other values if not required */ + if (!isRequest) + break; + } + } + } + + if (isRequest) + ssl->alpn_client_list[idx-1] = 0; + + if (!match) { + WOLFSSL_MSG("No ALPN protocol match"); + + /* do nothing if no protocol match between client and server and option + is set to continue (like OpenSSL) */ + if (list->options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) { + WOLFSSL_MSG("Continue on mismatch"); + return 0; + } + + SendAlert(ssl, alert_fatal, no_application_protocol); + return UNKNOWN_ALPN_PROTOCOL_NAME_E; + } + + /* set the matching negotiated protocol */ + r = TLSX_SetALPN(&ssl->extensions, + alpn->protocol_name, + (word16)XSTRLEN(alpn->protocol_name), + ssl->heap); + if (r != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("TLSX_UseALPN failed"); + return BUFFER_ERROR; + } + + /* reply to ALPN extension sent from client */ + if (isRequest) { +#ifndef NO_WOLFSSL_SERVER + TLSX_SetResponse(ssl, TLSX_APPLICATION_LAYER_PROTOCOL); +#endif + } + + return 0; +} + +/** Add a protocol name to the list of accepted usable ones */ +int TLSX_UseALPN(TLSX** extensions, const void* data, word16 size, byte options, + void* heap) +{ + ALPN *alpn; + TLSX *extension; + int ret; + + if (extensions == NULL || data == NULL) + return BAD_FUNC_ARG; + + alpn = TLSX_ALPN_New((char *)data, size, heap); + if (alpn == NULL) { + WOLFSSL_MSG("Memory failure"); + return MEMORY_E; + } + + /* Set Options of ALPN */ + alpn->options = options; + + extension = TLSX_Find(*extensions, TLSX_APPLICATION_LAYER_PROTOCOL); + if (extension == NULL) { + ret = TLSX_Push(extensions, TLSX_APPLICATION_LAYER_PROTOCOL, + (void*)alpn, heap); + if (ret != 0) { + TLSX_ALPN_Free(alpn, heap); + return ret; + } + } + else { + /* push new ALPN object to extension data. */ + alpn->next = (ALPN*)extension->data; + extension->data = (void*)alpn; + } + + return WOLFSSL_SUCCESS; +} + +/** Get the protocol name set by the server */ +int TLSX_ALPN_GetRequest(TLSX* extensions, void** data, word16 *dataSz) +{ + TLSX *extension; + ALPN *alpn; + + if (extensions == NULL || data == NULL || dataSz == NULL) + return BAD_FUNC_ARG; + + extension = TLSX_Find(extensions, TLSX_APPLICATION_LAYER_PROTOCOL); + if (extension == NULL) { + WOLFSSL_MSG("TLS extension not found"); + return WOLFSSL_ALPN_NOT_FOUND; + } + + alpn = (ALPN *)extension->data; + if (alpn == NULL) { + WOLFSSL_MSG("ALPN extension not found"); + *data = NULL; + *dataSz = 0; + return WOLFSSL_FATAL_ERROR; + } + + if (alpn->negotiated != 1) { + + /* consider as an error */ + if (alpn->options & WOLFSSL_ALPN_FAILED_ON_MISMATCH) { + WOLFSSL_MSG("No protocol match with peer -> Failed"); + return WOLFSSL_FATAL_ERROR; + } + + /* continue without negotiated protocol */ + WOLFSSL_MSG("No protocol match with peer -> Continue"); + return WOLFSSL_ALPN_NOT_FOUND; + } + + if (alpn->next != NULL) { + WOLFSSL_MSG("Only one protocol name must be accepted"); + return WOLFSSL_FATAL_ERROR; + } + + *data = alpn->protocol_name; + *dataSz = (word16)XSTRLEN((char*)*data); + + return WOLFSSL_SUCCESS; +} + +#define ALPN_FREE_ALL TLSX_ALPN_FreeAll +#define ALPN_GET_SIZE TLSX_ALPN_GetSize +#define ALPN_WRITE TLSX_ALPN_Write +#define ALPN_PARSE TLSX_ALPN_ParseAndSet + +#else /* HAVE_ALPN */ + +#define ALPN_FREE_ALL(list, heap) +#define ALPN_GET_SIZE(list) 0 +#define ALPN_WRITE(a, b) 0 +#define ALPN_PARSE(a, b, c, d) 0 + +#endif /* HAVE_ALPN */ + +/******************************************************************************/ +/* Server Name Indication */ +/******************************************************************************/ + +#ifdef HAVE_SNI + +/** Creates a new SNI object. */ +static SNI* TLSX_SNI_New(byte type, const void* data, word16 size, void* heap) +{ + SNI* sni = (SNI*)XMALLOC(sizeof(SNI), heap, DYNAMIC_TYPE_TLSX); + + (void)heap; + + if (sni) { + sni->type = type; + sni->next = NULL; + + #ifndef NO_WOLFSSL_SERVER + sni->options = 0; + sni->status = WOLFSSL_SNI_NO_MATCH; + #endif + + switch (sni->type) { + case WOLFSSL_SNI_HOST_NAME: + sni->data.host_name = (char*)XMALLOC(size + 1, heap, + DYNAMIC_TYPE_TLSX); + if (sni->data.host_name) { + XSTRNCPY(sni->data.host_name, (const char*)data, size); + sni->data.host_name[size] = '\0'; + } else { + XFREE(sni, heap, DYNAMIC_TYPE_TLSX); + sni = NULL; + } + break; + + default: /* invalid type */ + XFREE(sni, heap, DYNAMIC_TYPE_TLSX); + sni = NULL; + } + } + + return sni; +} + +/** Releases a SNI object. */ +static void TLSX_SNI_Free(SNI* sni, void* heap) +{ + if (sni) { + switch (sni->type) { + case WOLFSSL_SNI_HOST_NAME: + XFREE(sni->data.host_name, heap, DYNAMIC_TYPE_TLSX); + break; + } + + XFREE(sni, heap, DYNAMIC_TYPE_TLSX); + } + (void)heap; +} + +/** Releases all SNI objects in the provided list. */ +static void TLSX_SNI_FreeAll(SNI* list, void* heap) +{ + SNI* sni; + + while ((sni = list)) { + list = sni->next; + TLSX_SNI_Free(sni, heap); + } +} + +/** Tells the buffered size of the SNI objects in a list. */ +static word16 TLSX_SNI_GetSize(SNI* list) +{ + SNI* sni; + word16 length = OPAQUE16_LEN; /* list length */ + + while ((sni = list)) { + list = sni->next; + + length += ENUM_LEN + OPAQUE16_LEN; /* sni type + sni length */ + + switch (sni->type) { + case WOLFSSL_SNI_HOST_NAME: + length += (word16)XSTRLEN((char*)sni->data.host_name); + break; + } + } + + return length; +} + +/** Writes the SNI objects of a list in a buffer. */ +static word16 TLSX_SNI_Write(SNI* list, byte* output) +{ + SNI* sni; + word16 length = 0; + word16 offset = OPAQUE16_LEN; /* list length offset */ + + while ((sni = list)) { + list = sni->next; + + output[offset++] = sni->type; /* sni type */ + + switch (sni->type) { + case WOLFSSL_SNI_HOST_NAME: + length = (word16)XSTRLEN((char*)sni->data.host_name); + + c16toa(length, output + offset); /* sni length */ + offset += OPAQUE16_LEN; + + XMEMCPY(output + offset, sni->data.host_name, length); + + offset += length; + break; + } + } + + c16toa(offset - OPAQUE16_LEN, output); /* writing list length */ + + return offset; +} + +/** Finds a SNI object in the provided list. */ +static SNI* TLSX_SNI_Find(SNI *list, byte type) +{ + SNI* sni = list; + + while (sni && sni->type != type) + sni = sni->next; + + return sni; +} + +/** Sets the status of a SNI object. */ +static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME); + SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type); + + if (sni) + sni->status = status; +} + +/** Gets the status of a SNI object. */ +byte TLSX_SNI_Status(TLSX* extensions, byte type) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME); + SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type); + + if (sni) + return sni->status; + + return 0; +} + +/** Parses a buffer of SNI extensions. */ +static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ +#ifndef NO_WOLFSSL_SERVER + word16 size = 0; + word16 offset = 0; + int cacheOnly = 0; + SNI *sni = NULL; + byte type; + int matchStat; + byte matched; +#endif + + TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); + + if (!extension) + extension = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME); + + if (!isRequest) { + #ifndef NO_WOLFSSL_CLIENT + if (!extension || !extension->data) + return TLSX_HandleUnsupportedExtension(ssl); + + if (length > 0) + return BUFFER_ERROR; /* SNI response MUST be empty. */ + + /* This call enables wolfSSL_SNI_GetRequest() to be called in the + * client side to fetch the used SNI. It will only work if the SNI + * was set at the SSL object level. Right now we only support one + * name type, WOLFSSL_SNI_HOST_NAME, but in the future, the + * inclusion of other name types will turn this method inaccurate, + * as the extension response doesn't contains information of which + * name was accepted. + */ + TLSX_SNI_SetStatus(ssl->extensions, WOLFSSL_SNI_HOST_NAME, + WOLFSSL_SNI_REAL_MATCH); + + return 0; + #endif + } + +#ifndef NO_WOLFSSL_SERVER + if (!extension || !extension->data) { + #if defined(WOLFSSL_ALWAYS_KEEP_SNI) && !defined(NO_WOLFSSL_SERVER) + /* This will keep SNI even though TLSX_UseSNI has not been called. + * Enable it so that the received sni is available to functions + * that use a custom callback when SNI is received. + */ + + cacheOnly = 1; + WOLFSSL_MSG("Forcing SSL object to store SNI parameter"); + #else + /* Skipping, SNI not enabled at server side. */ + return 0; + #endif + } + + if (OPAQUE16_LEN > length) + return BUFFER_ERROR; + + ato16(input, &size); + offset += OPAQUE16_LEN; + + /* validating sni list length */ + if (length != OPAQUE16_LEN + size || size == 0) + return BUFFER_ERROR; + + /* SNI was badly specified and only one type is now recognized and allowed. + * Only one SNI value per type (RFC6066), so, no loop. */ + type = input[offset++]; + if (type != WOLFSSL_SNI_HOST_NAME) + return BUFFER_ERROR; + + if (offset + OPAQUE16_LEN > length) + return BUFFER_ERROR; + ato16(input + offset, &size); + offset += OPAQUE16_LEN; + + if (offset + size != length || size == 0) + return BUFFER_ERROR; + + if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type))) + return 0; /* not using this type of SNI. */ + +#ifdef WOLFSSL_TLS13 + /* Don't process the second ClientHello SNI extension if there + * was problems with the first. + */ + if (!cacheOnly && sni->status != 0) + return 0; +#endif + matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size && + XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0); + + if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) { + int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size, + ssl->heap); + if (r != WOLFSSL_SUCCESS) + return r; /* throws error. */ + + if (cacheOnly) { + WOLFSSL_MSG("Forcing storage of SNI, Fake match"); + matchStat = WOLFSSL_SNI_FORCE_KEEP; + } + else if (matched) { + WOLFSSL_MSG("SNI did match!"); + matchStat = WOLFSSL_SNI_REAL_MATCH; + } + else { + WOLFSSL_MSG("fake SNI match from ANSWER_ON_MISMATCH"); + matchStat = WOLFSSL_SNI_FAKE_MATCH; + } + + TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat); + + if(!cacheOnly) + TLSX_SetResponse(ssl, TLSX_SERVER_NAME); + } + else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) { + SendAlert(ssl, alert_fatal, unrecognized_name); + + return UNKNOWN_SNI_HOST_NAME_E; + } +#else + (void)input; +#endif + + return 0; +} + +static int TLSX_SNI_VerifyParse(WOLFSSL* ssl, byte isRequest) +{ + (void)ssl; + + if (isRequest) { + #ifndef NO_WOLFSSL_SERVER + TLSX* ctx_ext = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME); + TLSX* ssl_ext = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); + SNI* ctx_sni = ctx_ext ? (SNI*)ctx_ext->data : NULL; + SNI* ssl_sni = ssl_ext ? (SNI*)ssl_ext->data : NULL; + SNI* sni = NULL; + + for (; ctx_sni; ctx_sni = ctx_sni->next) { + if (ctx_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) { + sni = TLSX_SNI_Find(ssl_sni, ctx_sni->type); + + if (sni) { + if (sni->status != WOLFSSL_SNI_NO_MATCH) + continue; + + /* if ssl level overrides ctx level, it is ok. */ + if ((sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) == 0) + continue; + } + + SendAlert(ssl, alert_fatal, handshake_failure); + return SNI_ABSENT_ERROR; + } + } + + for (; ssl_sni; ssl_sni = ssl_sni->next) { + if (ssl_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) { + if (ssl_sni->status != WOLFSSL_SNI_NO_MATCH) + continue; + + SendAlert(ssl, alert_fatal, handshake_failure); + return SNI_ABSENT_ERROR; + } + } + #endif /* NO_WOLFSSL_SERVER */ + } + + return 0; +} + +int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size, + void* heap) +{ + TLSX* extension; + SNI* sni = NULL; + + if (extensions == NULL || data == NULL) + return BAD_FUNC_ARG; + + if ((sni = TLSX_SNI_New(type, data, size, heap)) == NULL) + return MEMORY_E; + + extension = TLSX_Find(*extensions, TLSX_SERVER_NAME); + if (!extension) { + int ret = TLSX_Push(extensions, TLSX_SERVER_NAME, (void*)sni, heap); + + if (ret != 0) { + TLSX_SNI_Free(sni, heap); + return ret; + } + } + else { + /* push new SNI object to extension data. */ + sni->next = (SNI*)extension->data; + extension->data = (void*)sni; + + /* remove duplicate SNI, there should be only one of each type. */ + do { + if (sni->next && sni->next->type == type) { + SNI* next = sni->next; + + sni->next = next->next; + TLSX_SNI_Free(next, heap); + + /* there is no way to occur more than + * two SNIs of the same type. + */ + break; + } + } while ((sni = sni->next)); + } + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_SERVER + +/** Tells the SNI requested by the client. */ +word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME); + SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type); + + if (sni && sni->status != WOLFSSL_SNI_NO_MATCH) { + switch (sni->type) { + case WOLFSSL_SNI_HOST_NAME: + if (data) { + *data = sni->data.host_name; + return (word16)XSTRLEN((char*)*data); + } + } + } + + return 0; +} + +/** Sets the options for a SNI object. */ +void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME); + SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type); + + if (sni) + sni->options = options; +} + +/** Retrieves a SNI request from a client hello buffer. */ +int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, + byte type, byte* sni, word32* inOutSz) +{ + word32 offset = 0; + word32 len32 = 0; + word16 len16 = 0; + + if (helloSz < RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + CLIENT_HELLO_FIRST) + return INCOMPLETE_DATA; + + /* TLS record header */ + if ((enum ContentType) clientHello[offset++] != handshake) { + + /* checking for SSLv2.0 client hello according to: */ + /* http://tools.ietf.org/html/rfc4346#appendix-E.1 */ + if ((enum HandShakeType) clientHello[++offset] == client_hello) { + offset += ENUM_LEN + VERSION_SZ; /* skip version */ + + ato16(clientHello + offset, &len16); + offset += OPAQUE16_LEN; + + if (len16 % 3) /* cipher_spec_length must be multiple of 3 */ + return BUFFER_ERROR; + + ato16(clientHello + offset, &len16); + /* Returning SNI_UNSUPPORTED do not increment offset here */ + + if (len16 != 0) /* session_id_length must be 0 */ + return BUFFER_ERROR; + + return SNI_UNSUPPORTED; + } + + return BUFFER_ERROR; + } + + if (clientHello[offset++] != SSLv3_MAJOR) + return BUFFER_ERROR; + + if (clientHello[offset++] < TLSv1_MINOR) + return SNI_UNSUPPORTED; + + ato16(clientHello + offset, &len16); + offset += OPAQUE16_LEN; + + if (offset + len16 > helloSz) + return INCOMPLETE_DATA; + + /* Handshake header */ + if ((enum HandShakeType) clientHello[offset] != client_hello) + return BUFFER_ERROR; + + c24to32(clientHello + offset + 1, &len32); + offset += HANDSHAKE_HEADER_SZ; + + if (offset + len32 > helloSz) + return BUFFER_ERROR; + + /* client hello */ + offset += VERSION_SZ + RAN_LEN; /* version, random */ + + if (helloSz < offset + clientHello[offset]) + return BUFFER_ERROR; + + offset += ENUM_LEN + clientHello[offset]; /* skip session id */ + + /* cypher suites */ + if (helloSz < offset + OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(clientHello + offset, &len16); + offset += OPAQUE16_LEN; + + if (helloSz < offset + len16) + return BUFFER_ERROR; + + offset += len16; /* skip cypher suites */ + + /* compression methods */ + if (helloSz < offset + 1) + return BUFFER_ERROR; + + if (helloSz < offset + clientHello[offset]) + return BUFFER_ERROR; + + offset += ENUM_LEN + clientHello[offset]; /* skip compression methods */ + + /* extensions */ + if (helloSz < offset + OPAQUE16_LEN) + return 0; /* no extensions in client hello. */ + + ato16(clientHello + offset, &len16); + offset += OPAQUE16_LEN; + + if (helloSz < offset + len16) + return BUFFER_ERROR; + + while (len16 >= OPAQUE16_LEN + OPAQUE16_LEN) { + word16 extType; + word16 extLen; + + ato16(clientHello + offset, &extType); + offset += OPAQUE16_LEN; + + ato16(clientHello + offset, &extLen); + offset += OPAQUE16_LEN; + + if (helloSz < offset + extLen) + return BUFFER_ERROR; + + if (extType != TLSX_SERVER_NAME) { + offset += extLen; /* skip extension */ + } else { + word16 listLen; + + ato16(clientHello + offset, &listLen); + offset += OPAQUE16_LEN; + + if (helloSz < offset + listLen) + return BUFFER_ERROR; + + while (listLen > ENUM_LEN + OPAQUE16_LEN) { + byte sniType = clientHello[offset++]; + word16 sniLen; + + ato16(clientHello + offset, &sniLen); + offset += OPAQUE16_LEN; + + if (helloSz < offset + sniLen) + return BUFFER_ERROR; + + if (sniType != type) { + offset += sniLen; + listLen -= min(ENUM_LEN + OPAQUE16_LEN + sniLen, listLen); + continue; + } + + *inOutSz = min(sniLen, *inOutSz); + XMEMCPY(sni, clientHello + offset, *inOutSz); + + return WOLFSSL_SUCCESS; + } + } + + len16 -= min(2 * OPAQUE16_LEN + extLen, len16); + } + + return len16 ? BUFFER_ERROR : 0; +} + +#endif + +#define SNI_FREE_ALL TLSX_SNI_FreeAll +#define SNI_GET_SIZE TLSX_SNI_GetSize +#define SNI_WRITE TLSX_SNI_Write +#define SNI_PARSE TLSX_SNI_Parse +#define SNI_VERIFY_PARSE TLSX_SNI_VerifyParse + +#else + +#define SNI_FREE_ALL(list, heap) +#define SNI_GET_SIZE(list) 0 +#define SNI_WRITE(a, b) 0 +#define SNI_PARSE(a, b, c, d) 0 +#define SNI_VERIFY_PARSE(a, b) 0 + +#endif /* HAVE_SNI */ + +/******************************************************************************/ +/* Trusted CA Key Indication */ +/******************************************************************************/ + +#ifdef HAVE_TRUSTED_CA + +/** Creates a new TCA object. */ +static TCA* TLSX_TCA_New(byte type, const byte* id, word16 idSz, void* heap) +{ + TCA* tca = (TCA*)XMALLOC(sizeof(TCA), heap, DYNAMIC_TYPE_TLSX); + + if (tca) { + XMEMSET(tca, 0, sizeof(TCA)); + tca->type = type; + + switch (type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + + #ifndef NO_SHA + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + if (idSz == WC_SHA_DIGEST_SIZE && + (tca->id = + (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) { + XMEMCPY(tca->id, id, idSz); + tca->idSz = idSz; + } + else { + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + tca = NULL; + } + break; + #endif + + case WOLFSSL_TRUSTED_CA_X509_NAME: + if (idSz > 0 && + (tca->id = + (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) { + XMEMCPY(tca->id, id, idSz); + tca->idSz = idSz; + } + else { + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + tca = NULL; + } + break; + + default: /* invalid type */ + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + tca = NULL; + } + } + + (void)heap; + + return tca; +} + +/** Releases a TCA object. */ +static void TLSX_TCA_Free(TCA* tca, void* heap) +{ + (void)heap; + + if (tca) { + if (tca->id) + XFREE(tca->id, heap, DYNAMIC_TYPE_TLSX); + XFREE(tca, heap, DYNAMIC_TYPE_TLSX); + } +} + +/** Releases all TCA objects in the provided list. */ +static void TLSX_TCA_FreeAll(TCA* list, void* heap) +{ + TCA* tca; + + while ((tca = list)) { + list = tca->next; + TLSX_TCA_Free(tca, heap); + } +} + +/** Tells the buffered size of the TCA objects in a list. */ +static word16 TLSX_TCA_GetSize(TCA* list) +{ + TCA* tca; + word16 length = OPAQUE16_LEN; /* list length */ + + while ((tca = list)) { + list = tca->next; + + length += ENUM_LEN; /* tca type */ + + switch (tca->type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + length += tca->idSz; + break; + case WOLFSSL_TRUSTED_CA_X509_NAME: + length += OPAQUE16_LEN + tca->idSz; + break; + } + } + + return length; +} + +/** Writes the TCA objects of a list in a buffer. */ +static word16 TLSX_TCA_Write(TCA* list, byte* output) +{ + TCA* tca; + word16 offset = OPAQUE16_LEN; /* list length offset */ + + while ((tca = list)) { + list = tca->next; + + output[offset++] = tca->type; /* tca type */ + + switch (tca->type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + #ifndef NO_SHA + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + if (tca->id != NULL) { + XMEMCPY(output + offset, tca->id, tca->idSz); + offset += tca->idSz; + } + else { + /* ID missing. Set to an empty string. */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + } + break; + #endif + case WOLFSSL_TRUSTED_CA_X509_NAME: + if (tca->id != NULL) { + c16toa(tca->idSz, output + offset); /* tca length */ + offset += OPAQUE16_LEN; + XMEMCPY(output + offset, tca->id, tca->idSz); + offset += tca->idSz; + } + else { + /* ID missing. Set to an empty string. */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + } + break; + default: + /* ID unknown. Set to an empty string. */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + } + } + + c16toa(offset - OPAQUE16_LEN, output); /* writing list length */ + + return offset; +} + +#ifndef NO_WOLFSSL_SERVER +static TCA* TLSX_TCA_Find(TCA *list, byte type, const byte* id, word16 idSz) +{ + TCA* tca = list; + + while (tca && tca->type != type && type != WOLFSSL_TRUSTED_CA_PRE_AGREED && + idSz != tca->idSz && !XMEMCMP(id, tca->id, idSz)) + tca = tca->next; + + return tca; +} +#endif /* NO_WOLFSSL_SERVER */ + +/** Parses a buffer of TCA extensions. */ +static int TLSX_TCA_Parse(WOLFSSL* ssl, const byte* input, word16 length, + byte isRequest) +{ +#ifndef NO_WOLFSSL_SERVER + word16 size = 0; + word16 offset = 0; +#endif + + TLSX *extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS); + + if (!extension) + extension = TLSX_Find(ssl->ctx->extensions, TLSX_TRUSTED_CA_KEYS); + + if (!isRequest) { + #ifndef NO_WOLFSSL_CLIENT + if (!extension || !extension->data) + return TLSX_HandleUnsupportedExtension(ssl); + + if (length > 0) + return BUFFER_ERROR; /* TCA response MUST be empty. */ + + /* Set the flag that we're good for keys */ + TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS); + + return 0; + #endif + } + +#ifndef NO_WOLFSSL_SERVER + if (!extension || !extension->data) { + /* Skipping, TCA not enabled at server side. */ + return 0; + } + + if (OPAQUE16_LEN > length) + return BUFFER_ERROR; + + ato16(input, &size); + offset += OPAQUE16_LEN; + + /* validating tca list length */ + if (length != OPAQUE16_LEN + size) + return BUFFER_ERROR; + + for (size = 0; offset < length; offset += size) { + TCA *tca = NULL; + byte type; + const byte* id = NULL; + word16 idSz = 0; + + if (offset + ENUM_LEN > length) + return BUFFER_ERROR; + + type = input[offset++]; + + switch (type) { + case WOLFSSL_TRUSTED_CA_PRE_AGREED: + break; + #ifndef NO_SHA + case WOLFSSL_TRUSTED_CA_KEY_SHA1: + case WOLFSSL_TRUSTED_CA_CERT_SHA1: + if (offset + WC_SHA_DIGEST_SIZE > length) + return BUFFER_ERROR; + idSz = WC_SHA_DIGEST_SIZE; + id = input + offset; + offset += idSz; + break; + #endif + case WOLFSSL_TRUSTED_CA_X509_NAME: + if (offset + OPAQUE16_LEN > length) + return BUFFER_ERROR; + ato16(input + offset, &idSz); + offset += OPAQUE16_LEN; + if ((offset > length) || (idSz > length - offset)) + return BUFFER_ERROR; + id = input + offset; + offset += idSz; + break; + default: + return TCA_INVALID_ID_TYPE; + } + + /* Find the type/ID in the TCA list. */ + tca = TLSX_TCA_Find((TCA*)extension->data, type, id, idSz); + if (tca != NULL) { + /* Found it. Set the response flag and break out of the loop. */ + TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS); + break; + } + } +#else + (void)input; +#endif + + return 0; +} + +/* Checks to see if the server sent a response for the TCA. */ +static int TLSX_TCA_VerifyParse(WOLFSSL* ssl, byte isRequest) +{ + (void)ssl; + + if (!isRequest) { + #ifndef NO_WOLFSSL_CLIENT + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS); + + if (extension && !extension->resp) { + SendAlert(ssl, alert_fatal, handshake_failure); + return TCA_ABSENT_ERROR; + } + #endif /* NO_WOLFSSL_CLIENT */ + } + + return 0; +} + +int TLSX_UseTrustedCA(TLSX** extensions, byte type, + const byte* id, word16 idSz, void* heap) +{ + TLSX* extension; + TCA* tca = NULL; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + if ((tca = TLSX_TCA_New(type, id, idSz, heap)) == NULL) + return MEMORY_E; + + extension = TLSX_Find(*extensions, TLSX_TRUSTED_CA_KEYS); + if (!extension) { + int ret = TLSX_Push(extensions, TLSX_TRUSTED_CA_KEYS, (void*)tca, heap); + + if (ret != 0) { + TLSX_TCA_Free(tca, heap); + return ret; + } + } + else { + /* push new TCA object to extension data. */ + tca->next = (TCA*)extension->data; + extension->data = (void*)tca; + } + + return WOLFSSL_SUCCESS; +} + +#define TCA_FREE_ALL TLSX_TCA_FreeAll +#define TCA_GET_SIZE TLSX_TCA_GetSize +#define TCA_WRITE TLSX_TCA_Write +#define TCA_PARSE TLSX_TCA_Parse +#define TCA_VERIFY_PARSE TLSX_TCA_VerifyParse + +#else /* HAVE_TRUSTED_CA */ + +#define TCA_FREE_ALL(list, heap) +#define TCA_GET_SIZE(list) 0 +#define TCA_WRITE(a, b) 0 +#define TCA_PARSE(a, b, c, d) 0 +#define TCA_VERIFY_PARSE(a, b) 0 + +#endif /* HAVE_TRUSTED_CA */ + +/******************************************************************************/ +/* Max Fragment Length Negotiation */ +/******************************************************************************/ + +#ifdef HAVE_MAX_FRAGMENT + +static word16 TLSX_MFL_Write(byte* data, byte* output) +{ + output[0] = data[0]; + + return ENUM_LEN; +} + +static int TLSX_MFL_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + if (length != ENUM_LEN) + return BUFFER_ERROR; + +#ifdef WOLFSSL_OLD_UNSUPPORTED_EXTENSION + (void) isRequest; +#else + if (!isRequest) + if (TLSX_CheckUnsupportedExtension(ssl, TLSX_MAX_FRAGMENT_LENGTH)) + return TLSX_HandleUnsupportedExtension(ssl); +#endif + + switch (*input) { + case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; + case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; + case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; + case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; + case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; + case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; + + default: + SendAlert(ssl, alert_fatal, illegal_parameter); + + return UNKNOWN_MAX_FRAG_LEN_E; + } + +#ifndef NO_WOLFSSL_SERVER + if (isRequest) { + int ret = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap); + + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ + + TLSX_SetResponse(ssl, TLSX_MAX_FRAGMENT_LENGTH); + } +#endif + + return 0; +} + +int TLSX_UseMaxFragment(TLSX** extensions, byte mfl, void* heap) +{ + byte* data = NULL; + int ret = 0; + + if (extensions == NULL || mfl < WOLFSSL_MFL_MIN || mfl > WOLFSSL_MFL_MAX) + return BAD_FUNC_ARG; + + data = (byte*)XMALLOC(ENUM_LEN, heap, DYNAMIC_TYPE_TLSX); + if (data == NULL) + return MEMORY_E; + + data[0] = mfl; + + ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap); + if (ret != 0) { + XFREE(data, heap, DYNAMIC_TYPE_TLSX); + return ret; + } + + return WOLFSSL_SUCCESS; +} + + +#define MFL_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX) +#define MFL_GET_SIZE(data) ENUM_LEN +#define MFL_WRITE TLSX_MFL_Write +#define MFL_PARSE TLSX_MFL_Parse + +#else + +#define MFL_FREE_ALL(a, b) +#define MFL_GET_SIZE(a) 0 +#define MFL_WRITE(a, b) 0 +#define MFL_PARSE(a, b, c, d) 0 + +#endif /* HAVE_MAX_FRAGMENT */ + +/******************************************************************************/ +/* Truncated HMAC */ +/******************************************************************************/ + +#ifdef HAVE_TRUNCATED_HMAC + +static int TLSX_THM_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + if (length != 0 || input == NULL) + return BUFFER_ERROR; + + if (!isRequest) { + #ifndef WOLFSSL_OLD_UNSUPPORTED_EXTENSION + if (TLSX_CheckUnsupportedExtension(ssl, TLSX_TRUNCATED_HMAC)) + return TLSX_HandleUnsupportedExtension(ssl); + #endif + } + else { + #ifndef NO_WOLFSSL_SERVER + int ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); + + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ + + TLSX_SetResponse(ssl, TLSX_TRUNCATED_HMAC); + #endif + } + + ssl->truncated_hmac = 1; + + return 0; +} + +int TLSX_UseTruncatedHMAC(TLSX** extensions, void* heap) +{ + int ret = 0; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap); + if (ret != 0) + return ret; + + return WOLFSSL_SUCCESS; +} + +#define THM_PARSE TLSX_THM_Parse + +#else + +#define THM_PARSE(a, b, c, d) 0 + +#endif /* HAVE_TRUNCATED_HMAC */ + +/******************************************************************************/ +/* Certificate Status Request */ +/******************************************************************************/ + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + +static void TLSX_CSR_Free(CertificateStatusRequest* csr, void* heap) +{ + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + FreeOcspRequest(&csr->request.ocsp); + break; + } + + XFREE(csr, heap, DYNAMIC_TYPE_TLSX); + (void)heap; +} + +static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest) +{ + word16 size = 0; + + /* shut up compiler warnings */ + (void) csr; (void) isRequest; + +#ifndef NO_WOLFSSL_CLIENT + if (isRequest) { + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + size += ENUM_LEN + 2 * OPAQUE16_LEN; + + if (csr->request.ocsp.nonceSz) + size += OCSP_NONCE_EXT_SZ; + break; + } + } +#endif +#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) + if (!isRequest && csr->ssl->options.tls1_3) + return OPAQUE8_LEN + OPAQUE24_LEN + csr->response.length; +#endif + + return size; +} + +static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output, + byte isRequest) +{ + /* shut up compiler warnings */ + (void) csr; (void) output; (void) isRequest; + +#ifndef NO_WOLFSSL_CLIENT + if (isRequest) { + word16 offset = 0; + word16 length = 0; + + /* type */ + output[offset++] = csr->status_type; + + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + /* responder id list */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + + /* request extensions */ + if (csr->request.ocsp.nonceSz) + length = (word16)EncodeOcspRequestExtensions( + &csr->request.ocsp, + output + offset + OPAQUE16_LEN, + OCSP_NONCE_EXT_SZ); + + c16toa(length, output + offset); + offset += OPAQUE16_LEN + length; + + break; + } + + return offset; + } +#endif +#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) + if (!isRequest && csr->ssl->options.tls1_3) { + word16 offset = 0; + output[offset++] = csr->status_type; + c32to24(csr->response.length, output + offset); + offset += OPAQUE24_LEN; + XMEMCPY(output + offset, csr->response.buffer, csr->response.length); + offset += csr->response.length; + return offset; + } +#endif + + return 0; +} + +static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + int ret; + + /* shut up compiler warnings */ + (void) ssl; (void) input; + + if (!isRequest) { +#ifndef NO_WOLFSSL_CLIENT + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); + CertificateStatusRequest* csr = extension ? + (CertificateStatusRequest*)extension->data : NULL; + + if (!csr) { + /* look at context level */ + extension = TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST); + csr = extension ? (CertificateStatusRequest*)extension->data : NULL; + + if (!csr) /* unexpected extension */ + return TLSX_HandleUnsupportedExtension(ssl); + + /* enable extension at ssl level */ + ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, + csr->status_type, csr->options, ssl, + ssl->heap, ssl->devId); + if (ret != WOLFSSL_SUCCESS) + return ret; + + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + /* propagate nonce */ + if (csr->request.ocsp.nonceSz) { + OcspRequest* request = + (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions); + + if (request) { + XMEMCPY(request->nonce, csr->request.ocsp.nonce, + csr->request.ocsp.nonceSz); + request->nonceSz = csr->request.ocsp.nonceSz; + } + } + break; + } + } + + ssl->status_request = 1; + + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + word32 resp_length; + word32 offset = 0; + + /* Get the new extension potentially created above. */ + extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); + csr = extension ? (CertificateStatusRequest*)extension->data : NULL; + if (csr == NULL) + return MEMORY_ERROR; + + ret = 0; + if (OPAQUE8_LEN + OPAQUE24_LEN > length) + ret = BUFFER_ERROR; + if (ret == 0 && input[offset++] != WOLFSSL_CSR_OCSP) + ret = BAD_CERTIFICATE_STATUS_ERROR; + if (ret == 0) { + c24to32(input + offset, &resp_length); + offset += OPAQUE24_LEN; + if (offset + resp_length != length) + ret = BUFFER_ERROR; + } + #if !defined(NO_WOLFSSL_SERVER) + if (ret == 0) { + csr->response.buffer = input + offset; + csr->response.length = resp_length; + } + #endif + + return ret; + } + else + #endif + { + /* extension_data MUST be empty. */ + return length ? BUFFER_ERROR : 0; + } +#endif + } + else { +#ifndef NO_WOLFSSL_SERVER + byte status_type; + word16 offset = 0; + word16 size = 0; + + if (length == 0) + return 0; + if (length < ENUM_LEN) + return BUFFER_ERROR; + + status_type = input[offset++]; + + switch (status_type) { + case WOLFSSL_CSR_OCSP: { + + /* skip responder_id_list */ + if (length - offset < OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input + offset, &size); + offset += OPAQUE16_LEN + size; + + /* skip request_extensions */ + if (length - offset < OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input + offset, &size); + offset += OPAQUE16_LEN + size; + + if (offset > length) + return BUFFER_ERROR; + + /* is able to send OCSP response? */ + if (ssl->ctx->cm == NULL || !ssl->ctx->cm->ocspStaplingEnabled) + return 0; + } + break; + + /* unknown status type */ + default: + return 0; + } + + /* if using status_request and already sending it, skip this one */ + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) + return 0; + #endif + + /* accept the first good status_type and return */ + ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, + 0, ssl, ssl->heap, ssl->devId); + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ + + #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER) + if (ssl->options.tls1_3) { + OcspRequest* request; + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); + CertificateStatusRequest* csr = extension ? + (CertificateStatusRequest*)extension->data : NULL; + if (csr == NULL) + return MEMORY_ERROR; + + request = &csr->request.ocsp; + ret = CreateOcspResponse(ssl, &request, &csr->response); + if (ret != 0) + return ret; + if (csr->response.buffer) + TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST); + } + else + #endif + TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST); + ssl->status_request = status_type; +#endif + } + + return 0; +} + +int TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert, void* heap) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST); + CertificateStatusRequest* csr = extension ? + (CertificateStatusRequest*)extension->data : NULL; + int ret = 0; + + if (csr) { + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: { + byte nonce[MAX_OCSP_NONCE_SZ]; + int nonceSz = csr->request.ocsp.nonceSz; + + /* preserve nonce */ + XMEMCPY(nonce, csr->request.ocsp.nonce, nonceSz); + + if ((ret = InitOcspRequest(&csr->request.ocsp, cert, 0, heap)) + != 0) + return ret; + + /* restore nonce */ + XMEMCPY(csr->request.ocsp.nonce, nonce, nonceSz); + csr->request.ocsp.nonceSz = nonceSz; + } + break; + } + } + + return ret; +} + +void* TLSX_CSR_GetRequest(TLSX* extensions) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST); + CertificateStatusRequest* csr = extension ? + (CertificateStatusRequest*)extension->data : NULL; + + if (csr) { + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + return &csr->request.ocsp; + break; + } + } + + return NULL; +} + +int TLSX_CSR_ForceRequest(WOLFSSL* ssl) +{ + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); + CertificateStatusRequest* csr = extension ? + (CertificateStatusRequest*)extension->data : NULL; + + if (csr) { + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + if (ssl->ctx->cm->ocspEnabled) { + csr->request.ocsp.ssl = ssl; + return CheckOcspRequest(ssl->ctx->cm->ocsp, + &csr->request.ocsp, NULL); + } + else + return OCSP_LOOKUP_FAIL; + } + } + + return 0; +} + +int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type, + byte options, WOLFSSL* ssl, void* heap, + int devId) +{ + CertificateStatusRequest* csr = NULL; + int ret = 0; + + if (!extensions || status_type != WOLFSSL_CSR_OCSP) + return BAD_FUNC_ARG; + + csr = (CertificateStatusRequest*) + XMALLOC(sizeof(CertificateStatusRequest), heap, DYNAMIC_TYPE_TLSX); + if (!csr) + return MEMORY_E; + + ForceZero(csr, sizeof(CertificateStatusRequest)); + + csr->status_type = status_type; + csr->options = options; + csr->ssl = ssl; + + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + if (options & WOLFSSL_CSR_OCSP_USE_NONCE) { + WC_RNG rng; + + #ifndef HAVE_FIPS + ret = wc_InitRng_ex(&rng, heap, devId); + #else + ret = wc_InitRng(&rng); + (void)devId; + #endif + if (ret == 0) { + if (wc_RNG_GenerateBlock(&rng, csr->request.ocsp.nonce, + MAX_OCSP_NONCE_SZ) == 0) + csr->request.ocsp.nonceSz = MAX_OCSP_NONCE_SZ; + + wc_FreeRng(&rng); + } + } + break; + } + + if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST, csr, heap)) != 0) { + XFREE(csr, heap, DYNAMIC_TYPE_TLSX); + return ret; + } + + return WOLFSSL_SUCCESS; +} + +#define CSR_FREE_ALL TLSX_CSR_Free +#define CSR_GET_SIZE TLSX_CSR_GetSize +#define CSR_WRITE TLSX_CSR_Write +#define CSR_PARSE TLSX_CSR_Parse + +#else + +#define CSR_FREE_ALL(data, heap) +#define CSR_GET_SIZE(a, b) 0 +#define CSR_WRITE(a, b, c) 0 +#define CSR_PARSE(a, b, c, d) 0 + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + +/******************************************************************************/ +/* Certificate Status Request v2 */ +/******************************************************************************/ + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + +static void TLSX_CSR2_FreeAll(CertificateStatusRequestItemV2* csr2, void* heap) +{ + CertificateStatusRequestItemV2* next; + + for (; csr2; csr2 = next) { + next = csr2->next; + + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + case WOLFSSL_CSR2_OCSP_MULTI: + while(csr2->requests--) + FreeOcspRequest(&csr2->request.ocsp[csr2->requests]); + break; + } + + XFREE(csr2, heap, DYNAMIC_TYPE_TLSX); + } + (void)heap; +} + +static word16 TLSX_CSR2_GetSize(CertificateStatusRequestItemV2* csr2, + byte isRequest) +{ + word16 size = 0; + + /* shut up compiler warnings */ + (void) csr2; (void) isRequest; + +#ifndef NO_WOLFSSL_CLIENT + if (isRequest) { + CertificateStatusRequestItemV2* next; + + for (size = OPAQUE16_LEN; csr2; csr2 = next) { + next = csr2->next; + + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + case WOLFSSL_CSR2_OCSP_MULTI: + size += ENUM_LEN + 3 * OPAQUE16_LEN; + + if (csr2->request.ocsp[0].nonceSz) + size += OCSP_NONCE_EXT_SZ; + break; + } + } + } +#endif + + return size; +} + +static word16 TLSX_CSR2_Write(CertificateStatusRequestItemV2* csr2, + byte* output, byte isRequest) +{ + /* shut up compiler warnings */ + (void) csr2; (void) output; (void) isRequest; + +#ifndef NO_WOLFSSL_CLIENT + if (isRequest) { + word16 offset; + word16 length; + + for (offset = OPAQUE16_LEN; csr2 != NULL; csr2 = csr2->next) { + /* status_type */ + output[offset++] = csr2->status_type; + + /* request */ + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + case WOLFSSL_CSR2_OCSP_MULTI: + /* request_length */ + length = 2 * OPAQUE16_LEN; + + if (csr2->request.ocsp[0].nonceSz) + length += OCSP_NONCE_EXT_SZ; + + c16toa(length, output + offset); + offset += OPAQUE16_LEN; + + /* responder id list */ + c16toa(0, output + offset); + offset += OPAQUE16_LEN; + + /* request extensions */ + length = 0; + + if (csr2->request.ocsp[0].nonceSz) + length = (word16)EncodeOcspRequestExtensions( + &csr2->request.ocsp[0], + output + offset + OPAQUE16_LEN, + OCSP_NONCE_EXT_SZ); + + c16toa(length, output + offset); + offset += OPAQUE16_LEN + length; + break; + } + } + + /* list size */ + c16toa(offset - OPAQUE16_LEN, output); + + return offset; + } +#endif + + return 0; +} + +static int TLSX_CSR2_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + int ret; + + /* shut up compiler warnings */ + (void) ssl; (void) input; + + if (!isRequest) { +#ifndef NO_WOLFSSL_CLIENT + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST_V2); + CertificateStatusRequestItemV2* csr2 = extension ? + (CertificateStatusRequestItemV2*)extension->data : NULL; + + if (!csr2) { + /* look at context level */ + extension = TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST_V2); + csr2 = extension ? + (CertificateStatusRequestItemV2*)extension->data : NULL; + + if (!csr2) /* unexpected extension */ + return TLSX_HandleUnsupportedExtension(ssl); + + /* enable extension at ssl level */ + for (; csr2; csr2 = csr2->next) { + ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions, + csr2->status_type, csr2->options, ssl->heap, + ssl->devId); + if (ret != WOLFSSL_SUCCESS) + return ret; + + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + /* followed by */ + case WOLFSSL_CSR2_OCSP_MULTI: + /* propagate nonce */ + if (csr2->request.ocsp[0].nonceSz) { + OcspRequest* request = + (OcspRequest*)TLSX_CSR2_GetRequest(ssl->extensions, + csr2->status_type, 0); + + if (request) { + XMEMCPY(request->nonce, + csr2->request.ocsp[0].nonce, + csr2->request.ocsp[0].nonceSz); + + request->nonceSz = + csr2->request.ocsp[0].nonceSz; + } + } + break; + } + } + } + + ssl->status_request_v2 = 1; + + return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */ +#endif + } + else { +#ifndef NO_WOLFSSL_SERVER + byte status_type; + word16 request_length; + word16 offset = 0; + word16 size = 0; + + /* list size */ + if (offset + OPAQUE16_LEN >= length) { + return BUFFER_E; + } + + ato16(input + offset, &request_length); + offset += OPAQUE16_LEN; + + if (length - OPAQUE16_LEN != request_length) + return BUFFER_ERROR; + + while (length > offset) { + if (length - offset < ENUM_LEN + OPAQUE16_LEN) + return BUFFER_ERROR; + + status_type = input[offset++]; + + ato16(input + offset, &request_length); + offset += OPAQUE16_LEN; + + if (length - offset < request_length) + return BUFFER_ERROR; + + switch (status_type) { + case WOLFSSL_CSR2_OCSP: + case WOLFSSL_CSR2_OCSP_MULTI: + /* skip responder_id_list */ + if (length - offset < OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input + offset, &size); + if (length - offset < size) + return BUFFER_ERROR; + + offset += OPAQUE16_LEN + size; + /* skip request_extensions */ + if (length - offset < OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input + offset, &size); + if (length - offset < size) + return BUFFER_ERROR; + + offset += OPAQUE16_LEN + size; + if (offset > length) + return BUFFER_ERROR; + + /* is able to send OCSP response? */ + if (ssl->ctx->cm == NULL + || !ssl->ctx->cm->ocspStaplingEnabled) + continue; + break; + + default: + /* unknown status type, skipping! */ + offset += request_length; + continue; + } + + /* if using status_request and already sending it, skip this one */ + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST + if (ssl->status_request) + return 0; + #endif + + /* accept the first good status_type and return */ + ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions, + status_type, 0, ssl->heap, ssl->devId); + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ + + TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2); + ssl->status_request_v2 = status_type; + + return 0; + } +#endif + } + + return 0; +} + +int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert, byte isPeer, + void* heap) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2); + CertificateStatusRequestItemV2* csr2 = extension ? + (CertificateStatusRequestItemV2*)extension->data : NULL; + int ret = 0; + + for (; csr2; csr2 = csr2->next) { + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + if (!isPeer || csr2->requests != 0) + break; + + FALL_THROUGH; /* followed by */ + + case WOLFSSL_CSR2_OCSP_MULTI: { + if (csr2->requests < 1 + MAX_CHAIN_DEPTH) { + byte nonce[MAX_OCSP_NONCE_SZ]; + int nonceSz = csr2->request.ocsp[0].nonceSz; + + /* preserve nonce, replicating nonce of ocsp[0] */ + XMEMCPY(nonce, csr2->request.ocsp[0].nonce, nonceSz); + + if ((ret = InitOcspRequest( + &csr2->request.ocsp[csr2->requests], cert, + 0, heap)) != 0) + return ret; + + /* restore nonce */ + XMEMCPY(csr2->request.ocsp[csr2->requests].nonce, + nonce, nonceSz); + csr2->request.ocsp[csr2->requests].nonceSz = nonceSz; + csr2->requests++; + } + } + break; + } + } + + (void)cert; + return ret; +} + +void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type, byte idx) +{ + TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2); + CertificateStatusRequestItemV2* csr2 = extension ? + (CertificateStatusRequestItemV2*)extension->data : NULL; + + for (; csr2; csr2 = csr2->next) { + if (csr2->status_type == status_type) { + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + /* followed by */ + + case WOLFSSL_CSR2_OCSP_MULTI: + /* requests are initialized in the reverse order */ + return idx < csr2->requests + ? &csr2->request.ocsp[csr2->requests - idx - 1] + : NULL; + break; + } + } + } + + return NULL; +} + +int TLSX_CSR2_ForceRequest(WOLFSSL* ssl) +{ + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST_V2); + CertificateStatusRequestItemV2* csr2 = extension ? + (CertificateStatusRequestItemV2*)extension->data : NULL; + + /* forces only the first one */ + if (csr2) { + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + /* followed by */ + + case WOLFSSL_CSR2_OCSP_MULTI: + if (ssl->ctx->cm->ocspEnabled) { + csr2->request.ocsp[0].ssl = ssl; + return CheckOcspRequest(ssl->ctx->cm->ocsp, + &csr2->request.ocsp[0], NULL); + } + else + return OCSP_LOOKUP_FAIL; + } + } + + return 0; +} + +int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type, + byte options, void* heap, int devId) +{ + TLSX* extension = NULL; + CertificateStatusRequestItemV2* csr2 = NULL; + int ret = 0; + + if (!extensions) + return BAD_FUNC_ARG; + + if (status_type != WOLFSSL_CSR2_OCSP + && status_type != WOLFSSL_CSR2_OCSP_MULTI) + return BAD_FUNC_ARG; + + csr2 = (CertificateStatusRequestItemV2*) + XMALLOC(sizeof(CertificateStatusRequestItemV2), heap, DYNAMIC_TYPE_TLSX); + if (!csr2) + return MEMORY_E; + + ForceZero(csr2, sizeof(CertificateStatusRequestItemV2)); + + csr2->status_type = status_type; + csr2->options = options; + csr2->next = NULL; + + switch (csr2->status_type) { + case WOLFSSL_CSR2_OCSP: + case WOLFSSL_CSR2_OCSP_MULTI: + if (options & WOLFSSL_CSR2_OCSP_USE_NONCE) { + WC_RNG rng; + + #ifndef HAVE_FIPS + ret = wc_InitRng_ex(&rng, heap, devId); + #else + ret = wc_InitRng(&rng); + (void)devId; + #endif + if (ret == 0) { + if (wc_RNG_GenerateBlock(&rng, csr2->request.ocsp[0].nonce, + MAX_OCSP_NONCE_SZ) == 0) + csr2->request.ocsp[0].nonceSz = MAX_OCSP_NONCE_SZ; + + wc_FreeRng(&rng); + } + } + break; + } + + /* append new item */ + if ((extension = TLSX_Find(*extensions, TLSX_STATUS_REQUEST_V2))) { + CertificateStatusRequestItemV2* last = + (CertificateStatusRequestItemV2*)extension->data; + + for (; last->next; last = last->next); + + last->next = csr2; + } + else if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST_V2, csr2,heap))) { + XFREE(csr2, heap, DYNAMIC_TYPE_TLSX); + return ret; + } + + return WOLFSSL_SUCCESS; +} + +#define CSR2_FREE_ALL TLSX_CSR2_FreeAll +#define CSR2_GET_SIZE TLSX_CSR2_GetSize +#define CSR2_WRITE TLSX_CSR2_Write +#define CSR2_PARSE TLSX_CSR2_Parse + +#else + +#define CSR2_FREE_ALL(data, heap) +#define CSR2_GET_SIZE(a, b) 0 +#define CSR2_WRITE(a, b, c) 0 +#define CSR2_PARSE(a, b, c, d) 0 + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +/******************************************************************************/ +/* Supported Elliptic Curves */ +/******************************************************************************/ + +#ifdef HAVE_SUPPORTED_CURVES + +#if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448) \ + && !defined(HAVE_FFDHE) +#error Elliptic Curves Extension requires Elliptic Curve Cryptography. \ + Use --enable-ecc in the configure script or define HAVE_ECC. \ + Alternatively use FFDHE for DH ciperhsuites. +#endif + +static int TLSX_SupportedCurve_New(SupportedCurve** curve, word16 name, + void* heap) +{ + if (curve == NULL) + return BAD_FUNC_ARG; + + (void)heap; + + *curve = (SupportedCurve*)XMALLOC(sizeof(SupportedCurve), heap, + DYNAMIC_TYPE_TLSX); + if (*curve == NULL) + return MEMORY_E; + + (*curve)->name = name; + (*curve)->next = NULL; + + return 0; +} + +static int TLSX_PointFormat_New(PointFormat** point, byte format, void* heap) +{ + if (point == NULL) + return BAD_FUNC_ARG; + + (void)heap; + + *point = (PointFormat*)XMALLOC(sizeof(PointFormat), heap, + DYNAMIC_TYPE_TLSX); + if (*point == NULL) + return MEMORY_E; + + (*point)->format = format; + (*point)->next = NULL; + + return 0; +} + +static void TLSX_SupportedCurve_FreeAll(SupportedCurve* list, void* heap) +{ + SupportedCurve* curve; + + while ((curve = list)) { + list = curve->next; + XFREE(curve, heap, DYNAMIC_TYPE_TLSX); + } + (void)heap; +} + +static void TLSX_PointFormat_FreeAll(PointFormat* list, void* heap) +{ + PointFormat* point; + + while ((point = list)) { + list = point->next; + XFREE(point, heap, DYNAMIC_TYPE_TLSX); + } + (void)heap; +} + +static int TLSX_SupportedCurve_Append(SupportedCurve* list, word16 name, + void* heap) +{ + int ret = BAD_FUNC_ARG; + + while (list) { + if (list->name == name) { + ret = 0; /* curve already in use */ + break; + } + + if (list->next == NULL) { + ret = TLSX_SupportedCurve_New(&list->next, name, heap); + break; + } + + list = list->next; + } + + return ret; +} + +static int TLSX_PointFormat_Append(PointFormat* list, byte format, void* heap) +{ + int ret = BAD_FUNC_ARG; + + while (list) { + if (list->format == format) { + ret = 0; /* format already in use */ + break; + } + + if (list->next == NULL) { + ret = TLSX_PointFormat_New(&list->next, format, heap); + break; + } + + list = list->next; + } + + return ret; +} + +#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT) + +static void TLSX_SupportedCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore) +{ + word16 i; + + for (i = 0; i < ssl->suites->suiteSz; i+= 2) { + if (ssl->suites->suites[i] == TLS13_BYTE) + return; + if (ssl->suites->suites[i] == ECC_BYTE || + ssl->suites->suites[i] == CHACHA_BYTE) { + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + return; + #endif + } + else { + #ifdef HAVE_FFDHE + return; + #endif + } + } + + /* turns semaphore on to avoid sending this extension. */ + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_GROUPS)); +} + +static void TLSX_PointFormat_ValidateRequest(WOLFSSL* ssl, byte* semaphore) +{ + word16 i; + + for (i = 0; i < ssl->suites->suiteSz; i+= 2) { + if (ssl->suites->suites[i] == TLS13_BYTE) + return; + if (ssl->suites->suites[i] == ECC_BYTE || + ssl->suites->suites[i] == CHACHA_BYTE) { + #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + return; + #endif + } + else { + #ifdef HAVE_FFDHE + return; + #endif + } + } + + /* turns semaphore on to avoid sending this extension. */ + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); +} + +#endif + +#ifndef NO_WOLFSSL_SERVER + +static void TLSX_PointFormat_ValidateResponse(WOLFSSL* ssl, byte* semaphore) +{ +#if defined(HAVE_FFDHE) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448) + (void)semaphore; +#endif + + if (ssl->options.cipherSuite0 == TLS13_BYTE) + return; + if (ssl->options.cipherSuite0 == ECC_BYTE || + ssl->options.cipherSuite0 == CHACHA_BYTE) { +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + return; +#endif + } + else { +#ifdef HAVE_FFDHE + return; +#endif + } + +#if !defined(HAVE_FFDHE) || (!defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \ + && !defined(HAVE_CURVE448)) + /* turns semaphore on to avoid sending this extension. */ + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); +#endif +} + +#endif +#ifndef NO_WOLFSSL_CLIENT + +static word16 TLSX_SupportedCurve_GetSize(SupportedCurve* list) +{ + SupportedCurve* curve; + word16 length = OPAQUE16_LEN; /* list length */ + + while ((curve = list)) { + list = curve->next; + length += OPAQUE16_LEN; /* curve length */ + } + + return length; +} + +#endif + +static word16 TLSX_PointFormat_GetSize(PointFormat* list) +{ + PointFormat* point; + word16 length = ENUM_LEN; /* list length */ + + while ((point = list)) { + list = point->next; + length += ENUM_LEN; /* format length */ + } + + return length; +} + +#ifndef NO_WOLFSSL_CLIENT + +static word16 TLSX_SupportedCurve_Write(SupportedCurve* list, byte* output) +{ + word16 offset = OPAQUE16_LEN; + + while (list) { + c16toa(list->name, output + offset); + offset += OPAQUE16_LEN; + list = list->next; + } + + c16toa(offset - OPAQUE16_LEN, output); /* writing list length */ + + return offset; +} + +#endif + +static word16 TLSX_PointFormat_Write(PointFormat* list, byte* output) +{ + word16 offset = ENUM_LEN; + + while (list) { + output[offset++] = list->format; + list = list->next; + } + + output[0] = (byte)(offset - ENUM_LEN); + + return offset; +} + +#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) + +static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + word16 offset; + word16 name; + int ret; + + if(!isRequest && !IsAtLeastTLSv1_3(ssl->version)) { +#ifdef WOLFSSL_ALLOW_SERVER_SC_EXT + return 0; +#else + return BUFFER_ERROR; /* servers doesn't send this extension. */ +#endif + } + + if (OPAQUE16_LEN > length || length % OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input, &offset); + + /* validating curve list length */ + if (length != OPAQUE16_LEN + offset) + return BUFFER_ERROR; + + offset = OPAQUE16_LEN; + if (offset == length) + return 0; + +#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) + if (!isRequest) { + TLSX* extension; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension != NULL) { + /* Replace client list with server list of supported groups. */ + curve = (SupportedCurve*)extension->data; + extension->data = NULL; + TLSX_SupportedCurve_FreeAll(curve, ssl->heap); + + ato16(input + offset, &name); + offset += OPAQUE16_LEN; + + ret = TLSX_SupportedCurve_New(&curve, name, ssl->heap); + if (ret != 0) + return ret; /* throw error */ + extension->data = (void*)curve; + } + } +#endif + + for (; offset < length; offset += OPAQUE16_LEN) { + ato16(input + offset, &name); + + ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ + } + + return 0; +} + +#endif + +#if !defined(NO_WOLFSSL_SERVER) + +#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) + +/* Checks the priority of the groups on the server and set the supported groups + * response if there is a group not advertised by the client that is preferred. + * + * ssl SSL/TLS object. + * returns 0 on success, otherwise an error. + */ +int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl) +{ + int ret; + TLSX* extension; + TLSX* priority = NULL; + TLSX* ext = NULL; + word16 name; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + /* May be doing PSK with no key exchange. */ + if (extension == NULL) + return 0; + + if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS) + return ret; + + ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS); + curve = (SupportedCurve*)ext->data; + name = curve->name; + + curve = (SupportedCurve*)extension->data; + while (curve != NULL) { + if (curve->name == name) + break; + curve = curve->next; + } + + if (curve == NULL) { + /* Couldn't find the preferred group in client list. */ + extension->resp = 1; + + /* Send server list back and free client list. */ + curve = (SupportedCurve*)extension->data; + extension->data = ext->data; + ext->data = curve; + } + + TLSX_FreeAll(priority, ssl->heap); + + return 0; +} + +#endif + +#if defined(HAVE_FFDHE) && !defined(WOLFSSL_NO_TLS12) +/* Set the highest priority common FFDHE group on the server as compared to + * client extensions. + * + * ssl SSL/TLS object. + * returns 0 on success, otherwise an error. + */ +int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + TLSX* priority = NULL; + TLSX* ext = NULL; + SupportedCurve* serverGroup; + SupportedCurve* clientGroup; + SupportedCurve* group; + const DhParams* params = NULL; + int found = 0; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + /* May be doing PSK with no key exchange. */ + if (extension == NULL) + return 0; + clientGroup = (SupportedCurve*)extension->data; + for (group = clientGroup; group != NULL; group = group->next) { + if (group->name >= MIN_FFHDE_GROUP && group->name <= MAX_FFHDE_GROUP) { + found = 1; + break; + } + } + if (!found) + return 0; + + if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + ssl->buffers.serverDH_P.buffer = NULL; + ssl->buffers.serverDH_G.buffer = NULL; + ssl->buffers.weOwnDH = 0; + ssl->options.haveDH = 0; + + + if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS) + return ret; + ret = 0; + + ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS); + serverGroup = (SupportedCurve*)ext->data; + + for (; serverGroup != NULL; serverGroup = serverGroup->next) { + if ((serverGroup->name & NAMED_DH_MASK) != NAMED_DH_MASK) + continue; + + for (group = clientGroup; group != NULL; group = group->next) { + if (serverGroup->name != group->name) + continue; + + switch (serverGroup->name) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + params = wc_Dh_ffdhe2048_Get(); + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + params = wc_Dh_ffdhe3072_Get(); + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + params = wc_Dh_ffdhe4096_Get(); + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + params = wc_Dh_ffdhe6144_Get(); + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + params = wc_Dh_ffdhe8192_Get(); + break; + #endif + } + if (params == NULL) + return BAD_FUNC_ARG; + if (params->p_len >= ssl->options.minDhKeySz && + params->p_len <= ssl->options.maxDhKeySz) { + break; + } + } + + if (group != NULL && serverGroup->name == group->name) + break; + } + + if (serverGroup) { + ssl->buffers.serverDH_P.buffer = (unsigned char *)params->p; + ssl->buffers.serverDH_P.length = params->p_len; + ssl->buffers.serverDH_G.buffer = (unsigned char *)params->g; + ssl->buffers.serverDH_G.length = params->g_len; + ssl->namedGroup = serverGroup->name; + #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \ + !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) + ssl->options.dhDoKeyTest = 0; + #endif + ssl->options.haveDH = 1; + } + + TLSX_FreeAll(priority, ssl->heap); + + return ret; +} +#endif /* HAVE_FFDHE && !WOLFSSL_NO_TLS12 */ + +#endif /* !NO_WOLFSSL_SERVER */ + +#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) +/* Return the preferred group. + * + * ssl SSL/TLS object. + * checkSupported Whether to check for the first supported group. + * returns BAD_FUNC_ARG if no group found, otherwise the group. + */ +int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported) +{ + TLSX* extension; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension == NULL) + return BAD_FUNC_ARG; + + curve = (SupportedCurve*)extension->data; + while (curve != NULL) { + if (!checkSupported || TLSX_KeyShare_IsSupported(curve->name)) + return curve->name; + curve = curve->next; + } + + return BAD_FUNC_ARG; +} + +#endif + +#ifndef NO_WOLFSSL_SERVER + +static int TLSX_PointFormat_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + int ret; + + /* validating formats list length */ + if (ENUM_LEN > length || length != (word16)ENUM_LEN + input[0]) + return BUFFER_ERROR; + + if (isRequest) { + /* adding uncompressed point format to response */ + ret = TLSX_UsePointFormat(&ssl->extensions, WOLFSSL_EC_PF_UNCOMPRESSED, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ + + TLSX_SetResponse(ssl, TLSX_EC_POINT_FORMATS); + } + + return 0; +} + +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) +int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first, byte second) { + TLSX* extension = NULL; + SupportedCurve* curve = NULL; + word32 oid = 0; + word32 pkOid = 0; + word32 defOid = 0; + word32 defSz = 80; /* Maximum known curve size is 66. */ + word32 nextOid = 0; + word32 nextSz = 80; /* Maximum known curve size is 66. */ + word32 currOid = ssl->ecdhCurveOID; + int ephmSuite = 0; + word16 octets = 0; /* according to 'ecc_set_type ecc_sets[];' */ + int sig = 0; /* validate signature */ + int key = 0; /* validate key */ + + (void)oid; + + if (first == ECC_BYTE || first == CHACHA_BYTE) + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (!extension) + return 1; /* no suite restriction */ + + for (curve = (SupportedCurve*)extension->data; + curve && !(sig && key); + curve = curve->next) { + + #ifdef OPENSSL_EXTRA + /* skip if name is not in supported ECC range */ + if (curve->name > WOLFSSL_ECC_X448) + continue; + /* skip if curve is disabled by user */ + if (ssl->ctx->disabledCurves & (1 << curve->name)) + continue; + #endif + + /* find supported curve */ + switch (curve->name) { +#ifdef HAVE_ECC + #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP160R1: + pkOid = oid = ECC_SECP160R1_OID; + octets = 20; + break; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + case WOLFSSL_ECC_SECP160R2: + pkOid = oid = ECC_SECP160R2_OID; + octets = 20; + break; + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP160K1: + pkOid = oid = ECC_SECP160K1_OID; + octets = 20; + break; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP192R1: + pkOid = oid = ECC_SECP192R1_OID; + octets = 24; + break; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP192K1: + pkOid = oid = ECC_SECP192K1_OID; + octets = 24; + break; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP224R1: + pkOid = oid = ECC_SECP224R1_OID; + octets = 28; + break; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP224K1: + pkOid = oid = ECC_SECP224K1_OID; + octets = 28; + break; + #endif /* HAVE_ECC_KOBLITZ */ + #endif + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + pkOid = oid = ECC_SECP256R1_OID; + octets = 32; + break; + #endif /* !NO_ECC_SECP */ + #endif /* !NO_ECC256 || HAVE_ALL_CURVES */ +#endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + oid = ECC_X25519_OID; + #ifdef HAVE_ED25519 + pkOid = ECC_ED25519_OID; + #else + pkOid = ECC_X25519_OID; + #endif + octets = 32; + break; + #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ECC + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_KOBLITZ + case WOLFSSL_ECC_SECP256K1: + pkOid = oid = ECC_SECP256K1_OID; + octets = 32; + break; + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP256R1: + pkOid = oid = ECC_BRAINPOOLP256R1_OID; + octets = 32; + break; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif +#endif + #ifdef HAVE_CURVE448 + case WOLFSSL_ECC_X448: + oid = ECC_X448_OID; + #ifdef HAVE_ED448 + pkOid = ECC_ED448_OID; + #else + pkOid = ECC_X448_OID; + #endif + octets = 57; + break; + #endif /* HAVE_CURVE448 */ +#ifdef HAVE_ECC + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + pkOid = oid = ECC_SECP384R1_OID; + octets = 48; + break; + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP384R1: + pkOid = oid = ECC_BRAINPOOLP384R1_OID; + octets = 48; + break; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP512R1: + pkOid = oid = ECC_BRAINPOOLP512R1_OID; + octets = 64; + break; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + pkOid = oid = ECC_SECP521R1_OID; + octets = 66; + break; + #endif /* !NO_ECC_SECP */ + #endif +#endif + default: continue; /* unsupported curve */ + } + + #ifdef HAVE_ECC + /* Set default Oid */ + if (defOid == 0 && ssl->eccTempKeySz <= octets && defSz > octets) { + defOid = oid; + defSz = octets; + } + + /* The eccTempKeySz is the preferred ephemeral key size */ + if (currOid == 0 && ssl->eccTempKeySz == octets) + currOid = oid; + if ((nextOid == 0 || nextSz > octets) && ssl->eccTempKeySz <= octets) { + nextOid = oid; + nextSz = octets; + } + #else + if (defOid == 0 && defSz > octets) { + defOid = oid; + defSz = octets; + } + + if (currOid == 0) + currOid = oid; + if (nextOid == 0 || nextSz > octets) { + nextOid = oid; + nextSz = octets; + } + #endif + + if (first == ECC_BYTE) { + switch (second) { + /* ECDHE_ECDSA */ + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + sig |= ssl->pkCurveOID == pkOid; + key |= ssl->ecdhCurveOID == oid; + ephmSuite = 1; + break; + +#ifdef WOLFSSL_STATIC_DH + /* ECDH_ECDSA */ + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + if (oid == ECC_X25519_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + if (oid == ECC_X448_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + sig |= ssl->pkCurveOID == pkOid; + key |= ssl->pkCurveOID == oid; + break; +#endif /* WOLFSSL_STATIC_DH */ +#ifndef NO_RSA + /* ECDHE_RSA */ + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + case TLS_ECDHE_RSA_WITH_RC4_128_SHA: + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + sig = 1; + key |= ssl->ecdhCurveOID == oid; + ephmSuite = 1; + break; + +#ifdef WOLFSSL_STATIC_DH + /* ECDH_RSA */ + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + case TLS_ECDH_RSA_WITH_RC4_128_SHA: + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + if (oid == ECC_X25519_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + if (oid == ECC_X448_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + sig = 1; + key |= ssl->pkCurveOID == pkOid; + break; +#endif /* WOLFSSL_STATIC_DH */ +#endif + default: + if (oid == ECC_X25519_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + if (oid == ECC_X448_OID && defOid == oid) { + defOid = 0; + defSz = 80; + } + if (oid != ECC_X25519_OID && oid != ECC_X448_OID) { + sig = 1; + } + key = 1; + break; + } + } + + /* ChaCha20-Poly1305 ECC cipher suites */ + if (first == CHACHA_BYTE) { + switch (second) { + /* ECDHE_ECDSA */ + case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 : + case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + sig |= ssl->pkCurveOID == pkOid; + key |= ssl->ecdhCurveOID == oid; + ephmSuite = 1; + break; +#ifndef NO_RSA + /* ECDHE_RSA */ + case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + sig = 1; + key |= ssl->ecdhCurveOID == oid; + ephmSuite = 1; + break; +#endif + default: + sig = 1; + key = 1; + break; + } + } + } + + /* Choose the default if it is at the required strength. */ +#ifdef HAVE_ECC + if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz) +#else + if (ssl->ecdhCurveOID == 0) +#endif + { + key = 1; + ssl->ecdhCurveOID = defOid; + } + /* Choose any curve at the required strength. */ + if (ssl->ecdhCurveOID == 0) { + key = 1; + ssl->ecdhCurveOID = currOid; + } + /* Choose the default if it is at the next highest strength. */ + if (ssl->ecdhCurveOID == 0 && defSz == nextSz) + ssl->ecdhCurveOID = defOid; + /* Choose any curve at the next highest strength. */ + if (ssl->ecdhCurveOID == 0) + ssl->ecdhCurveOID = nextOid; + /* No curve and ephemeral ECC suite requires a matching curve. */ + if (ssl->ecdhCurveOID == 0 && ephmSuite) + key = 0; + + return sig && key; +} +#endif + +#endif /* NO_WOLFSSL_SERVER */ + +int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap) +{ + TLSX* extension = NULL; + SupportedCurve* curve = NULL; + int ret; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + extension = TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS); + + if (!extension) { + ret = TLSX_SupportedCurve_New(&curve, name, heap); + if (ret != 0) + return ret; + + ret = TLSX_Push(extensions, TLSX_SUPPORTED_GROUPS, curve, heap); + if (ret != 0) { + XFREE(curve, heap, DYNAMIC_TYPE_TLSX); + return ret; + } + } + else { + ret = TLSX_SupportedCurve_Append((SupportedCurve*)extension->data, name, + heap); + if (ret != 0) + return ret; + } + + return WOLFSSL_SUCCESS; +} + +int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap) +{ + TLSX* extension = NULL; + PointFormat* point = NULL; + int ret = 0; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + extension = TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS); + + if (!extension) { + ret = TLSX_PointFormat_New(&point, format, heap); + if (ret != 0) + return ret; + + ret = TLSX_Push(extensions, TLSX_EC_POINT_FORMATS, point, heap); + if (ret != 0) { + XFREE(point, heap, DYNAMIC_TYPE_TLSX); + return ret; + } + } + else { + ret = TLSX_PointFormat_Append((PointFormat*)extension->data, format, + heap); + if (ret != 0) + return ret; + } + + return WOLFSSL_SUCCESS; +} + +#define EC_FREE_ALL TLSX_SupportedCurve_FreeAll +#define EC_VALIDATE_REQUEST TLSX_SupportedCurve_ValidateRequest + +#ifndef NO_WOLFSSL_CLIENT +#define EC_GET_SIZE TLSX_SupportedCurve_GetSize +#define EC_WRITE TLSX_SupportedCurve_Write +#else +#define EC_GET_SIZE(list) 0 +#define EC_WRITE(a, b) 0 +#endif + +#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) +#define EC_PARSE TLSX_SupportedCurve_Parse +#else +#define EC_PARSE(a, b, c, d) 0 +#endif + +#define PF_FREE_ALL TLSX_PointFormat_FreeAll +#define PF_VALIDATE_REQUEST TLSX_PointFormat_ValidateRequest +#define PF_VALIDATE_RESPONSE TLSX_PointFormat_ValidateResponse + +#define PF_GET_SIZE TLSX_PointFormat_GetSize +#define PF_WRITE TLSX_PointFormat_Write + +#ifndef NO_WOLFSSL_SERVER +#define PF_PARSE TLSX_PointFormat_Parse +#else +#define PF_PARSE(a, b, c, d) 0 +#endif + +#else + +#define EC_FREE_ALL(list, heap) +#define EC_GET_SIZE(list) 0 +#define EC_WRITE(a, b) 0 +#define EC_PARSE(a, b, c, d) 0 +#define EC_VALIDATE_REQUEST(a, b) + +#define PF_FREE_ALL(list, heap) +#define PF_GET_SIZE(list) 0 +#define PF_WRITE(a, b) 0 +#define PF_PARSE(a, b, c, d) 0 +#define PF_VALIDATE_REQUEST(a, b) +#define PF_VALIDATE_RESPONSE(a, b) + +#endif /* HAVE_SUPPORTED_CURVES */ + +/******************************************************************************/ +/* Renegotiation Indication */ +/******************************************************************************/ + +#if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + +static byte TLSX_SecureRenegotiation_GetSize(SecureRenegotiation* data, + int isRequest) +{ + byte length = OPAQUE8_LEN; /* empty info length */ + + /* data will be NULL for HAVE_SERVER_RENEGOTIATION_INFO only */ + if (data && data->enabled && data->verifySet) { + /* client sends client_verify_data only */ + length += TLS_FINISHED_SZ; + + /* server also sends server_verify_data */ + if (!isRequest) + length += TLS_FINISHED_SZ; + } + + return length; +} + +static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data, + byte* output, int isRequest) +{ + word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */ + if (data && data->enabled && data->verifySet) { + /* client sends client_verify_data only */ + XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ); + offset += TLS_FINISHED_SZ; + + /* server also sends server_verify_data */ + if (!isRequest) { + XMEMCPY(output + offset, data->server_verify_data, TLS_FINISHED_SZ); + offset += TLS_FINISHED_SZ; + } + } + + output[0] = (byte)(offset - 1); /* info length - self */ + + return offset; +} + +static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, byte* input, + word16 length, byte isRequest) +{ + int ret = SECURE_RENEGOTIATION_E; + + if (length >= OPAQUE8_LEN) { + if (isRequest) { + #ifndef NO_WOLFSSL_SERVER + if (ssl->secure_renegotiation == NULL) { + ret = wolfSSL_UseSecureRenegotiation(ssl); + if (ret == WOLFSSL_SUCCESS) + ret = 0; + } + if (ret != 0 && ret != SECURE_RENEGOTIATION_E) { + } + else if (!ssl->secure_renegotiation->enabled) { + if (*input == 0) { + input++; /* get past size */ + + ssl->secure_renegotiation->enabled = 1; + TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO); + ret = 0; + } + else { + /* already in error state */ + WOLFSSL_MSG("SCR client verify data present"); + } + } + else if (*input == TLS_FINISHED_SZ) { + if (length < TLS_FINISHED_SZ + 1) { + WOLFSSL_MSG("SCR malformed buffer"); + ret = BUFFER_E; + } + else { + input++; /* get past size */ + + /* validate client verify data */ + if (XMEMCMP(input, + ssl->secure_renegotiation->client_verify_data, + TLS_FINISHED_SZ) == 0) { + WOLFSSL_MSG("SCR client verify data match"); + TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO); + ret = 0; /* verified */ + } else { + /* already in error state */ + WOLFSSL_MSG("SCR client verify data Failure"); + } + } + } + #endif + } + else { + #ifndef NO_WOLFSSL_CLIENT + if (!ssl->secure_renegotiation->enabled) { + if (*input == 0) { + ssl->secure_renegotiation->enabled = 1; + ret = 0; + } + } + else if (*input == 2 * TLS_FINISHED_SZ && + length == 2 * TLS_FINISHED_SZ + OPAQUE8_LEN) { + input++; /* get past size */ + + /* validate client and server verify data */ + if (XMEMCMP(input, + ssl->secure_renegotiation->client_verify_data, + TLS_FINISHED_SZ) == 0 && + XMEMCMP(input + TLS_FINISHED_SZ, + ssl->secure_renegotiation->server_verify_data, + TLS_FINISHED_SZ) == 0) { + WOLFSSL_MSG("SCR client and server verify data match"); + ret = 0; /* verified */ + } else { + /* already in error state */ + WOLFSSL_MSG("SCR client and server verify data Failure"); + } + } + #endif + } + } + + if (ret != 0) { + SendAlert(ssl, alert_fatal, handshake_failure); + } + + return ret; +} + +int TLSX_UseSecureRenegotiation(TLSX** extensions, void* heap) +{ + int ret = 0; + SecureRenegotiation* data; + + data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), heap, + DYNAMIC_TYPE_TLSX); + if (data == NULL) + return MEMORY_E; + + XMEMSET(data, 0, sizeof(SecureRenegotiation)); + + ret = TLSX_Push(extensions, TLSX_RENEGOTIATION_INFO, data, heap); + if (ret != 0) { + XFREE(data, heap, DYNAMIC_TYPE_TLSX); + return ret; + } + + return WOLFSSL_SUCCESS; +} + +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + +int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap) +{ + int ret; + + /* send empty renegotiation_info extension */ + TLSX* ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO); + if (ext == NULL) { + ret = TLSX_UseSecureRenegotiation(extensions, heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + + ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO); + } + if (ext) + ext->resp = 1; + + return WOLFSSL_SUCCESS; +} + +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ + + +#define SCR_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX) +#define SCR_GET_SIZE TLSX_SecureRenegotiation_GetSize +#define SCR_WRITE TLSX_SecureRenegotiation_Write +#define SCR_PARSE TLSX_SecureRenegotiation_Parse + +#else + +#define SCR_FREE_ALL(a, heap) +#define SCR_GET_SIZE(a, b) 0 +#define SCR_WRITE(a, b, c) 0 +#define SCR_PARSE(a, b, c, d) 0 + +#endif /* HAVE_SECURE_RENEGOTIATION */ + +/******************************************************************************/ +/* Session Tickets */ +/******************************************************************************/ + +#ifdef HAVE_SESSION_TICKET + +#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT) +static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl) +{ + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_SESSION_TICKET); + SessionTicket* ticket = extension ? + (SessionTicket*)extension->data : NULL; + + if (ticket) { + /* TODO validate ticket timeout here! */ + if (ticket->lifetime == 0xfffffff) { + /* send empty ticket on timeout */ + TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); + } + } +} +#endif /* WLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */ + + +static word16 TLSX_SessionTicket_GetSize(SessionTicket* ticket, int isRequest) +{ + (void)isRequest; + return ticket ? ticket->size : 0; +} + +static word16 TLSX_SessionTicket_Write(SessionTicket* ticket, byte* output, + int isRequest) +{ + word16 offset = 0; /* empty ticket */ + + if (isRequest && ticket) { + XMEMCPY(output + offset, ticket->data, ticket->size); + offset += ticket->size; + } + + return offset; +} + + +static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + int ret = 0; + + (void) input; /* avoid unused parameter if NO_WOLFSSL_SERVER defined */ + + if (!isRequest) { + if (TLSX_CheckUnsupportedExtension(ssl, TLSX_SESSION_TICKET)) + return TLSX_HandleUnsupportedExtension(ssl); + + if (length != 0) + return BUFFER_ERROR; + +#ifndef NO_WOLFSSL_CLIENT + ssl->expect_session_ticket = 1; +#endif + } +#ifndef NO_WOLFSSL_SERVER + else { + /* server side */ + if (ssl->ctx->ticketEncCb == NULL) { + WOLFSSL_MSG("Client sent session ticket, server has no callback"); + return 0; + } + + if (length == 0) { + /* blank ticket */ + ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); + if (ret == WOLFSSL_SUCCESS) { + ret = 0; + TLSX_SetResponse(ssl, TLSX_SESSION_TICKET); /* send blank ticket */ + ssl->options.createTicket = 1; /* will send ticket msg */ + ssl->options.useTicket = 1; + ssl->options.resuming = 0; /* no standard resumption */ + ssl->arrays->sessionIDSz = 0; /* no echo on blank ticket */ + } + } else { + /* got actual ticket from client */ + ret = DoClientTicket(ssl, input, length); + if (ret == WOLFSSL_TICKET_RET_OK) { /* use ticket to resume */ + WOLFSSL_MSG("Using existing client ticket"); + ssl->options.useTicket = 1; + ssl->options.resuming = 1; + } else if (ret == WOLFSSL_TICKET_RET_CREATE) { + WOLFSSL_MSG("Using existing client ticket, creating new one"); + ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); + if (ret == WOLFSSL_SUCCESS) { + ret = 0; + TLSX_SetResponse(ssl, TLSX_SESSION_TICKET); + /* send blank ticket */ + ssl->options.createTicket = 1; /* will send ticket msg */ + ssl->options.useTicket = 1; + ssl->options.resuming = 1; + } + } else if (ret == WOLFSSL_TICKET_RET_REJECT) { + WOLFSSL_MSG("Process client ticket rejected, not using"); + ssl->options.rejectTicket = 1; + ret = 0; /* not fatal */ + } else if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) { + WOLFSSL_MSG("Process client ticket fatal error, not using"); + } + } + } +#endif /* NO_WOLFSSL_SERVER */ + + return ret; +} + +WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, + byte* data, word16 size, void* heap) +{ + SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket), + heap, DYNAMIC_TYPE_TLSX); + if (ticket) { + ticket->data = (byte*)XMALLOC(size, heap, DYNAMIC_TYPE_TLSX); + if (ticket->data == NULL) { + XFREE(ticket, heap, DYNAMIC_TYPE_TLSX); + return NULL; + } + + XMEMCPY(ticket->data, data, size); + ticket->size = size; + ticket->lifetime = lifetime; + } + + (void)heap; + + return ticket; +} +WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap) +{ + if (ticket) { + XFREE(ticket->data, heap, DYNAMIC_TYPE_TLSX); + XFREE(ticket, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket, void* heap) +{ + int ret = 0; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + /* If the ticket is NULL, the client will request a new ticket from the + server. Otherwise, the client will use it in the next client hello. */ + if ((ret = TLSX_Push(extensions, TLSX_SESSION_TICKET, (void*)ticket, heap)) + != 0) + return ret; + + return WOLFSSL_SUCCESS; +} + +#define WOLF_STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest +#define WOLF_STK_GET_SIZE TLSX_SessionTicket_GetSize +#define WOLF_STK_WRITE TLSX_SessionTicket_Write +#define WOLF_STK_PARSE TLSX_SessionTicket_Parse +#define WOLF_STK_FREE(stk, heap) TLSX_SessionTicket_Free((SessionTicket*)stk,(heap)) + +#else + +#define WOLF_STK_FREE(a, b) +#define WOLF_STK_VALIDATE_REQUEST(a) +#define WOLF_STK_GET_SIZE(a, b) 0 +#define WOLF_STK_WRITE(a, b, c) 0 +#define WOLF_STK_PARSE(a, b, c, d) 0 + +#endif /* HAVE_SESSION_TICKET */ + +/******************************************************************************/ +/* Quantum-Safe-Hybrid */ +/******************************************************************************/ + +#ifdef HAVE_QSH +#if defined(HAVE_NTRU) +static WC_RNG* gRng; +static wolfSSL_Mutex* gRngMutex; +#endif + +static void TLSX_QSH_FreeAll(QSHScheme* list, void* heap) +{ + QSHScheme* current; + + while ((current = list)) { + list = current->next; + XFREE(current, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +static int TLSX_QSH_Append(QSHScheme** list, word16 name, byte* pub, + word16 pubLen) +{ + QSHScheme* temp; + + if (list == NULL) + return BAD_FUNC_ARG; + + if ((temp = (QSHScheme*)XMALLOC(sizeof(QSHScheme), NULL, + DYNAMIC_TYPE_TLSX)) == NULL) + return MEMORY_E; + + temp->name = name; + temp->PK = pub; + temp->PKLen = pubLen; + temp->next = *list; + + *list = temp; + + return 0; +} + + +/* request for server's public key : 02 indicates 0-2 requested */ +static byte TLSX_QSH_SerPKReq(byte* output, byte isRequest) +{ + if (isRequest) { + /* only request one public key from the server */ + output[0] = 0x01; + + return OPAQUE8_LEN; + } + else { + return 0; + } +} + +#ifndef NO_WOLFSSL_CLIENT + +/* check for TLS_QSH suite */ +static void TLSX_QSH_ValidateRequest(WOLFSSL* ssl, byte* semaphore) +{ + int i; + + for (i = 0; i < ssl->suites->suiteSz; i+= 2) + if (ssl->suites->suites[i] == QSH_BYTE) + return; + + /* No QSH suite found */ + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_QUANTUM_SAFE_HYBRID)); +} + + +/* return the size of the QSH hello extension + list the list of QSHScheme structs containing id and key + isRequest if 1 then is being sent to the server + */ +word16 TLSX_QSH_GetSize(QSHScheme* list, byte isRequest) +{ + QSHScheme* temp = list; + word16 length = 0; + + /* account for size of scheme list and public key list */ + if (isRequest) + length = OPAQUE16_LEN; + length += OPAQUE24_LEN; + + /* for each non null element in list add size */ + while ((temp)) { + /* add public key info Scheme | Key Length | Key */ + length += OPAQUE16_LEN; + length += OPAQUE16_LEN; + length += temp->PKLen; + + /* if client add name size for scheme list + advance to next QSHScheme struct in list */ + if (isRequest) + length += OPAQUE16_LEN; + temp = temp->next; + } + + /* add length for request server public keys */ + if (isRequest) + length += OPAQUE8_LEN; + + return length; +} + + +/* write out a list of QSHScheme IDs */ +static word16 TLSX_QSH_Write(QSHScheme* list, byte* output) +{ + QSHScheme* current = list; + word16 length = 0; + + length += OPAQUE16_LEN; + + while (current) { + c16toa(current->name, output + length); + length += OPAQUE16_LEN; + current = (QSHScheme*)current->next; + } + + c16toa(length - OPAQUE16_LEN, output); /* writing list length */ + + return length; +} + + +/* write public key list in extension */ +static word16 TLSX_QSHPK_WriteR(QSHScheme* format, byte* output) +{ + word32 offset = 0; + word16 public_len = 0; + + if (!format) + return offset; + + /* write scheme ID */ + c16toa(format->name, output + offset); + offset += OPAQUE16_LEN; + + /* write public key matching scheme */ + public_len = format->PKLen; + c16toa(public_len, output + offset); + offset += OPAQUE16_LEN; + if (format->PK) { + XMEMCPY(output+offset, format->PK, public_len); + } + + return public_len + offset; +} + +word16 TLSX_QSHPK_Write(QSHScheme* list, byte* output) +{ + QSHScheme* current = list; + word32 length = 0; + word24 toWire; + + length += OPAQUE24_LEN; + + while (current) { + length += TLSX_QSHPK_WriteR(current, output + length); + current = (QSHScheme*)current->next; + } + /* length of public keys sent */ + c32to24(length - OPAQUE24_LEN, toWire); + output[0] = toWire[0]; + output[1] = toWire[1]; + output[2] = toWire[2]; + + return length; +} + +#endif /* NO_WOLFSSL_CLIENT */ +#ifndef NO_WOLFSSL_SERVER + +static void TLSX_QSHAgreement(TLSX** extensions, void* heap) +{ + TLSX* extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID); + QSHScheme* format = NULL; + QSHScheme* del = NULL; + QSHScheme* prev = NULL; + + if (extension == NULL) + return; + + format = (QSHScheme*)extension->data; + while (format) { + if (format->PKLen == 0) { + /* case of head */ + if (format == extension->data) { + extension->data = format->next; + } + if (prev) + prev->next = format->next; + del = format; + format = format->next; + XFREE(del, heap, DYNAMIC_TYPE_TMP_BUFFER); + del = NULL; + } else { + prev = format; + format = format->next; + } + } + + (void)heap; +} + + +/* Parse in hello extension + input the byte stream to process + length length of total extension found + isRequest set to 1 if being sent to the server + */ +static int TLSX_QSH_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + byte numKeys = 0; + word16 offset = 0; + word16 schemSz = 0; + word16 offset_len = 0; + word32 offset_pk = 0; + word16 name = 0; + word16 PKLen = 0; + byte* PK = NULL; + int r; + + + if (OPAQUE16_LEN > length) + return BUFFER_ERROR; + + if (isRequest) { + ato16(input, &schemSz); + + /* list of public keys available for QSH schemes */ + offset_len = schemSz + OPAQUE16_LEN; + } + + offset_pk = ((input[offset_len] << 16) & 0xFF00000) | + (((input[offset_len + 1]) << 8) & 0xFF00) | + (input[offset_len + 2] & 0xFF); + offset_len += OPAQUE24_LEN; + + /* check buffer size */ + if (offset_pk > length) + return BUFFER_ERROR; + + /* set maximum number of keys the client will accept */ + if (!isRequest) + numKeys = (ssl->maxRequest < 1)? 1 : ssl->maxRequest; + + /* hello extension read list of scheme ids */ + if (isRequest) { + + /* read in request for public keys */ + ssl->minRequest = (input[length -1] >> 4) & 0xFF; + ssl->maxRequest = input[length -1] & 0x0F; + + /* choose the min between min requested by client and 1 */ + numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1; + + if (ssl->minRequest > ssl->maxRequest) + return BAD_FUNC_ARG; + + offset += OPAQUE16_LEN; + schemSz += offset; + + /* check buffer size */ + if (schemSz > length) + return BUFFER_ERROR; + + while ((offset < schemSz) && numKeys) { + /* Scheme ID list */ + ato16(input + offset, &name); + offset += OPAQUE16_LEN; + + /* validate we have scheme id */ + if (ssl->user_set_QSHSchemes && + !TLSX_ValidateQSHScheme(&ssl->extensions, name)) { + continue; + } + + /* server create keys on demand */ + if ((r = TLSX_CreateNtruKey(ssl, name)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return r; + } + + /* peer sent an agreed upon scheme */ + r = TLSX_UseQSHScheme(&ssl->extensions, name, NULL, 0, ssl->heap); + + if (r != WOLFSSL_SUCCESS) return r; /* throw error */ + + numKeys--; + } + + /* choose the min between min requested by client and 1 */ + numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1; + } + + /* QSHPK struct */ + offset_pk += offset_len; + while ((offset_len < offset_pk) && numKeys) { + QSHKey * temp; + + if ((temp = (QSHKey*)XMALLOC(sizeof(QSHKey), ssl->heap, + DYNAMIC_TYPE_TLSX)) == NULL) + return MEMORY_E; + + /* initialize */ + temp->next = NULL; + temp->pub.buffer = NULL; + temp->pub.length = 0; + temp->pri.buffer = NULL; + temp->pri.length = 0; + + /* scheme id */ + ato16(input + offset_len, &(temp->name)); + offset_len += OPAQUE16_LEN; + + /* public key length */ + ato16(input + offset_len, &PKLen); + temp->pub.length = PKLen; + offset_len += OPAQUE16_LEN; + + + if (isRequest) { + /* validate we have scheme id */ + if (ssl->user_set_QSHSchemes && + (!TLSX_ValidateQSHScheme(&ssl->extensions, temp->name))) { + offset_len += PKLen; + XFREE(temp, ssl->heap, DYNAMIC_TYPE_TLSX); + continue; + } + } + + /* read in public key */ + if (PKLen > 0) { + temp->pub.buffer = (byte*)XMALLOC(temp->pub.length, + ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + XMEMCPY(temp->pub.buffer, input + offset_len, temp->pub.length); + offset_len += PKLen; + } + else { + PK = NULL; + } + + /* use own key when adding to extensions list for sending reply */ + PKLen = 0; + PK = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, &PKLen, temp->name); + r = TLSX_UseQSHScheme(&ssl->extensions, temp->name, PK, PKLen, + ssl->heap); + + /* store peers key */ + ssl->peerQSHKeyPresent = 1; + if (TLSX_AddQSHKey(&ssl->peerQSHKey, temp) != 0) + return MEMORY_E; + + if (temp->pub.length == 0) { + XFREE(temp, ssl->heap, DYNAMIC_TYPE_TLSX); + } + + if (r != WOLFSSL_SUCCESS) {return r;} /* throw error */ + + numKeys--; + } + + /* reply to a QSH extension sent from client */ + if (isRequest) { + TLSX_SetResponse(ssl, TLSX_QUANTUM_SAFE_HYBRID); + /* only use schemes we have key generated for -- free the rest */ + TLSX_QSHAgreement(&ssl->extensions, ssl->heap); + } + + return 0; +} + + +/* Used for parsing in QSHCipher structs on Key Exchange */ +int TLSX_QSHCipher_Parse(WOLFSSL* ssl, const byte* input, word16 length, + byte isServer) +{ + QSHKey* key; + word16 Max_Secret_Len = 48; + word16 offset = 0; + word16 offset_len = 0; + word32 offset_pk = 0; + word16 name = 0; + word16 secretLen = 0; + byte* secret = NULL; + word16 buffLen = 0; + byte buff[145]; /* size enough for 3 secrets */ + buffer* buf; + + /* pointer to location where secret should be stored */ + if (isServer) { + buf = ssl->QSH_secret->CliSi; + } + else { + buf = ssl->QSH_secret->SerSi; + } + + offset_pk = ((input[offset_len] << 16) & 0xFF0000) | + (((input[offset_len + 1]) << 8) & 0xFF00) | + (input[offset_len + 2] & 0xFF); + offset_len += OPAQUE24_LEN; + + /* validating extension list length -- check if trying to read over edge + of buffer */ + if (length < (offset_pk + OPAQUE24_LEN)) { + return BUFFER_ERROR; + } + + /* QSHCipherList struct */ + offset_pk += offset_len; + while (offset_len < offset_pk) { + + /* scheme id */ + ato16(input + offset_len, &name); + offset_len += OPAQUE16_LEN; + + /* public key length */ + ato16(input + offset_len, &secretLen); + offset_len += OPAQUE16_LEN; + + /* read in public key */ + if (secretLen > 0) { + secret = (byte*)(input + offset_len); + offset_len += secretLen; + } + else { + secret = NULL; + } + + /* no secret sent */ + if (secret == NULL) + continue; + + /* find corresponding key */ + key = ssl->QSH_Key; + while (key) { + if (key->name == name) + break; + else + key = (QSHKey*)key->next; + } + + /* if we do not have the key than there was a big issue negotiation */ + if (key == NULL) { + WOLFSSL_MSG("key was null for decryption!!!\n"); + return MEMORY_E; + } + + /* Decrypt sent secret */ + buffLen = Max_Secret_Len; + QSH_Decrypt(key, secret, secretLen, buff + offset, &buffLen); + offset += buffLen; + } + + /* allocate memory for buffer */ + buf->length = offset; + buf->buffer = (byte*)XMALLOC(offset, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf->buffer == NULL) + return MEMORY_E; + + /* store secrets */ + XMEMCPY(buf->buffer, buff, offset); + ForceZero(buff, offset); + + return offset_len; +} + + +/* return 1 on success */ +int TLSX_ValidateQSHScheme(TLSX** extensions, word16 theirs) { + TLSX* extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID); + QSHScheme* format = NULL; + + /* if no extension is sent then do not use QSH */ + if (!extension) { + WOLFSSL_MSG("No QSH Extension"); + return 0; + } + + for (format = (QSHScheme*)extension->data; format; format = format->next) { + if (format->name == theirs) { + WOLFSSL_MSG("Found Matching QSH Scheme"); + return 1; /* have QSH */ + } + } + + return 0; +} +#endif /* NO_WOLFSSL_SERVER */ + +/* test if the QSH Scheme is implemented + return 1 if yes 0 if no */ +static int TLSX_HaveQSHScheme(word16 name) +{ + switch(name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + return 1; + #endif + case WOLFSSL_LWE_XXX: + case WOLFSSL_HFE_XXX: + return 0; /* not supported yet */ + + default: + return 0; + } +} + + +/* Add a QSHScheme struct to list of usable ones */ +int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz, + void* heap) +{ + TLSX* extension = NULL; + QSHScheme* format = NULL; + int ret = 0; + + /* sanity check */ + if (extensions == NULL || (pKey == NULL && pkeySz != 0)) + return BAD_FUNC_ARG; + + extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID); + + /* if scheme is implemented than add */ + if (TLSX_HaveQSHScheme(name)) { + if ((ret = TLSX_QSH_Append(&format, name, pKey, pkeySz)) != 0) + return ret; + + extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID); + if (!extension) { + if ((ret = TLSX_Push(extensions, TLSX_QUANTUM_SAFE_HYBRID, format, + heap)) != 0) { + XFREE(format, 0, DYNAMIC_TYPE_TLSX); + return ret; + } + } + else { + /* push new QSH object to extension data. */ + format->next = (QSHScheme*)extension->data; + extension->data = (void*)format; + + /* look for another format of the same name to remove (replacement) */ + do { + if (format->next && (format->next->name == name)) { + QSHScheme* next = format->next; + + format->next = next->next; + XFREE(next, 0, DYNAMIC_TYPE_TLSX); + + break; + } + } while ((format = format->next)); + } + } + return WOLFSSL_SUCCESS; +} + +#define QSH_FREE_ALL TLSX_QSH_FreeAll +#define QSH_VALIDATE_REQUEST TLSX_QSH_ValidateRequest + +#ifndef NO_WOLFSSL_CLIENT +#define QSH_GET_SIZE TLSX_QSH_GetSize +#define QSH_WRITE TLSX_QSH_Write +#else +#define QSH_GET_SIZE(list, a) 0 +#define QSH_WRITE(a, b) 0 +#endif + +#ifndef NO_WOLFSSL_SERVER +#define QSH_PARSE TLSX_QSH_Parse +#else +#define QSH_PARSE(a, b, c, d) 0 +#endif + +#define QSHPK_WRITE TLSX_QSHPK_Write +#define QSH_SERREQ TLSX_QSH_SerPKReq +#else + +#define QSH_FREE_ALL(list, heap) +#define QSH_GET_SIZE(list, a) 0 +#define QSH_WRITE(a, b) 0 +#define QSH_PARSE(a, b, c, d) 0 +#define QSHPK_WRITE(a, b) 0 +#define QSH_SERREQ(a, b) 0 +#define QSH_VALIDATE_REQUEST(a, b) + +#endif /* HAVE_QSH */ + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +/******************************************************************************/ +/* Encrypt-then-MAC */ +/******************************************************************************/ + +#ifndef WOLFSSL_NO_TLS12 +static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl); + +/** + * Get the size of the Encrypt-Then-MAC extension. + * + * msgType Type of message to put extension into. + * pSz Size of extension data. + * return SANITY_MSG_E when the message is not allowed to have extension and + * 0 otherwise. + */ +static int TLSX_EncryptThenMac_GetSize(byte msgType, word16* pSz) +{ + (void)pSz; + + if (msgType != client_hello && msgType != server_hello) { + return SANITY_MSG_E; + } + + /* Empty extension */ + + return 0; +} + +/** + * Write the Encrypt-Then-MAC extension. + * + * data Unused + * output Extension data buffer. Unused. + * msgType Type of message to put extension into. + * pSz Size of extension data. + * return SANITY_MSG_E when the message is not allowed to have extension and + * 0 otherwise. + */ +static int TLSX_EncryptThenMac_Write(void* data, byte* output, byte msgType, + word16* pSz) +{ + (void)data; + (void)output; + (void)pSz; + + if (msgType != client_hello && msgType != server_hello) { + return SANITY_MSG_E; + } + + /* Empty extension */ + + return 0; +} + +/** + * Parse the Encrypt-Then-MAC extension. + * + * ssl SSL object + * input Extension data buffer. + * length Length of this extension's data. + * msgType Type of message to extension appeared in. + * return SANITY_MSG_E when the message is not allowed to have extension, + * BUFFER_ERROR when the extension's data is invalid, + * MEMORY_E when unable to allocate memory and + * 0 otherwise. + */ +static int TLSX_EncryptThenMac_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + int ret; + + (void)input; + + if (msgType != client_hello && msgType != server_hello) { + return SANITY_MSG_E; + } + + /* Empty extension */ + if (length != 0) + return BUFFER_ERROR; + + if (msgType == client_hello) { + /* Check the user hasn't disallowed use of Encrypt-Then-Mac. */ + if (!ssl->options.disallowEncThenMac) { + ssl->options.encThenMac = 1; + /* Set the extension reply. */ + ret = TLSX_EncryptThenMac_Use(ssl); + if (ret != 0) + return ret; + TLSX_SetResponse(ssl, TLSX_ENCRYPT_THEN_MAC); + } + return 0; + } + + /* Server Hello */ + if (ssl->options.disallowEncThenMac) + return SANITY_MSG_E; + + ssl->options.encThenMac = 1; + return 0; + +} + +/** + * Add the Encrypt-Then-MAC extension to list. + * + * ssl SSL object + * return MEMORY_E when unable to allocate memory and 0 otherwise. + */ +static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + + /* Find the Encrypt-Then-Mac extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_ENCRYPT_THEN_MAC); + if (extension == NULL) { + /* Push new Encrypt-Then-Mac extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_ENCRYPT_THEN_MAC, NULL, + ssl->heap); + if (ret != 0) + return ret; + } + + return 0; +} + +#define ETM_GET_SIZE TLSX_EncryptThenMac_GetSize +#define ETM_WRITE TLSX_EncryptThenMac_Write +#define ETM_PARSE TLSX_EncryptThenMac_Parse + +#else + +#define ETM_GET_SIZE(a, b) 0 +#define ETM_WRITE(a, b, c, d) 0 +#define ETM_PARSE(a, b, c, d) 0 + +#endif /* !WOLFSSL_NO_TLS12 */ + +#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ + +/******************************************************************************/ +/* Supported Versions */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +/* Return the size of the SupportedVersions extension's data. + * + * data The SSL/TLS object. + * msgType The type of the message this extension is being written into. + * returns the length of data that will be in the extension. + */ +static int TLSX_SupportedVersions_GetSize(void* data, byte msgType, word16* pSz) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + + if (msgType == client_hello) { + /* TLS v1.2 and TLS v1.3 */ + int cnt = 0; + + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == 0) + #endif + cnt++; + + if (ssl->options.downgrade) { +#ifndef WOLFSSL_NO_TLS12 + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == 0) + #endif + cnt++; +#endif + +#ifndef NO_OLD_TLS + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == 0) + #endif + cnt++; + #ifdef WOLFSSL_ALLOW_TLSV10 + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1) == 0) + #endif + cnt++; + #endif +#endif + } + + *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN); + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else if (msgType == server_hello || msgType == hello_retry_request) + *pSz += OPAQUE16_LEN; +#endif + else + return SANITY_MSG_E; + + return 0; +} + +/* Writes the SupportedVersions extension into the buffer. + * + * data The SSL/TLS object. + * output The buffer to write the extension into. + * msgType The type of the message this extension is being written into. + * returns the length of data that was written. + */ +static int TLSX_SupportedVersions_Write(void* data, byte* output, + byte msgType, word16* pSz) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + byte major; + byte* cnt; + + if (msgType == client_hello) { + major = ssl->ctx->method->version.major; + + + cnt = output++; + *cnt = 0; + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == 0) + #endif + { + *cnt += OPAQUE16_LEN; +#ifdef WOLFSSL_TLS13_DRAFT + /* The TLS draft major number. */ + *(output++) = TLS_DRAFT_MAJOR; + /* Version of draft supported. */ + *(output++) = TLS_DRAFT_MINOR; +#else + *(output++) = major; + *(output++) = (byte)TLSv1_3_MINOR; +#endif + } + if (ssl->options.downgrade) { +#ifndef WOLFSSL_NO_TLS12 + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == 0) + #endif + { + *cnt += OPAQUE16_LEN; + *(output++) = major; + *(output++) = (byte)TLSv1_2_MINOR; + } +#endif + +#ifndef NO_OLD_TLS + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == 0) + #endif + { + *cnt += OPAQUE16_LEN; + *(output++) = major; + *(output++) = (byte)TLSv1_1_MINOR; + } + #ifdef WOLFSSL_ALLOW_TLSV10 + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if ((ssl->options.mask & SSL_OP_NO_TLSv1) == 0) + #endif + { + *cnt += OPAQUE16_LEN; + *(output++) = major; + *(output++) = (byte)TLSv1_MINOR; + } + #endif +#endif + } + + *pSz += (word16)(OPAQUE8_LEN + *cnt); + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else if (msgType == server_hello || msgType == hello_retry_request) { + #ifdef WOLFSSL_TLS13_DRAFT + if (ssl->version.major == SSLv3_MAJOR && + ssl->version.minor == TLSv1_3_MINOR) { + output[0] = TLS_DRAFT_MAJOR; + output[1] = TLS_DRAFT_MINOR; + } + else + #endif + { + output[0] = ssl->version.major; + output[1] = ssl->version.minor; + } + + *pSz += OPAQUE16_LEN; + } +#endif + else + return SANITY_MSG_E; + + return 0; +} + +/* Parse the SupportedVersions extension. + * + * ssl The SSL/TLS object. + * input The buffer with the extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SupportedVersions_Parse(WOLFSSL* ssl, byte* input, + word16 length, byte msgType) +{ + ProtocolVersion pv = ssl->ctx->method->version; + int i; + int len; + byte major, minor; + int newMinor = 0; + int set = 0; + + if (msgType == client_hello) { + /* Must contain a length and at least one version. */ + if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1) + return BUFFER_ERROR; + + len = *input; + + /* Protocol version array must fill rest of data. */ + if (length != (word16)OPAQUE8_LEN + len) + return BUFFER_ERROR; + + input++; + + /* Find first match. */ + for (i = 0; i < len; i += OPAQUE16_LEN) { + major = input[i]; + minor = input[i + OPAQUE8_LEN]; + +#ifdef WOLFSSL_TLS13_DRAFT + if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) { + major = SSLv3_MAJOR; + minor = TLSv1_3_MINOR; + } +#else + if (major == TLS_DRAFT_MAJOR) + continue; +#endif + + if (major != pv.major) + continue; + + /* No upgrade allowed. */ + if (minor > ssl->version.minor) + continue; + /* Check downgrade. */ + if (minor < ssl->version.minor) { + if (!ssl->options.downgrade) + continue; + + if (minor < ssl->options.minDowngrade) + continue; + + if (newMinor == 0 && minor > ssl->options.oldMinor) { + /* Downgrade the version. */ + ssl->version.minor = minor; + } + } + + if (minor >= TLSv1_3_MINOR) { + if (!ssl->options.tls1_3) { + ssl->options.tls1_3 = 1; + TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, ssl, + ssl->heap); +#ifndef WOLFSSL_TLS13_DRAFT_18 + TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS); +#endif + } + if (minor > newMinor) { + ssl->version.minor = minor; + newMinor = minor; + } + } + else if (minor > ssl->options.oldMinor) + ssl->options.oldMinor = minor; + + set = 1; + } + if (!set) { + #ifdef WOLFSSL_MYSQL_COMPATIBLE + SendAlert(ssl, alert_fatal, wc_protocol_version); + #else + SendAlert(ssl, alert_fatal, protocol_version); + #endif + return VERSION_ERROR; + } + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else if (msgType == server_hello || msgType == hello_retry_request) { + /* Must contain one version. */ + if (length != OPAQUE16_LEN) + return BUFFER_ERROR; + + major = input[0]; + minor = input[OPAQUE8_LEN]; + + #ifdef WOLFSSL_TLS13_DRAFT + if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) { + major = SSLv3_MAJOR; + minor = TLSv1_3_MINOR; + } + #endif + + if (major != pv.major) + return VERSION_ERROR; + + /* Can't downgrade with this extension below TLS v1.3. */ + if (minor < TLSv1_3_MINOR) + return VERSION_ERROR; + + /* Version is TLS v1.2 to handle downgrading from TLS v1.3+. */ + if (ssl->options.downgrade && ssl->version.minor == TLSv1_2_MINOR) { + /* Set minor version back to TLS v1.3+ */ + ssl->version.minor = ssl->ctx->method->version.minor; + } + + /* No upgrade allowed. */ + if (ssl->version.minor < minor) + return VERSION_ERROR; + + /* Check downgrade. */ + if (ssl->version.minor > minor) { + if (!ssl->options.downgrade) + return VERSION_ERROR; + + if (minor < ssl->options.minDowngrade) + return VERSION_ERROR; + + /* Downgrade the version. */ + ssl->version.minor = minor; + } + } +#endif + else + return SANITY_MSG_E; + + return 0; +} + +/* Sets a new SupportedVersions extension into the extension list. + * + * extensions The list of extensions. + * data The extensions specific data. + * heap The heap used for allocation. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data, + void* heap) +{ + if (extensions == NULL || data == NULL) + return BAD_FUNC_ARG; + + return TLSX_Push(extensions, TLSX_SUPPORTED_VERSIONS, (void *)data, heap); +} + +#define SV_GET_SIZE TLSX_SupportedVersions_GetSize +#define SV_WRITE TLSX_SupportedVersions_Write +#define SV_PARSE TLSX_SupportedVersions_Parse + +#else + +#define SV_GET_SIZE(a, b, c) 0 +#define SV_WRITE(a, b, c, d) 0 +#define SV_PARSE(a, b, c, d) 0 + +#endif /* WOLFSSL_TLS13 */ + +#if defined(WOLFSSL_TLS13) + +/******************************************************************************/ +/* Cookie */ +/******************************************************************************/ + +/* Free the cookie data. + * + * cookie Cookie data. + * heap The heap used for allocation. + */ +static void TLSX_Cookie_FreeAll(Cookie* cookie, void* heap) +{ + (void)heap; + + if (cookie != NULL) + XFREE(cookie, heap, DYNAMIC_TYPE_TLSX); +} + +/* Get the size of the encoded Cookie extension. + * In messages: ClientHello and HelloRetryRequest. + * + * cookie The cookie to write. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded Cookie extension. + */ +static int TLSX_Cookie_GetSize(Cookie* cookie, byte msgType, word16* pSz) +{ + if (msgType == client_hello || msgType == hello_retry_request) + *pSz += OPAQUE16_LEN + cookie->len; + else + return SANITY_MSG_E; + return 0; +} + +/* Writes the Cookie extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * In messages: ClientHello and HelloRetryRequest. + * + * cookie The cookie to write. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static int TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType, + word16* pSz) +{ + if (msgType == client_hello || msgType == hello_retry_request) { + c16toa(cookie->len, output); + output += OPAQUE16_LEN; + XMEMCPY(output, &cookie->data, cookie->len); + *pSz += OPAQUE16_LEN + cookie->len; + } + else + return SANITY_MSG_E; + return 0; +} + +/* Parse the Cookie extension. + * In messages: ClientHello and HelloRetryRequest. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_Cookie_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + word16 len; + word16 idx = 0; + TLSX* extension; + Cookie* cookie; + + if (msgType != client_hello && msgType != hello_retry_request) + return SANITY_MSG_E; + + /* Message contains length and Cookie which must be at least one byte + * in length. + */ + if (length < OPAQUE16_LEN + 1) + return BUFFER_E; + ato16(input + idx, &len); + idx += OPAQUE16_LEN; + if (length - idx != len) + return BUFFER_E; + + if (msgType == hello_retry_request) + return TLSX_Cookie_Use(ssl, input + idx, len, NULL, 0, 0); + + /* client_hello */ + extension = TLSX_Find(ssl->extensions, TLSX_COOKIE); + if (extension == NULL) + return HRR_COOKIE_ERROR; + + cookie = (Cookie*)extension->data; + if (cookie->len != len || XMEMCMP(&cookie->data, input + idx, len) != 0) + return HRR_COOKIE_ERROR; + + /* Request seen. */ + extension->resp = 0; + + return 0; +} + +/* Use the data to create a new Cookie object in the extensions. + * + * ssl SSL/TLS object. + * data Cookie data. + * len Length of cookie data in bytes. + * mac MAC data. + * macSz Length of MAC data in bytes. + * resp Indicates the extension will go into a response (HelloRetryRequest). + * returns 0 on success and other values indicate failure. + */ +int TLSX_Cookie_Use(WOLFSSL* ssl, byte* data, word16 len, byte* mac, + byte macSz, int resp) +{ + int ret = 0; + TLSX* extension; + Cookie* cookie; + + /* Find the cookie extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_COOKIE); + if (extension == NULL) { + /* Push new cookie extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_COOKIE, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_COOKIE); + if (extension == NULL) + return MEMORY_E; + } + + /* The Cookie structure has one byte for cookie data already. */ + cookie = (Cookie*)XMALLOC(sizeof(Cookie) + len + macSz - 1, ssl->heap, + DYNAMIC_TYPE_TLSX); + if (cookie == NULL) + return MEMORY_E; + + cookie->len = len + macSz; + XMEMCPY(&cookie->data, data, len); + if (mac != NULL) + XMEMCPY(&cookie->data + len, mac, macSz); + + extension->data = (void*)cookie; + extension->resp = (byte)resp; + + return 0; +} + +#define CKE_FREE_ALL TLSX_Cookie_FreeAll +#define CKE_GET_SIZE TLSX_Cookie_GetSize +#define CKE_WRITE TLSX_Cookie_Write +#define CKE_PARSE TLSX_Cookie_Parse + +#else + +#define CKE_FREE_ALL(a, b) 0 +#define CKE_GET_SIZE(a, b, c) 0 +#define CKE_WRITE(a, b, c, d) 0 +#define CKE_PARSE(a, b, c, d) 0 + +#endif +#if !defined(WOLFSSL_NO_SIGALG) +/******************************************************************************/ +/* Signature Algorithms */ +/******************************************************************************/ + +/* Return the size of the SignatureAlgorithms extension's data. + * + * data Unused + * returns the length of data that will be in the extension. + */ + +static word16 TLSX_SignatureAlgorithms_GetSize(void* data) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + + return OPAQUE16_LEN + ssl->suites->hashSigAlgoSz; +} + +/* Creates a bit string of supported hash algorithms with RSA PSS. + * The bit string is used when determining which signature algorithm to use + * when creating the CertificateVerify message. + * Note: Valid data has an even length as each signature algorithm is two bytes. + * + * ssl The SSL/TLS object. + * input The buffer with the list of supported signature algorithms. + * length The length of the list in bytes. + * returns 0 on success, BUFFER_ERROR when the length is not even. + */ +static int TLSX_SignatureAlgorithms_MapPss(WOLFSSL *ssl, byte* input, + word16 length) +{ + word16 i; + + if ((length & 1) == 1) + return BUFFER_ERROR; + + ssl->pssAlgo = 0; + for (i = 0; i < length; i += 2) { + if (input[i] == rsa_pss_sa_algo && input[i + 1] <= sha512_mac) + ssl->pssAlgo |= 1 << input[i + 1]; + #ifdef WOLFSSL_TLS13 + if (input[i] == rsa_pss_sa_algo && input[i + 1] >= pss_sha256 && + input[i + 1] <= pss_sha512) { + ssl->pssAlgo |= 1 << input[i + 1]; + } + #endif + } + + return 0; +} + +/* Writes the SignatureAlgorithms extension into the buffer. + * + * data Unused + * output The buffer to write the extension into. + * returns the length of data that was written. + */ +static word16 TLSX_SignatureAlgorithms_Write(void* data, byte* output) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + + c16toa(ssl->suites->hashSigAlgoSz, output); + XMEMCPY(output + OPAQUE16_LEN, ssl->suites->hashSigAlgo, + ssl->suites->hashSigAlgoSz); + + TLSX_SignatureAlgorithms_MapPss(ssl, output + OPAQUE16_LEN, + ssl->suites->hashSigAlgoSz); + + return OPAQUE16_LEN + ssl->suites->hashSigAlgoSz; +} + +/* Parse the SignatureAlgorithms extension. + * + * ssl The SSL/TLS object. + * input The buffer with the extension data. + * length The length of the extension data. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input, + word16 length, byte isRequest, Suites* suites) +{ + word16 len; + + if (!isRequest) + return BUFFER_ERROR; + + /* Must contain a length and at least algorithm. */ + if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0) + return BUFFER_ERROR; + + ato16(input, &len); + input += OPAQUE16_LEN; + + /* Algorithm array must fill rest of data. */ + if (length != OPAQUE16_LEN + len) + return BUFFER_ERROR; + + /* truncate hashSigAlgo list if too long */ + suites->hashSigAlgoSz = len; + if (suites->hashSigAlgoSz > WOLFSSL_MAX_SIGALGO) { + WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating"); + suites->hashSigAlgoSz = WOLFSSL_MAX_SIGALGO; + } + XMEMCPY(suites->hashSigAlgo, input, suites->hashSigAlgoSz); + + return TLSX_SignatureAlgorithms_MapPss(ssl, input, len); +} + +/* Sets a new SignatureAlgorithms extension into the extension list. + * + * extensions The list of extensions. + * data The extensions specific data. + * heap The heap used for allocation. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SetSignatureAlgorithms(TLSX** extensions, const void* data, + void* heap) +{ + if (extensions == NULL) + return BAD_FUNC_ARG; + + return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS, (void *)data, heap); +} + +#define SA_GET_SIZE TLSX_SignatureAlgorithms_GetSize +#define SA_WRITE TLSX_SignatureAlgorithms_Write +#define SA_PARSE TLSX_SignatureAlgorithms_Parse +#endif +/******************************************************************************/ +/* Signature Algorithms Certificate */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) +/* Return the size of the SignatureAlgorithms extension's data. + * + * data Unused + * returns the length of data that will be in the extension. + */ +static word16 TLSX_SignatureAlgorithmsCert_GetSize(void* data) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + + return OPAQUE16_LEN + ssl->certHashSigAlgoSz; +} + +/* Writes the SignatureAlgorithmsCert extension into the buffer. + * + * data Unused + * output The buffer to write the extension into. + * returns the length of data that was written. + */ +static word16 TLSX_SignatureAlgorithmsCert_Write(void* data, byte* output) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + + c16toa(ssl->certHashSigAlgoSz, output); + XMEMCPY(output + OPAQUE16_LEN, ssl->certHashSigAlgo, + ssl->certHashSigAlgoSz); + + return OPAQUE16_LEN + ssl->certHashSigAlgoSz; +} + +/* Parse the SignatureAlgorithmsCert extension. + * + * ssl The SSL/TLS object. + * input The buffer with the extension data. + * length The length of the extension data. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SignatureAlgorithmsCert_Parse(WOLFSSL *ssl, byte* input, + word16 length, byte isRequest) +{ + word16 len; + + if (!isRequest) + return BUFFER_ERROR; + + /* Must contain a length and at least algorithm. */ + if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0) + return BUFFER_ERROR; + + ato16(input, &len); + input += OPAQUE16_LEN; + + /* Algorithm array must fill rest of data. */ + if (length != OPAQUE16_LEN + len) + return BUFFER_ERROR; + + /* truncate hashSigAlgo list if too long */ + ssl->certHashSigAlgoSz = len; + if (ssl->certHashSigAlgoSz > WOLFSSL_MAX_SIGALGO) { + WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating"); + ssl->certHashSigAlgoSz = WOLFSSL_MAX_SIGALGO; + } + XMEMCPY(ssl->certHashSigAlgo, input, ssl->certHashSigAlgoSz); + + return 0; +} + +/* Sets a new SignatureAlgorithmsCert extension into the extension list. + * + * extensions The list of extensions. + * data The extensions specific data. + * heap The heap used for allocation. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SetSignatureAlgorithmsCert(TLSX** extensions, const void* data, + void* heap) +{ + if (extensions == NULL) + return BAD_FUNC_ARG; + + return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS_CERT, (void *)data, + heap); +} + +#define SAC_GET_SIZE TLSX_SignatureAlgorithmsCert_GetSize +#define SAC_WRITE TLSX_SignatureAlgorithmsCert_Write +#define SAC_PARSE TLSX_SignatureAlgorithmsCert_Parse +#endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */ +#endif /* WOLFSSL_TLS13 */ + + +/******************************************************************************/ +/* Key Share */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +/* Create a key share entry using named Diffie-Hellman parameters group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret; +#ifndef NO_DH + byte* keyData; + void* key = NULL; + word32 keySz; + word32 dataSz; + const DhParams* params; +#ifdef WOLFSSL_SMALL_STACK + DhKey* dhKey = NULL; +#else + DhKey dhKey[1]; +#endif + + /* TODO: [TLS13] The key size should come from wolfcrypt. */ + /* Pick the parameters from the named group. */ + switch (kse->group) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + params = wc_Dh_ffdhe2048_Get(); + keySz = 29; + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + params = wc_Dh_ffdhe3072_Get(); + keySz = 34; + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + params = wc_Dh_ffdhe4096_Get(); + keySz = 39; + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + params = wc_Dh_ffdhe6144_Get(); + keySz = 46; + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + params = wc_Dh_ffdhe8192_Get(); + keySz = 52; + break; + #endif + default: + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH); + if (dhKey == NULL) + return MEMORY_E; +#endif + + ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId); + if (ret != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); + #endif + return ret; + } + + /* Allocate space for the public key. */ + dataSz = params->p_len; + keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (keyData == NULL) { + ret = MEMORY_E; + goto end; + } + /* Allocate space for the private key. */ + key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + if (key == NULL) { + ret = MEMORY_E; + goto end; + } + + /* Set key */ + ret = wc_DhSetKey(dhKey, + (byte*)params->p, params->p_len, + (byte*)params->g, params->g_len); + if (ret != 0) + goto end; + + /* Generate a new key pair. */ + ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData, + &dataSz); +#ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE); + } +#endif + if (ret != 0) + goto end; + + if (params->p_len != dataSz) { + /* Pad the front of the key data with zeros. */ + XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz); + XMEMSET(keyData, 0, params->p_len - dataSz); + } + + kse->pubKey = keyData; + kse->pubKeyLen = params->p_len; + kse->key = key; + kse->keyLen = keySz; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public DH Key"); + WOLFSSL_BUFFER(keyData, params->p_len); +#endif + +end: + + wc_FreeDhKey(dhKey); +#ifdef WOLFSSL_SMALL_STACK + XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); +#endif + + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + if (keyData != NULL) + XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (key != NULL) + XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + } +#else + (void)ssl; + (void)kse; + + ret = NOT_COMPILED_IN; +#endif + + return ret; +} + +/* Create a key share entry using X25519 parameters group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret; +#ifdef HAVE_CURVE25519 + byte* keyData = NULL; + word32 dataSize = CURVE25519_KEYSIZE; + curve25519_key* key; + + /* Allocate an ECC key to hold private key. */ + key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (key == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + + /* Make an ECC key. */ + ret = wc_curve25519_init(key); + if (ret != 0) + goto end; + ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key); + if (ret != 0) + goto end; + + /* Allocate space for the public key. */ + keyData = (byte*)XMALLOC(CURVE25519_KEYSIZE, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (keyData == NULL) { + WOLFSSL_MSG("Key data Memory error"); + ret = MEMORY_E; + goto end; + } + + /* Export public key. */ + if (wc_curve25519_export_public_ex(key, keyData, &dataSize, + EC25519_LITTLE_ENDIAN) != 0) { + ret = ECC_EXPORT_ERROR; + goto end; + } + + kse->pubKey = keyData; + kse->pubKeyLen = CURVE25519_KEYSIZE; + kse->key = key; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public Curve25519 Key"); + WOLFSSL_BUFFER(keyData, dataSize); +#endif + +end: + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + if (keyData != NULL) + XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + wc_curve25519_free(key); + XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + } +#else + (void)ssl; + (void)kse; + + ret = NOT_COMPILED_IN; +#endif /* HAVE_CURVE25519 */ + + return ret; +} + +/* Create a key share entry using X448 parameters group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenX448Key(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret; +#ifdef HAVE_CURVE448 + byte* keyData = NULL; + word32 dataSize = CURVE448_KEY_SIZE; + curve448_key* key; + + /* Allocate an ECC key to hold private key. */ + key = (curve448_key*)XMALLOC(sizeof(curve448_key), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (key == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + + /* Make an ECC key. */ + ret = wc_curve448_init(key); + if (ret != 0) + goto end; + ret = wc_curve448_make_key(ssl->rng, CURVE448_KEY_SIZE, key); + if (ret != 0) + goto end; + + /* Allocate space for the public key. */ + keyData = (byte*)XMALLOC(CURVE448_KEY_SIZE, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (keyData == NULL) { + WOLFSSL_MSG("Key data Memory error"); + ret = MEMORY_E; + goto end; + } + + /* Export public key. */ + if (wc_curve448_export_public_ex(key, keyData, &dataSize, + EC448_LITTLE_ENDIAN) != 0) { + ret = ECC_EXPORT_ERROR; + goto end; + } + + kse->pubKey = keyData; + kse->pubKeyLen = CURVE448_KEY_SIZE; + kse->key = key; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public Curve448 Key"); + WOLFSSL_BUFFER(keyData, dataSize); +#endif + +end: + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + if (keyData != NULL) + XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + wc_curve448_free(key); + XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + } +#else + (void)ssl; + (void)kse; + + ret = NOT_COMPILED_IN; +#endif /* HAVE_CURVE448 */ + + return ret; +} + +/* Create a key share entry using named elliptic curve parameters group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret; +#ifdef HAVE_ECC + byte* keyData = NULL; + word32 dataSize; + byte* keyPtr = NULL; + word32 keySize; + ecc_key* eccKey; + word16 curveId; + + /* TODO: [TLS13] The key sizes should come from wolfcrypt. */ + /* Translate named group to a curve id. */ + switch (kse->group) { + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + curveId = ECC_SECP256R1; + keySize = 32; + dataSize = keySize * 2 + 1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + curveId = ECC_SECP384R1; + keySize = 48; + dataSize = keySize * 2 + 1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + curveId = ECC_SECP521R1; + keySize = 66; + dataSize = keySize * 2 + 1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #ifdef HAVE_X448 + case WOLFSSL_ECC_X448: + curveId = ECC_X448; + dataSize = keySize = 56; + break; + #endif + default: + return BAD_FUNC_ARG; + } + + /* Allocate an ECC key to hold private key. */ + keyPtr = (byte*)XMALLOC(sizeof(ecc_key), ssl->heap, + DYNAMIC_TYPE_PRIVATE_KEY); + if (keyPtr == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + eccKey = (ecc_key*)keyPtr; + + /* Make an ECC key. */ + ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId); + if (ret != 0) + goto end; + ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId); +#ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE); + } +#endif + if (ret != 0) + goto end; + + /* Allocate space for the public key. */ + keyData = (byte*)XMALLOC(dataSize, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (keyData == NULL) { + WOLFSSL_MSG("Key data Memory error"); + ret = MEMORY_E; + goto end; + } + + /* Export public key. */ + if (wc_ecc_export_x963(eccKey, keyData, &dataSize) != 0) { + ret = ECC_EXPORT_ERROR; + goto end; + } + + kse->pubKey = keyData; + kse->pubKeyLen = dataSize; + kse->key = keyPtr; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public ECC Key"); + WOLFSSL_BUFFER(keyData, dataSize); +#endif + +end: + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + if (keyPtr != NULL) + XFREE(keyPtr, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + if (keyData != NULL) + XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } +#else + (void)ssl; + (void)kse; + + ret = NOT_COMPILED_IN; +#endif /* HAVE_ECC */ + + return ret; +} + +/* Generate a secret/key using the key share entry. + * + * ssl The SSL/TLS object. + * kse The key share entry holding peer data. + */ +static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse) +{ + /* Named FFHE groups have a bit set to identify them. */ + if ((kse->group & NAMED_DH_MASK) == NAMED_DH_MASK) + return TLSX_KeyShare_GenDhKey(ssl, kse); + if (kse->group == WOLFSSL_ECC_X25519) + return TLSX_KeyShare_GenX25519Key(ssl, kse); + if (kse->group == WOLFSSL_ECC_X448) + return TLSX_KeyShare_GenX448Key(ssl, kse); + return TLSX_KeyShare_GenEccKey(ssl, kse); +} + +/* Free the key share dynamic data. + * + * list The linked list of key share entry objects. + * heap The heap used for allocation. + */ +static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) +{ + KeyShareEntry* current; + + while ((current = list) != NULL) { + list = current->next; + if ((current->group & NAMED_DH_MASK) == 0) { + if (current->group == WOLFSSL_ECC_X25519) { +#ifdef HAVE_CURVE25519 + wc_curve25519_free((curve25519_key*)current->key); +#endif + } + else if (current->group == WOLFSSL_ECC_X448) { +#ifdef HAVE_CURVE448 + wc_curve448_free((curve448_key*)current->key); +#endif + } + else { +#ifdef HAVE_ECC + wc_ecc_free((ecc_key*)(current->key)); +#endif + } + } + if (current->key != NULL) + XFREE(current->key, heap, DYNAMIC_TYPE_PRIVATE_KEY); + XFREE(current->pubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(current->ke, heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(current, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +/* Get the size of the encoded key share extension. + * + * list The linked list of key share extensions. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded key share extension. + */ +static word16 TLSX_KeyShare_GetSize(KeyShareEntry* list, byte msgType) +{ + word16 len = 0; + byte isRequest = (msgType == client_hello); + KeyShareEntry* current; + + /* The named group the server wants to use. */ + if (msgType == hello_retry_request) + return OPAQUE16_LEN; + + /* List of key exchange groups. */ + if (isRequest) + len += OPAQUE16_LEN; + while ((current = list) != NULL) { + list = current->next; + + if (!isRequest && current->key == NULL) + continue; + + len += KE_GROUP_LEN + OPAQUE16_LEN + current->pubKeyLen; + } + + return len; +} + +/* Writes the key share extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * + * list The linked list of key share entries. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static word16 TLSX_KeyShare_Write(KeyShareEntry* list, byte* output, + byte msgType) +{ + word16 i = 0; + byte isRequest = (msgType == client_hello); + KeyShareEntry* current; + + if (msgType == hello_retry_request) { + c16toa(list->group, output); + return OPAQUE16_LEN; + } + + /* ClientHello has a list but ServerHello is only the chosen. */ + if (isRequest) + i += OPAQUE16_LEN; + + /* Write out all in the list. */ + while ((current = list) != NULL) { + list = current->next; + + if (!isRequest && current->key == NULL) + continue; + + c16toa(current->group, &output[i]); + i += KE_GROUP_LEN; + c16toa((word16)(current->pubKeyLen), &output[i]); + i += OPAQUE16_LEN; + XMEMCPY(&output[i], current->pubKey, current->pubKeyLen); + i += (word16)current->pubKeyLen; + } + /* Write the length of the list if required. */ + if (isRequest) + c16toa(i - OPAQUE16_LEN, output); + + return i; +} + +/* Process the DH key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ +#ifndef NO_DH + int ret; + const DhParams* params; +#ifdef WOLFSSL_SMALL_STACK + DhKey* dhKey = NULL; +#else + DhKey dhKey[1]; +#endif + + switch (keyShareEntry->group) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + params = wc_Dh_ffdhe2048_Get(); + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + params = wc_Dh_ffdhe3072_Get(); + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + params = wc_Dh_ffdhe4096_Get(); + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + params = wc_Dh_ffdhe6144_Get(); + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + params = wc_Dh_ffdhe8192_Get(); + break; + #endif + default: + return PEER_KEY_ERROR; + } + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Peer DH Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); +#endif + +#ifdef WOLFSSL_SMALL_STACK + dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH); + if (dhKey == NULL) + return MEMORY_E; +#endif + + ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId); + if (ret != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); + #endif + return ret; + } + + /* Set key */ + ret = wc_DhSetKey(dhKey, (byte*)params->p, params->p_len, (byte*)params->g, + params->g_len); + if (ret != 0) { + wc_FreeDhKey(dhKey); + #ifdef WOLFSSL_SMALL_STACK + XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); + #endif + return ret; + } + + ret = wc_DhCheckPubKey(dhKey, keyShareEntry->ke, keyShareEntry->keLen); + if (ret != 0) { + wc_FreeDhKey(dhKey); + #ifdef WOLFSSL_SMALL_STACK + XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); + #endif + return PEER_KEY_ERROR; + } + + /* Derive secret from private key and peer's public key. */ + ret = wc_DhAgree(dhKey, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, + (const byte*)keyShareEntry->key, keyShareEntry->keyLen, + keyShareEntry->ke, keyShareEntry->keLen); +#ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE); + } +#endif + /* RFC 8446 Section 7.4.1: + * ... left-padded with zeros up to the size of the prime. ... + */ + if (params->p_len > ssl->arrays->preMasterSz) { + word32 diff = params->p_len - ssl->arrays->preMasterSz; + XMEMMOVE(ssl->arrays->preMasterSecret + diff, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); + XMEMSET(ssl->arrays->preMasterSecret, 0, diff); + ssl->arrays->preMasterSz = params->p_len; + } + + ssl->options.dhKeySz = params->p_len; + + wc_FreeDhKey(dhKey); +#ifdef WOLFSSL_SMALL_STACK + XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); +#endif + if (keyShareEntry->key != NULL) { + XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + keyShareEntry->key = NULL; + } + XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + keyShareEntry->pubKey = NULL; + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + keyShareEntry->ke = NULL; + + return ret; +#else + (void)ssl; + (void)keyShareEntry; + return PEER_KEY_ERROR; +#endif +} + +/* Process the X25519 key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl, + KeyShareEntry* keyShareEntry) +{ + int ret; + +#ifdef HAVE_CURVE25519 + curve25519_key* key = (curve25519_key*)keyShareEntry->key; + curve25519_key* peerX25519Key; + +#ifdef HAVE_ECC + if (ssl->peerEccKey != NULL) { + wc_ecc_free(ssl->peerEccKey); + ssl->peerEccKey = NULL; + } +#endif + + peerX25519Key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (peerX25519Key == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + return MEMORY_ERROR; + } + ret = wc_curve25519_init(peerX25519Key); + if (ret != 0) { + XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX); + return ret; + } +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Peer Curve25519 Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); +#endif + + if (wc_curve25519_check_public(keyShareEntry->ke, keyShareEntry->keLen, + EC25519_LITTLE_ENDIAN) != 0) { + ret = ECC_PEERKEY_ERROR; + } + + if (ret == 0) { + if (wc_curve25519_import_public_ex(keyShareEntry->ke, + keyShareEntry->keLen, peerX25519Key, + EC25519_LITTLE_ENDIAN) != 0) { + ret = ECC_PEERKEY_ERROR; + } + } + + if (ret == 0) { + ssl->ecdhCurveOID = ECC_X25519_OID; + + ret = wc_curve25519_shared_secret_ex(key, peerX25519Key, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + EC25519_LITTLE_ENDIAN); + } + + wc_curve25519_free(peerX25519Key); + XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX); + wc_curve25519_free((curve25519_key*)keyShareEntry->key); + if (keyShareEntry->key != NULL) { + XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + keyShareEntry->key = NULL; + } +#else + (void)ssl; + (void)keyShareEntry; + + ret = PEER_KEY_ERROR; +#endif /* HAVE_CURVE25519 */ + + return ret; +} + +/* Process the X448 key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ + int ret; + +#ifdef HAVE_CURVE448 + curve448_key* key = (curve448_key*)keyShareEntry->key; + curve448_key* peerX448Key; + +#ifdef HAVE_ECC + if (ssl->peerEccKey != NULL) { + wc_ecc_free(ssl->peerEccKey); + ssl->peerEccKey = NULL; + } +#endif + + peerX448Key = (curve448_key*)XMALLOC(sizeof(curve448_key), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (peerX448Key == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + return MEMORY_ERROR; + } + ret = wc_curve448_init(peerX448Key); + if (ret != 0) { + XFREE(peerX448Key, ssl->heap, DYNAMIC_TYPE_TLSX); + return ret; + } +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Peer Curve448 Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); +#endif + + if (wc_curve448_check_public(keyShareEntry->ke, keyShareEntry->keLen, + EC448_LITTLE_ENDIAN) != 0) { + ret = ECC_PEERKEY_ERROR; + } + + if (ret == 0) { + if (wc_curve448_import_public_ex(keyShareEntry->ke, + keyShareEntry->keLen, peerX448Key, + EC448_LITTLE_ENDIAN) != 0) { + ret = ECC_PEERKEY_ERROR; + } + } + + if (ret == 0) { + ssl->ecdhCurveOID = ECC_X448_OID; + + ret = wc_curve448_shared_secret_ex(key, peerX448Key, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + EC448_LITTLE_ENDIAN); + } + + wc_curve448_free(peerX448Key); + XFREE(peerX448Key, ssl->heap, DYNAMIC_TYPE_TLSX); + wc_curve448_free((curve448_key*)keyShareEntry->key); + if (keyShareEntry->key != NULL) { + XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + keyShareEntry->key = NULL; + } +#else + (void)ssl; + (void)keyShareEntry; + + ret = PEER_KEY_ERROR; +#endif /* HAVE_CURVE448 */ + + return ret; +} + +/* Process the ECC key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ + int ret; + +#ifdef HAVE_ECC + int curveId; + ecc_key* keyShareKey = (ecc_key*)keyShareEntry->key; + + if (ssl->peerEccKey != NULL) + wc_ecc_free(ssl->peerEccKey); + + ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap, + DYNAMIC_TYPE_ECC); + if (ssl->peerEccKey == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + return MEMORY_ERROR; + } + ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + + /* find supported curve */ + switch (keyShareEntry->group) { + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + curveId = ECC_SECP256R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + curveId = ECC_SECP384R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + curveId = ECC_SECP521R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #ifdef HAVE_X448 + case WOLFSSL_ECC_X448: + curveId = ECC_X448; + break; + #endif + default: + /* unsupported curve */ + return ECC_PEERKEY_ERROR; + } + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Peer ECC Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); +#endif + + /* Point is validated by import function. */ + if (wc_ecc_import_x963_ex(keyShareEntry->ke, keyShareEntry->keLen, + ssl->peerEccKey, curveId) != 0) { + return ECC_PEERKEY_ERROR; + } + ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum; + + do { + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &keyShareKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) + ret = wc_ecc_shared_secret(keyShareKey, ssl->peerEccKey, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz); + } while (ret == WC_PENDING_E); + +#if 0 + /* TODO: Switch to support async here and use: */ + ret = EccSharedSecret(ssl, keyShareEntry->key, ssl->peerEccKey, + keyShareEntry->ke, &keyShareEntry->keLen, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, + ssl->options.side + ); +#endif + + wc_ecc_free(ssl->peerEccKey); + XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->peerEccKey = NULL; + wc_ecc_free((ecc_key*)(keyShareEntry->key)); + if (keyShareEntry->key != NULL) { + XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); + keyShareEntry->key = NULL; + } + +#else + (void)ssl; + (void)keyShareEntry; + + ret = PEER_KEY_ERROR; +#endif /* HAVE_ECC */ + + return ret; +} + +/* Process the key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ + int ret; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + ssl->session.namedGroup = (byte)keyShareEntry->group; +#endif + /* Use Key Share Data from server. */ + if (keyShareEntry->group & NAMED_DH_MASK) + ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry); + else if (keyShareEntry->group == WOLFSSL_ECC_X25519) + ret = TLSX_KeyShare_ProcessX25519(ssl, keyShareEntry); + else if (keyShareEntry->group == WOLFSSL_ECC_X448) + ret = TLSX_KeyShare_ProcessX448(ssl, keyShareEntry); + else + ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry); + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("KE Secret"); + WOLFSSL_BUFFER(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); +#endif + + return ret; +} + +/* Parse an entry of the KeyShare extension. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * kse The new key share entry object. + * returns a positive number to indicate amount of data parsed and a negative + * number on error. + */ +static int TLSX_KeyShareEntry_Parse(WOLFSSL* ssl, byte* input, word16 length, + KeyShareEntry **kse) +{ + int ret; + word16 group; + word16 keLen; + int offset = 0; + byte* ke; + + if (length < OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_ERROR; + /* Named group */ + ato16(&input[offset], &group); + offset += OPAQUE16_LEN; + /* Key exchange data - public key. */ + ato16(&input[offset], &keLen); + offset += OPAQUE16_LEN; + if (keLen == 0) + return INVALID_PARAMETER; + if (keLen > length - offset) + return BUFFER_ERROR; + + /* Store a copy in the key share object. */ + ke = (byte*)XMALLOC(keLen, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ke == NULL) + return MEMORY_E; + XMEMCPY(ke, &input[offset], keLen); + + /* Populate a key share object in the extension. */ + ret = TLSX_KeyShare_Use(ssl, group, keLen, ke, kse); + if (ret != 0) { + XFREE(ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + return ret; + } + + /* Total length of the parsed data. */ + return offset + keLen; +} + +/* Searches the groups sent for the specified named group. + * + * ssl SSL/TLS object. + * name Group name to match. + * returns 1 when the extension has the group name and 0 otherwise. + */ +static int TLSX_KeyShare_Find(WOLFSSL* ssl, word16 group) +{ + TLSX* extension; + KeyShareEntry* list; + + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) { + extension = TLSX_Find(ssl->ctx->extensions, TLSX_KEY_SHARE); + if (extension == NULL) + return 0; + } + + list = (KeyShareEntry*)extension->data; + while (list != NULL) { + if (list->group == group) + return 1; + list = list->next; + } + + return 0; +} + + +/* Searches the supported groups extension for the specified named group. + * + * ssl The SSL/TLS object. + * name The group name to match. + * returns 1 when the extension has the group name and 0 otherwise. + */ +static int TLSX_SupportedGroups_Find(WOLFSSL* ssl, word16 name) +{ +#ifdef HAVE_SUPPORTED_CURVES + TLSX* extension; + SupportedCurve* curve = NULL; + + if ((extension = TLSX_Find(ssl->extensions, + TLSX_SUPPORTED_GROUPS)) == NULL) { + if ((extension = TLSX_Find(ssl->ctx->extensions, + TLSX_SUPPORTED_GROUPS)) == NULL) { + return 0; + } + } + + for (curve = (SupportedCurve*)extension->data; curve; curve = curve->next) { + if (curve->name == name) + return 1; + } +#endif + + (void)ssl; + (void)name; + + return 0; +} + + +/* Parse the KeyShare extension. + * Different formats in different messages. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + int ret; + KeyShareEntry *keyShareEntry = NULL; + word16 group; + + if (msgType == client_hello) { + int offset = 0; + word16 len; + TLSX* extension; + + /* Add a KeyShare extension if it doesn't exist. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) { + /* Push new KeyShare extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap); + if (ret != 0) + return ret; + } + + if (length < OPAQUE16_LEN) + return BUFFER_ERROR; + + /* ClientHello contains zero or more key share entries. */ + ato16(input, &len); + if (len != length - OPAQUE16_LEN) + return BUFFER_ERROR; + offset += OPAQUE16_LEN; + + while (offset < (int)length) { + ret = TLSX_KeyShareEntry_Parse(ssl, &input[offset], length - offset, + &keyShareEntry); + if (ret < 0) + return ret; + + offset += ret; + } + + ret = 0; + } + else if (msgType == server_hello) { + int len; + + if (length < OPAQUE16_LEN) + return BUFFER_ERROR; + + /* The data is the named group the server wants to use. */ + ato16(input, &group); + + /* Check the selected group was supported by ClientHello extensions. */ + if (!TLSX_SupportedGroups_Find(ssl, group)) + return BAD_KEY_SHARE_DATA; + + /* Check if the group was sent. */ + if (!TLSX_KeyShare_Find(ssl, group)) + return BAD_KEY_SHARE_DATA; + + /* ServerHello contains one key share entry. */ + len = TLSX_KeyShareEntry_Parse(ssl, input, length, &keyShareEntry); + if (len != (int)length) + return BUFFER_ERROR; + + /* Not in list sent if there isn't a private key. */ + if (keyShareEntry == NULL || keyShareEntry->key == NULL) + return BAD_KEY_SHARE_DATA; + + /* Process the entry to calculate the secret. */ + ret = TLSX_KeyShare_Process(ssl, keyShareEntry); + if (ret == 0) + ssl->session.namedGroup = ssl->namedGroup = group; + } + else if (msgType == hello_retry_request) { + if (length != OPAQUE16_LEN) + return BUFFER_ERROR; + + /* The data is the named group the server wants to use. */ + ato16(input, &group); + + /* Check the selected group was supported by ClientHello extensions. */ + if (!TLSX_SupportedGroups_Find(ssl, group)) + return BAD_KEY_SHARE_DATA; + + /* Check if the group was sent. */ + if (TLSX_KeyShare_Find(ssl, group)) + return BAD_KEY_SHARE_DATA; + + /* Clear out unusable key shares. */ + ret = TLSX_KeyShare_Empty(ssl); + if (ret != 0) + return ret; + + /* Try to use the server's group. */ + ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL); + } + else { + /* Not a message type that is allowed to have this extension. */ + return SANITY_MSG_E; + } + + return ret; +} + +/* Create a new key share entry and put it into the list. + * + * list The linked list of key share entries. + * group The named group. + * heap The memory to allocate with. + * keyShareEntry The new key share entry object. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap, + KeyShareEntry** keyShareEntry) +{ + KeyShareEntry* kse; + KeyShareEntry** next; + + kse = (KeyShareEntry*)XMALLOC(sizeof(KeyShareEntry), heap, + DYNAMIC_TYPE_TLSX); + if (kse == NULL) + return MEMORY_E; + + XMEMSET(kse, 0, sizeof(*kse)); + kse->group = (word16)group; + + /* Add it to the back and maintain the links. */ + while (*list != NULL) { + /* Assign to temporary to work around compiler bug found by customer. */ + next = &((*list)->next); + list = next; + } + *list = kse; + *keyShareEntry = kse; + + (void)heap; + + return 0; +} + +/* Use the data to create a new key share object in the extensions. + * + * ssl The SSL/TLS object. + * group The named group. + * len The length of the public key data. + * data The public key data. + * kse The new key share entry object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, byte* data, + KeyShareEntry **kse) +{ + int ret = 0; + TLSX* extension; + KeyShareEntry* keyShareEntry = NULL; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) { + /* Push new KeyShare extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) + return MEMORY_E; + } + extension->resp = 0; + + /* Try to find the key share entry with this group. */ + keyShareEntry = (KeyShareEntry*)extension->data; + while (keyShareEntry != NULL) { + if (keyShareEntry->group == group) + break; + keyShareEntry = keyShareEntry->next; + } + + /* Create a new key share entry if not found. */ + if (keyShareEntry == NULL) { + ret = TLSX_KeyShare_New((KeyShareEntry**)&extension->data, group, + ssl->heap, &keyShareEntry); + if (ret != 0) + return ret; + } + + if (data != NULL) { + if (keyShareEntry->ke != NULL) { + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + } + keyShareEntry->ke = data; + keyShareEntry->keLen = len; + } + else { + /* Generate a key pair. */ + ret = TLSX_KeyShare_GenKey(ssl, keyShareEntry); + if (ret != 0) + return ret; + } + + if (kse != NULL) + *kse = keyShareEntry; + + return 0; +} + +/* Set an empty Key Share extension. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_Empty(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) { + /* Push new KeyShare extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap); + } + else if (extension->data != NULL) { + TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap); + extension->data = NULL; + } + + return ret; +} + +/* Returns whether this group is supported. + * + * namedGroup The named group to check. + * returns 1 when supported or 0 otherwise. + */ +static int TLSX_KeyShare_IsSupported(int namedGroup) +{ + switch (namedGroup) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + break; + #endif + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + break; + #endif /* !NO_ECC_SECP */ + #endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + break; + #endif + #ifdef HAVE_CURVE448 + case WOLFSSL_ECC_X448: + break; + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + break; + #endif /* !NO_ECC_SECP */ + #endif + default: + return 0; + } + + return 1; +} + +/* Examines the application specified group ranking and returns the rank of the + * group. + * If no group ranking set then all groups are rank 0 (highest). + * + * ssl The SSL/TLS object. + * group The group to check ranking for. + * returns ranking from 0 to MAX_GROUP_COUNT-1 or -1 when group not in list. + */ +static int TLSX_KeyShare_GroupRank(WOLFSSL* ssl, int group) +{ + byte i; + + if (ssl->numGroups == 0) { +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP256R1; + #endif + #endif +#endif + #ifndef HAVE_FIPS + #if defined(HAVE_CURVE25519) + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X25519; + #endif + #endif + #ifndef HAVE_FIPS + #if defined(HAVE_CURVE448) + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X448; + #endif + #endif +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP384R1; + #endif + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP521R1; + #endif + #endif +#endif + /* Add FFDHE supported groups. */ + #ifdef HAVE_FFDHE_2048 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_2048; + #endif + #ifdef HAVE_FFDHE_3072 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_3072; + #endif + #ifdef HAVE_FFDHE_4096 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_4096; + #endif + #ifdef HAVE_FFDHE_6144 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_6144; + #endif + #ifdef HAVE_FFDHE_8192 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_8192; + #endif + } + + for (i = 0; i < ssl->numGroups; i++) + if (ssl->group[i] == (word16)group) + return i; + + return -1; +} + +/* Set a key share that is supported by the client into extensions. + * + * ssl The SSL/TLS object. + * returns BAD_KEY_SHARE_DATA if no supported group has a key share, + * 0 if a supported group has a key share and other values indicate an error. + */ +static int TLSX_KeyShare_SetSupported(WOLFSSL* ssl) +{ + int ret; +#ifdef HAVE_SUPPORTED_CURVES + TLSX* extension; + SupportedCurve* curve = NULL; + SupportedCurve* preferredCurve = NULL; + int preferredRank = WOLFSSL_MAX_GROUP_COUNT; + int rank; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension != NULL) + curve = (SupportedCurve*)extension->data; + /* Use server's preference order. */ + for (; curve != NULL; curve = curve->next) { + if (!TLSX_KeyShare_IsSupported(curve->name)) + continue; + + rank = TLSX_KeyShare_GroupRank(ssl, curve->name); + if (rank == -1) + continue; + if (rank < preferredRank) { + preferredCurve = curve; + preferredRank = rank; + } + } + curve = preferredCurve; + + if (curve == NULL) + return BAD_KEY_SHARE_DATA; + + /* Delete the old key share data list. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension != NULL) { + TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap); + extension->data = NULL; + } + + /* Add in the chosen group. */ + ret = TLSX_KeyShare_Use(ssl, curve->name, 0, NULL, NULL); + if (ret != 0) + return ret; + + /* Set extension to be in response. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + extension->resp = 1; +#else + + (void)ssl; + ret = NOT_COMPILED_IN; +#endif + + return ret; +} + +/* Ensure there is a key pair that can be used for key exchange. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_Establish(WOLFSSL *ssl) +{ + int ret; + TLSX* extension; + KeyShareEntry* clientKSE = NULL; + KeyShareEntry* serverKSE; + KeyShareEntry* list = NULL; + KeyShareEntry* preferredKSE = NULL; + int preferredRank = WOLFSSL_MAX_GROUP_COUNT; + int rank; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension != NULL) + list = (KeyShareEntry*)extension->data; + + if (extension && extension->resp == 1) + return 0; + + /* Use server's preference order. */ + for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) { + if (clientKSE->ke == NULL) + continue; + + /* Check consistency now - extensions in any order. */ + if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group)) + return BAD_KEY_SHARE_DATA; + + #ifdef OPENSSL_EXTRA + if ((clientKSE->group & NAMED_DH_MASK) == 0) { + /* Check if server supports group. */ + if (ssl->ctx->disabledCurves & (1 << clientKSE->group)) + continue; + } + #endif + if (!TLSX_KeyShare_IsSupported(clientKSE->group)) + continue; + + rank = TLSX_KeyShare_GroupRank(ssl, clientKSE->group); + if (rank == -1) + continue; + if (rank < preferredRank) { + preferredKSE = clientKSE; + preferredRank = rank; + } + } + clientKSE = preferredKSE; + + /* No supported group found - send HelloRetryRequest. */ + if (clientKSE == NULL) { + ret = TLSX_KeyShare_SetSupported(ssl); + /* Return KEY_SHARE_ERROR to indicate HelloRetryRequest required. */ + if (ret == 0) + return KEY_SHARE_ERROR; + return ret; + } + + list = NULL; + /* Generate a new key pair. */ + ret = TLSX_KeyShare_New(&list, clientKSE->group, ssl->heap, &serverKSE); + if (ret != 0) + return ret; + + if (clientKSE->key == NULL) { + ret = TLSX_KeyShare_GenKey(ssl, serverKSE); + if (ret != 0) + return ret; + } + else { + serverKSE->key = clientKSE->key; + serverKSE->keyLen = clientKSE->keyLen; + serverKSE->pubKey = clientKSE->pubKey; + serverKSE->pubKeyLen = clientKSE->pubKeyLen; + clientKSE->key = NULL; + clientKSE->pubKey = NULL; + } + serverKSE->ke = clientKSE->ke; + serverKSE->keLen = clientKSE->keLen; + clientKSE->ke = NULL; + clientKSE->keLen = 0; + + TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap); + extension->data = (void *)serverKSE; + + extension->resp = 1; + + return 0; +} + +/* Derive the shared secret of the key exchange. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_DeriveSecret(WOLFSSL *ssl) +{ + int ret; + TLSX* extension; + KeyShareEntry* list = NULL; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension != NULL) + list = (KeyShareEntry*)extension->data; + + if (list == NULL) + return KEY_SHARE_ERROR; + + /* Calculate secret. */ + ret = TLSX_KeyShare_Process(ssl, list); + if (ret != 0) + return ret; + + return ret; +} + +#define KS_FREE_ALL TLSX_KeyShare_FreeAll +#define KS_GET_SIZE TLSX_KeyShare_GetSize +#define KS_WRITE TLSX_KeyShare_Write +#define KS_PARSE TLSX_KeyShare_Parse + +#else + +#define KS_FREE_ALL(a, b) +#define KS_GET_SIZE(a, b) 0 +#define KS_WRITE(a, b, c) 0 +#define KS_PARSE(a, b, c, d) 0 + +#endif /* WOLFSSL_TLS13 */ + +/******************************************************************************/ +/* Pre-Shared Key */ +/******************************************************************************/ + +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) +/* Free the pre-shared key dynamic data. + * + * list The linked list of key share entry objects. + * heap The heap used for allocation. + */ +static void TLSX_PreSharedKey_FreeAll(PreSharedKey* list, void* heap) +{ + PreSharedKey* current; + + while ((current = list) != NULL) { + list = current->next; + XFREE(current->identity, heap, DYNAMIC_TYPE_TLSX); + XFREE(current, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +/* Get the size of the encoded pre shared key extension. + * + * list The linked list of pre-shared key extensions. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded pre-shared key extension or + * SANITY_MSG_E to indicate invalid message type. + */ +static int TLSX_PreSharedKey_GetSize(PreSharedKey* list, byte msgType, + word16* pSz) +{ + if (msgType == client_hello) { + /* Length of identities + Length of binders. */ + word16 len = OPAQUE16_LEN + OPAQUE16_LEN; + while (list != NULL) { + /* Each entry has: identity, ticket age and binder. */ + len += OPAQUE16_LEN + list->identityLen + OPAQUE32_LEN + + OPAQUE8_LEN + list->binderLen; + list = list->next; + } + *pSz += len; + return 0; + } + + if (msgType == server_hello) { + *pSz += OPAQUE16_LEN; + return 0; + } + + return SANITY_MSG_E; +} + +/* The number of bytes to be written for the binders. + * + * list The linked list of pre-shared key extensions. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded pre-shared key extension or + * SANITY_MSG_E to indicate invalid message type. + */ +int TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list, byte msgType, + word16* pSz) +{ + word16 len; + + if (msgType != client_hello) + return SANITY_MSG_E; + + /* Length of all binders. */ + len = OPAQUE16_LEN; + while (list != NULL) { + len += OPAQUE8_LEN + list->binderLen; + list = list->next; + } + + *pSz = len; + return 0; +} + +/* Writes the pre-shared key extension into the output buffer - binders only. + * Assumes that the the output buffer is big enough to hold data. + * + * list The linked list of key share entries. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +int TLSX_PreSharedKey_WriteBinders(PreSharedKey* list, byte* output, + byte msgType, word16* pSz) +{ + PreSharedKey* current = list; + word16 idx = 0; + word16 lenIdx; + word16 len; + + if (msgType != client_hello) + return SANITY_MSG_E; + + /* Skip length of all binders. */ + lenIdx = idx; + idx += OPAQUE16_LEN; + while (current != NULL) { + /* Binder data length. */ + output[idx++] = current->binderLen; + /* Binder data. */ + XMEMCPY(output + idx, current->binder, current->binderLen); + idx += current->binderLen; + + current = current->next; + } + /* Length of the binders. */ + len = idx - lenIdx - OPAQUE16_LEN; + c16toa(len, output + lenIdx); + + *pSz = idx; + return 0; +} + + +/* Writes the pre-shared key extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * + * list The linked list of key share entries. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static int TLSX_PreSharedKey_Write(PreSharedKey* list, byte* output, + byte msgType, word16* pSz) +{ + if (msgType == client_hello) { + PreSharedKey* current = list; + word16 idx = 0; + word16 lenIdx; + word16 len; + int ret; + + /* Write identites only. Binders after HMACing over this. */ + lenIdx = idx; + idx += OPAQUE16_LEN; + while (current != NULL) { + /* Identity length */ + c16toa(current->identityLen, output + idx); + idx += OPAQUE16_LEN; + /* Identity data */ + XMEMCPY(output + idx, current->identity, current->identityLen); + idx += current->identityLen; + + /* Obfuscated ticket age. */ + c32toa(current->ticketAge, output + idx); + idx += OPAQUE32_LEN; + + current = current->next; + } + /* Length of the identites. */ + len = idx - lenIdx - OPAQUE16_LEN; + c16toa(len, output + lenIdx); + + /* Don't include binders here. + * The binders are based on the hash of all the ClientHello data up to + * and include the identities written above. + */ + ret = TLSX_PreSharedKey_GetSizeBinders(list, msgType, &len); + if (ret < 0) + return ret; + *pSz += idx + len; + } + else if (msgType == server_hello) { + word16 i; + + /* Find the index of the chosen identity. */ + for (i=0; list != NULL && !list->chosen; i++) + list = list->next; + if (list == NULL) + return BUILD_MSG_ERROR; + + /* The index of the identity chosen by the server from the list supplied + * by the client. + */ + c16toa(i, output); + *pSz += OPAQUE16_LEN; + } + else + return SANITY_MSG_E; + + return 0; +} + +/* Parse the pre-shared key extension. + * Different formats in different messages. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + TLSX* extension; + PreSharedKey* list; + + if (msgType == client_hello) { + int ret; + word16 len; + word16 idx = 0; + + TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap); + + /* Length of identities and of binders. */ + if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_E; + + /* Length of identities. */ + ato16(input + idx, &len); + idx += OPAQUE16_LEN; + if (len < MIN_PSK_ID_LEN || length - idx < len) + return BUFFER_E; + + /* Create a pre-shared key object for each identity. */ + while (len > 0) { + byte* identity; + word16 identityLen; + word32 age; + + if (len < OPAQUE16_LEN) + return BUFFER_E; + + /* Length of identity. */ + ato16(input + idx, &identityLen); + idx += OPAQUE16_LEN; + if (len < OPAQUE16_LEN + identityLen + OPAQUE32_LEN || + identityLen > MAX_PSK_ID_LEN) + return BUFFER_E; + /* Cache identity pointer. */ + identity = input + idx; + idx += identityLen; + /* Ticket age. */ + ato32(input + idx, &age); + idx += OPAQUE32_LEN; + + ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, no_mac, + 0, 0, 1, NULL); + if (ret != 0) + return ret; + + /* Done with this identity. */ + len -= OPAQUE16_LEN + identityLen + OPAQUE32_LEN; + } + + /* Find the list of identities sent to server. */ + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) + return PSK_KEY_ERROR; + list = (PreSharedKey*)extension->data; + + /* Length of binders. */ + if (idx + OPAQUE16_LEN > length) + return BUFFER_E; + ato16(input + idx, &len); + idx += OPAQUE16_LEN; + if (len < MIN_PSK_BINDERS_LEN || length - idx < len) + return BUFFER_E; + + /* Set binder for each identity. */ + while (list != NULL && len > 0) { + /* Length of binder */ + list->binderLen = input[idx++]; + if (list->binderLen < WC_SHA256_DIGEST_SIZE || + list->binderLen > WC_MAX_DIGEST_SIZE) + return BUFFER_E; + if (len < OPAQUE8_LEN + list->binderLen) + return BUFFER_E; + + /* Copy binder into static buffer. */ + XMEMCPY(list->binder, input + idx, list->binderLen); + idx += list->binderLen; + + /* Done with binder entry. */ + len -= OPAQUE8_LEN + list->binderLen; + + /* Next identity. */ + list = list->next; + } + if (list != NULL || len != 0) + return BUFFER_E; + + return 0; + } + + if (msgType == server_hello) { + word16 idx; + + /* Index of identity chosen by server. */ + if (length != OPAQUE16_LEN) + return BUFFER_E; + ato16(input, &idx); + + #ifdef WOLFSSL_EARLY_DATA + ssl->options.pskIdIndex = idx + 1; + #endif + + /* Find the list of identities sent to server. */ + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) + return PSK_KEY_ERROR; + list = (PreSharedKey*)extension->data; + + /* Mark the identity as chosen. */ + for (; list != NULL && idx > 0; idx--) + list = list->next; + if (list == NULL) + return PSK_KEY_ERROR; + list->chosen = 1; + + #ifdef HAVE_SESSION_TICKET + if (list->resumption) { + /* Check that the session's details are the same as the server's. */ + if (ssl->options.cipherSuite0 != ssl->session.cipherSuite0 || + ssl->options.cipherSuite != ssl->session.cipherSuite || + ssl->session.version.major != ssl->ctx->method->version.major || + ssl->session.version.minor != ssl->ctx->method->version.minor) { + return PSK_KEY_ERROR; + } + } + #endif + + return 0; + } + + return SANITY_MSG_E; +} + +/* Create a new pre-shared key and put it into the list. + * + * list The linked list of pre-shared key. + * identity The identity. + * len The length of the identity data. + * heap The memory to allocate with. + * preSharedKey The new pre-shared key object. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PreSharedKey_New(PreSharedKey** list, byte* identity, + word16 len, void *heap, + PreSharedKey** preSharedKey) +{ + PreSharedKey* psk; + PreSharedKey** next; + + psk = (PreSharedKey*)XMALLOC(sizeof(PreSharedKey), heap, DYNAMIC_TYPE_TLSX); + if (psk == NULL) + return MEMORY_E; + XMEMSET(psk, 0, sizeof(*psk)); + + /* Make a copy of the identity data. */ + psk->identity = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TLSX); + if (psk->identity == NULL) { + XFREE(psk, heap, DYNAMIC_TYPE_TLSX); + return MEMORY_E; + } + XMEMCPY(psk->identity, identity, len); + psk->identityLen = len; + + /* Add it to the end and maintain the links. */ + while (*list != NULL) { + /* Assign to temporary to work around compiler bug found by customer. */ + next = &((*list)->next); + list = next; + } + *list = psk; + *preSharedKey = psk; + + (void)heap; + + return 0; +} + +static WC_INLINE byte GetHmacLength(int hmac) +{ + switch (hmac) { + #ifndef NO_SHA256 + case sha256_mac: + return WC_SHA256_DIGEST_SIZE; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + return WC_SHA384_DIGEST_SIZE; + #endif + #ifdef WOLFSSL_SHA512 + case sha512_mac: + return WC_SHA512_DIGEST_SIZE; + #endif + } + return 0; +} + +/* Use the data to create a new pre-shared key object in the extensions. + * + * ssl The SSL/TLS object. + * identity The identity. + * len The length of the identity data. + * age The age of the identity. + * hmac The HMAC algorithm. + * ciphersuite0 The first byte of the ciphersuite to use. + * ciphersuite The second byte of the ciphersuite to use. + * resumption The PSK is for resumption of a session. + * preSharedKey The new pre-shared key object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, + byte hmac, byte cipherSuite0, + byte cipherSuite, byte resumption, + PreSharedKey **preSharedKey) +{ + int ret = 0; + TLSX* extension; + PreSharedKey* psk = NULL; + + /* Find the pre-shared key extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) { + /* Push new pre-shared key extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_PRE_SHARED_KEY, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) + return MEMORY_E; + } + + /* Try to find the pre-shared key with this identity. */ + psk = (PreSharedKey*)extension->data; + while (psk != NULL) { + if ((psk->identityLen == len) && + (XMEMCMP(psk->identity, identity, len) == 0)) { + break; + } + psk = psk->next; + } + + /* Create a new pre-shared key object if not found. */ + if (psk == NULL) { + ret = TLSX_PreSharedKey_New((PreSharedKey**)&extension->data, identity, + len, ssl->heap, &psk); + if (ret != 0) + return ret; + } + + /* Update/set age and HMAC algorithm. */ + psk->ticketAge = age; + psk->hmac = hmac; + psk->cipherSuite0 = cipherSuite0; + psk->cipherSuite = cipherSuite; + psk->resumption = resumption; + psk->binderLen = GetHmacLength(psk->hmac); + + if (preSharedKey != NULL) + *preSharedKey = psk; + + return 0; +} + +#define PSK_FREE_ALL TLSX_PreSharedKey_FreeAll +#define PSK_GET_SIZE TLSX_PreSharedKey_GetSize +#define PSK_WRITE TLSX_PreSharedKey_Write +#define PSK_PARSE TLSX_PreSharedKey_Parse + +#else + +#define PSK_FREE_ALL(a, b) +#define PSK_GET_SIZE(a, b, c) 0 +#define PSK_WRITE(a, b, c, d) 0 +#define PSK_PARSE(a, b, c, d) 0 + +#endif + +/******************************************************************************/ +/* PSK Key Exchange Modes */ +/******************************************************************************/ + +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) +/* Get the size of the encoded PSK KE modes extension. + * Only in ClientHello. + * + * modes The PSK KE mode bit string. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded PSK KE mode extension. + */ +static int TLSX_PskKeModes_GetSize(byte modes, byte msgType, word16* pSz) +{ + if (msgType == client_hello) { + /* Format: Len | Modes* */ + word16 len = OPAQUE8_LEN; + /* Check whether each possible mode is to be written. */ + if (modes & (1 << PSK_KE)) + len += OPAQUE8_LEN; + if (modes & (1 << PSK_DHE_KE)) + len += OPAQUE8_LEN; + *pSz += len; + return 0; + } + + return SANITY_MSG_E; +} + +/* Writes the PSK KE modes extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * Only in ClientHello. + * + * modes The PSK KE mode bit string. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static int TLSX_PskKeModes_Write(byte modes, byte* output, byte msgType, + word16* pSz) +{ + if (msgType == client_hello) { + /* Format: Len | Modes* */ + int idx = OPAQUE8_LEN; + + /* Write out each possible mode. */ + if (modes & (1 << PSK_KE)) + output[idx++] = PSK_KE; + if (modes & (1 << PSK_DHE_KE)) + output[idx++] = PSK_DHE_KE; + /* Write out length of mode list. */ + output[0] = idx - OPAQUE8_LEN; + + *pSz += idx; + return 0; + } + + return SANITY_MSG_E; +} + +/* Parse the PSK KE modes extension. + * Only in ClientHello. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PskKeModes_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + int ret; + + if (msgType == client_hello) { + /* Format: Len | Modes* */ + int idx = 0; + word16 len; + byte modes = 0; + + /* Ensure length byte exists. */ + if (length < OPAQUE8_LEN) + return BUFFER_E; + + /* Get length of mode list and ensure that is the only data. */ + len = input[0]; + if (length - OPAQUE8_LEN != len) + return BUFFER_E; + + idx = OPAQUE8_LEN; + /* Set a bit for each recognized modes. */ + while (len > 0) { + /* Ignore unrecognized modes. */ + if (input[idx] <= PSK_DHE_KE) + modes |= 1 << input[idx]; + idx++; + len--; + } + + ret = TLSX_PskKeModes_Use(ssl, modes); + if (ret != 0) + return ret; + + return 0; + } + + return SANITY_MSG_E; +} + +/* Use the data to create a new PSK Key Exchange Modes object in the extensions. + * + * ssl The SSL/TLS object. + * modes The PSK key exchange modes. + * returns 0 on success and other values indicate failure. + */ +int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes) +{ + int ret = 0; + TLSX* extension; + + /* Find the PSK key exchange modes extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (extension == NULL) { + /* Push new PSK key exchange modes extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES, NULL, + ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (extension == NULL) + return MEMORY_E; + } + + extension->val = modes; + + return 0; +} + +#define PKM_GET_SIZE TLSX_PskKeModes_GetSize +#define PKM_WRITE TLSX_PskKeModes_Write +#define PKM_PARSE TLSX_PskKeModes_Parse + +#else + +#define PKM_GET_SIZE(a, b, c) 0 +#define PKM_WRITE(a, b, c, d) 0 +#define PKM_PARSE(a, b, c, d) 0 + +#endif + +/******************************************************************************/ +/* Post-Handshake Authentication */ +/******************************************************************************/ + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* Get the size of the encoded Post-Handshake Authentication extension. + * Only in ClientHello. + * + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded Post-Handshake Authentication + * extension. + */ +static int TLSX_PostHandAuth_GetSize(byte msgType, word16* pSz) +{ + if (msgType == client_hello) { + *pSz += 0; + return 0; + } + + return SANITY_MSG_E; +} + +/* Writes the Post-Handshake Authentication extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * Only in ClientHello. + * + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static int TLSX_PostHandAuth_Write(byte* output, byte msgType, word16* pSz) +{ + (void)output; + + if (msgType == client_hello) { + *pSz += 0; + return 0; + } + + return SANITY_MSG_E; +} + +/* Parse the Post-Handshake Authentication extension. + * Only in ClientHello. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PostHandAuth_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + (void)input; + + if (msgType == client_hello) { + /* Ensure extension is empty. */ + if (length != 0) + return BUFFER_E; + + ssl->options.postHandshakeAuth = 1; + return 0; + } + + return SANITY_MSG_E; +} + +/* Create a new Post-handshake authentication object in the extensions. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PostHandAuth_Use(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + + /* Find the PSK key exchange modes extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_POST_HANDSHAKE_AUTH); + if (extension == NULL) { + /* Push new Post-handshake Authentication extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_POST_HANDSHAKE_AUTH, NULL, + ssl->heap); + if (ret != 0) + return ret; + } + + return 0; +} + +#define PHA_GET_SIZE TLSX_PostHandAuth_GetSize +#define PHA_WRITE TLSX_PostHandAuth_Write +#define PHA_PARSE TLSX_PostHandAuth_Parse + +#else + +#define PHA_GET_SIZE(a, b) 0 +#define PHA_WRITE(a, b, c) 0 +#define PHA_PARSE(a, b, c, d) 0 + +#endif + +/******************************************************************************/ +/* Early Data Indication */ +/******************************************************************************/ + +#ifdef WOLFSSL_EARLY_DATA +/* Get the size of the encoded Early Data Indication extension. + * In messages: ClientHello, EncryptedExtensions and NewSessionTicket. + * + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded Early Data Indication extension. + */ +static int TLSX_EarlyData_GetSize(byte msgType, word16* pSz) +{ + int ret = 0; + + if (msgType == client_hello || msgType == encrypted_extensions) + *pSz += 0; + else if (msgType == session_ticket) + *pSz += OPAQUE32_LEN; + else + ret = SANITY_MSG_E; + + return ret; +} + +/* Writes the Early Data Indicator extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * In messages: ClientHello, EncryptedExtensions and NewSessionTicket. + * + * max The maximum early data size. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static int TLSX_EarlyData_Write(word32 max, byte* output, byte msgType, + word16* pSz) +{ + if (msgType == client_hello || msgType == encrypted_extensions) + return 0; + else if (msgType == session_ticket) { + c32toa(max, output); + *pSz += OPAQUE32_LEN; + return 0; + } + + return SANITY_MSG_E; +} + +/* Parse the Early Data Indicator extension. + * In messages: ClientHello, EncryptedExtensions and NewSessionTicket. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_EarlyData_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + if (msgType == client_hello) { + if (length != 0) + return BUFFER_E; + + if (ssl->earlyData == expecting_early_data) + return TLSX_EarlyData_Use(ssl, 0); + ssl->earlyData = early_data_ext; + return 0; + } + if (msgType == encrypted_extensions) { + if (length != 0) + return BUFFER_E; + + /* Ensure the index of PSK identity chosen by server is 0. + * Index is plus one to handle 'not set' value of 0. + */ + if (ssl->options.pskIdIndex != 1) + return PSK_KEY_ERROR; + + return TLSX_EarlyData_Use(ssl, 1); + } + if (msgType == session_ticket) { + word32 maxSz; + + if (length != OPAQUE32_LEN) + return BUFFER_E; + ato32(input, &maxSz); + + ssl->session.maxEarlyDataSz = maxSz; + return 0; + } + + return SANITY_MSG_E; +} + +/* Use the data to create a new Early Data object in the extensions. + * + * ssl The SSL/TLS object. + * max The maximum early data size. + * returns 0 on success and other values indicate failure. + */ +int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max) +{ + int ret = 0; + TLSX* extension; + + /* Find the early data extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extension == NULL) { + /* Push new early data extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extension == NULL) + return MEMORY_E; + } + + extension->resp = 1; + extension->val = max; + + return 0; +} + +#define EDI_GET_SIZE TLSX_EarlyData_GetSize +#define EDI_WRITE TLSX_EarlyData_Write +#define EDI_PARSE TLSX_EarlyData_Parse + +#else + +#define EDI_GET_SIZE(a, b) 0 +#define EDI_WRITE(a, b, c, d) 0 +#define EDI_PARSE(a, b, c, d) 0 + +#endif + +/******************************************************************************/ +/* TLS Extensions Framework */ +/******************************************************************************/ + +/** Finds an extension in the provided list. */ +TLSX* TLSX_Find(TLSX* list, TLSX_Type type) +{ + TLSX* extension = list; + + while (extension && extension->type != type) + extension = extension->next; + + return extension; +} + +/** Remove an extension. */ +void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap) +{ + TLSX* extension = *list; + TLSX** next = list; + + while (extension && extension->type != type) { + next = &extension->next; + extension = extension->next; + } + + if (extension) { + *next = extension->next; + extension->next = NULL; + TLSX_FreeAll(extension, heap); + } +} + +/** Releases all extensions in the provided list. */ +void TLSX_FreeAll(TLSX* list, void* heap) +{ + TLSX* extension; + + while ((extension = list)) { + list = extension->next; + + switch (extension->type) { + + case TLSX_SERVER_NAME: + SNI_FREE_ALL((SNI*)extension->data, heap); + break; + + case TLSX_TRUSTED_CA_KEYS: + TCA_FREE_ALL((TCA*)extension->data, heap); + break; + + case TLSX_MAX_FRAGMENT_LENGTH: + MFL_FREE_ALL(extension->data, heap); + break; + + case TLSX_TRUNCATED_HMAC: + /* Nothing to do. */ + break; + + case TLSX_SUPPORTED_GROUPS: + EC_FREE_ALL((SupportedCurve*)extension->data, heap); + break; + + case TLSX_EC_POINT_FORMATS: + PF_FREE_ALL((PointFormat*)extension->data, heap); + break; + + case TLSX_STATUS_REQUEST: + CSR_FREE_ALL((CertificateStatusRequest*)extension->data, heap); + break; + + case TLSX_STATUS_REQUEST_V2: + CSR2_FREE_ALL((CertificateStatusRequestItemV2*)extension->data, + heap); + break; + + case TLSX_RENEGOTIATION_INFO: + SCR_FREE_ALL(extension->data, heap); + break; + + case TLSX_SESSION_TICKET: + WOLF_STK_FREE(extension->data, heap); + break; + + case TLSX_QUANTUM_SAFE_HYBRID: + QSH_FREE_ALL((QSHScheme*)extension->data, heap); + break; + + case TLSX_APPLICATION_LAYER_PROTOCOL: + ALPN_FREE_ALL((ALPN*)extension->data, heap); + break; +#if !defined(WOLFSSL_NO_SIGALG) + case TLSX_SIGNATURE_ALGORITHMS: + break; +#endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + break; +#endif +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + break; + + case TLSX_COOKIE: + CKE_FREE_ALL((Cookie*)extension->data, heap); + break; + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + case TLSX_PRE_SHARED_KEY: + PSK_FREE_ALL((PreSharedKey*)extension->data, heap); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + break; + #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + break; + #endif + + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + break; + #endif + + #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) + case TLSX_SIGNATURE_ALGORITHMS_CERT: + break; + #endif + + case TLSX_KEY_SHARE: + KS_FREE_ALL((KeyShareEntry*)extension->data, heap); + break; +#endif + } + + XFREE(extension, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +/** Checks if the tls extensions are supported based on the protocol version. */ +int TLSX_SupportExtensions(WOLFSSL* ssl) { + return ssl && (IsTLS(ssl) || ssl->version.major == DTLS_MAJOR); +} + +/** Tells the buffered size of the extensions in a list. */ +static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, + word16* pLength) +{ + int ret = 0; + TLSX* extension; + word16 length = 0; + byte isRequest = (msgType == client_hello || + msgType == certificate_request); + + while ((extension = list)) { + list = extension->next; + + /* only extensions marked as response are sent back to the client. */ + if (!isRequest && !extension->resp) + continue; /* skip! */ + + /* ssl level extensions are expected to override ctx level ones. */ + if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type))) + continue; /* skip! */ + + /* extension type + extension data length. */ + length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; + + + switch (extension->type) { + + case TLSX_SERVER_NAME: + /* SNI only sends the name on the request. */ + if (isRequest) + length += SNI_GET_SIZE((SNI*)extension->data); + break; + + case TLSX_TRUSTED_CA_KEYS: + /* TCA only sends the list on the request. */ + if (isRequest) + length += TCA_GET_SIZE((TCA*)extension->data); + break; + + case TLSX_MAX_FRAGMENT_LENGTH: + length += MFL_GET_SIZE(extension->data); + break; + + case TLSX_TRUNCATED_HMAC: + /* always empty. */ + break; + + case TLSX_SUPPORTED_GROUPS: + length += EC_GET_SIZE((SupportedCurve*)extension->data); + break; + + case TLSX_EC_POINT_FORMATS: + length += PF_GET_SIZE((PointFormat*)extension->data); + break; + + case TLSX_STATUS_REQUEST: + length += CSR_GET_SIZE( + (CertificateStatusRequest*)extension->data, isRequest); + break; + + case TLSX_STATUS_REQUEST_V2: + length += CSR2_GET_SIZE( + (CertificateStatusRequestItemV2*)extension->data, + isRequest); + break; + + case TLSX_RENEGOTIATION_INFO: + length += SCR_GET_SIZE((SecureRenegotiation*)extension->data, + isRequest); + break; + + case TLSX_SESSION_TICKET: + length += WOLF_STK_GET_SIZE((SessionTicket*)extension->data, + isRequest); + break; + + case TLSX_QUANTUM_SAFE_HYBRID: + length += QSH_GET_SIZE((QSHScheme*)extension->data, isRequest); + break; + + case TLSX_APPLICATION_LAYER_PROTOCOL: + length += ALPN_GET_SIZE((ALPN*)extension->data); + break; +#if !defined(WOLFSSL_NO_SIGALG) + case TLSX_SIGNATURE_ALGORITHMS: + length += SA_GET_SIZE(extension->data); + break; +#endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + ret = ETM_GET_SIZE(msgType, &length); + break; +#endif /* HAVE_ENCRYPT_THEN_MAC */ +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + ret = SV_GET_SIZE(extension->data, msgType, &length); + break; + + case TLSX_COOKIE: + ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length); + break; + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + case TLSX_PRE_SHARED_KEY: + ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType, + &length); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + ret = PKM_GET_SIZE(extension->val, msgType, &length); + break; + #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + ret = EDI_GET_SIZE(msgType, &length); + break; + #endif + + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + ret = PHA_GET_SIZE(msgType, &length); + break; + #endif + + #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) + case TLSX_SIGNATURE_ALGORITHMS_CERT: + length += SAC_GET_SIZE(extension->data); + break; + #endif + + case TLSX_KEY_SHARE: + length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType); + break; +#endif + } + + /* marks the extension as processed so ctx level */ + /* extensions don't overlap with ssl level ones. */ + TURN_ON(semaphore, TLSX_ToSemaphore(extension->type)); + } + + *pLength += length; + + return ret; +} + +/** Writes the extensions of a list in a buffer. */ +static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, + byte msgType, word16* pOffset) +{ + int ret = 0; + TLSX* extension; + word16 offset = 0; + word16 length_offset = 0; + byte isRequest = (msgType == client_hello || + msgType == certificate_request); + + while ((extension = list)) { + list = extension->next; + + /* only extensions marked as response are written in a response. */ + if (!isRequest && !extension->resp) + continue; /* skip! */ + + /* ssl level extensions are expected to override ctx level ones. */ + if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type))) + continue; /* skip! */ + + /* writes extension type. */ + c16toa(extension->type, output + offset); + offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; + length_offset = offset; + + /* extension data should be written internally. */ + switch (extension->type) { + case TLSX_SERVER_NAME: + if (isRequest) { + WOLFSSL_MSG("SNI extension to write"); + offset += SNI_WRITE((SNI*)extension->data, output + offset); + } + break; + + case TLSX_TRUSTED_CA_KEYS: + WOLFSSL_MSG("Trusted CA Indication extension to write"); + if (isRequest) { + offset += TCA_WRITE((TCA*)extension->data, output + offset); + } + break; + + case TLSX_MAX_FRAGMENT_LENGTH: + WOLFSSL_MSG("Max Fragment Length extension to write"); + offset += MFL_WRITE((byte*)extension->data, output + offset); + break; + + case TLSX_TRUNCATED_HMAC: + WOLFSSL_MSG("Truncated HMAC extension to write"); + /* always empty. */ + break; + + case TLSX_SUPPORTED_GROUPS: + WOLFSSL_MSG("Supported Groups extension to write"); + offset += EC_WRITE((SupportedCurve*)extension->data, + output + offset); + break; + + case TLSX_EC_POINT_FORMATS: + WOLFSSL_MSG("Point Formats extension to write"); + offset += PF_WRITE((PointFormat*)extension->data, + output + offset); + break; + + case TLSX_STATUS_REQUEST: + WOLFSSL_MSG("Certificate Status Request extension to write"); + offset += CSR_WRITE((CertificateStatusRequest*)extension->data, + output + offset, isRequest); + break; + + case TLSX_STATUS_REQUEST_V2: + WOLFSSL_MSG("Certificate Status Request v2 extension to write"); + offset += CSR2_WRITE( + (CertificateStatusRequestItemV2*)extension->data, + output + offset, isRequest); + break; + + case TLSX_RENEGOTIATION_INFO: + WOLFSSL_MSG("Secure Renegotiation extension to write"); + offset += SCR_WRITE((SecureRenegotiation*)extension->data, + output + offset, isRequest); + break; + + case TLSX_SESSION_TICKET: + WOLFSSL_MSG("Session Ticket extension to write"); + offset += WOLF_STK_WRITE((SessionTicket*)extension->data, + output + offset, isRequest); + break; + + case TLSX_QUANTUM_SAFE_HYBRID: + WOLFSSL_MSG("Quantum-Safe-Hybrid extension to write"); + if (isRequest) { + offset += QSH_WRITE((QSHScheme*)extension->data, output + offset); + } + offset += QSHPK_WRITE((QSHScheme*)extension->data, output + offset); + offset += QSH_SERREQ(output + offset, isRequest); + break; + + case TLSX_APPLICATION_LAYER_PROTOCOL: + WOLFSSL_MSG("ALPN extension to write"); + offset += ALPN_WRITE((ALPN*)extension->data, output + offset); + break; +#if !defined(WOLFSSL_NO_SIGALG) + case TLSX_SIGNATURE_ALGORITHMS: + WOLFSSL_MSG("Signature Algorithms extension to write"); + offset += SA_WRITE(extension->data, output + offset); + break; +#endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + WOLFSSL_MSG("Encrypt-Then-Mac extension to write"); + ret = ETM_WRITE(extension->data, output, msgType, &offset); + break; +#endif /* HAVE_ENCRYPT_THEN_MAC */ +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + WOLFSSL_MSG("Supported Versions extension to write"); + ret = SV_WRITE(extension->data, output + offset, msgType, &offset); + break; + + case TLSX_COOKIE: + WOLFSSL_MSG("Cookie extension to write"); + ret = CKE_WRITE((Cookie*)extension->data, output + offset, + msgType, &offset); + break; + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + case TLSX_PRE_SHARED_KEY: + WOLFSSL_MSG("Pre-Shared Key extension to write"); + ret = PSK_WRITE((PreSharedKey*)extension->data, output + offset, + msgType, &offset); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + WOLFSSL_MSG("PSK Key Exchange Modes extension to write"); + ret = PKM_WRITE(extension->val, output + offset, msgType, + &offset); + break; + #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + WOLFSSL_MSG("Early Data extension to write"); + ret = EDI_WRITE(extension->val, output + offset, msgType, + &offset); + break; + #endif + + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + WOLFSSL_MSG("Post-Handshake Authentication extension to write"); + ret = PHA_WRITE(output + offset, msgType, &offset); + break; + #endif + + #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) + case TLSX_SIGNATURE_ALGORITHMS_CERT: + WOLFSSL_MSG("Signature Algorithms extension to write"); + offset += SAC_WRITE(extension->data, output + offset); + break; + #endif + + case TLSX_KEY_SHARE: + WOLFSSL_MSG("Key Share extension to write"); + offset += KS_WRITE((KeyShareEntry*)extension->data, + output + offset, msgType); + break; +#endif + } + + /* writes extension data length. */ + c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN); + + /* marks the extension as processed so ctx level */ + /* extensions don't overlap with ssl level ones. */ + TURN_ON(semaphore, TLSX_ToSemaphore(extension->type)); + } + + *pOffset += offset; + + return ret; +} + + +#if defined(HAVE_NTRU) && defined(HAVE_QSH) + +static word32 GetEntropy(unsigned char* out, word32 num_bytes) +{ + int ret = 0; + + if (gRng == NULL) { + if ((gRng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, + DYNAMIC_TYPE_TLSX)) == NULL) + return DRBG_OUT_OF_MEMORY; + wc_InitRng(gRng); + } + + if (gRngMutex == NULL) { + if ((gRngMutex = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL, + DYNAMIC_TYPE_TLSX)) == NULL) + return DRBG_OUT_OF_MEMORY; + wc_InitMutex(gRngMutex); + } + + ret |= wc_LockMutex(gRngMutex); + ret |= wc_RNG_GenerateBlock(gRng, out, num_bytes); + ret |= wc_UnLockMutex(gRngMutex); + + if (ret != 0) + return DRBG_ENTROPY_FAIL; + + return DRBG_OK; +} +#endif + + +#ifdef HAVE_QSH +static int TLSX_CreateQSHKey(WOLFSSL* ssl, int type) +{ + int ret = -1; + + (void)ssl; + + switch (type) { +#ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + ret = TLSX_CreateNtruKey(ssl, type); + break; +#endif + default: + WOLFSSL_MSG("Unknown type for creating NTRU key"); + break; + } + + return ret; +} + + +static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key) +{ + QSHKey* current; + + if (key == NULL) + return BAD_FUNC_ARG; + + /* if no public key stored in key then do not add */ + if (key->pub.length == 0 || key->pub.buffer == NULL) + return 0; + + /* first element to be added to the list */ + current = *list; + if (current == NULL) { + *list = key; + return 0; + } + + while (current->next) { + /* can only have one of the key in the list */ + if (current->name == key->name) + return -1; + current = (QSHKey*)current->next; + } + + current->next = (struct QSHKey*)key; + + return 0; +} + + +#if defined(HAVE_NTRU) +int TLSX_CreateNtruKey(WOLFSSL* ssl, int type) +{ + int ret = -1; + int ntruType; + + /* variable declarations for NTRU*/ + QSHKey* temp = NULL; + byte public_key[1027]; + word16 public_key_len = sizeof(public_key); + byte private_key[1120]; + word16 private_key_len = sizeof(private_key); + DRBG_HANDLE drbg; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (type) { + case WOLFSSL_NTRU_EESS439: + ntruType = NTRU_EES439EP1; + break; + case WOLFSSL_NTRU_EESS593: + ntruType = NTRU_EES593EP1; + break; + case WOLFSSL_NTRU_EESS743: + ntruType = NTRU_EES743EP1; + break; + default: + WOLFSSL_MSG("Unknown type for creating NTRU key"); + return -1; + } + ret = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) { + WOLFSSL_MSG("NTRU drbg instantiate failed\n"); + return ret; + } + + if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType, + &public_key_len, NULL, &private_key_len, NULL)) != NTRU_OK) + return ret; + + if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType, + &public_key_len, public_key, &private_key_len, private_key)) != NTRU_OK) + return ret; + + ret = ntru_crypto_drbg_uninstantiate(drbg); + if (ret != NTRU_OK) { + WOLFSSL_MSG("NTRU drbg uninstantiate failed\n"); + return ret; + } + + if ((temp = (QSHKey*)XMALLOC(sizeof(QSHKey), ssl->heap, + DYNAMIC_TYPE_TLSX)) == NULL) + return MEMORY_E; + temp->name = type; + temp->pub.length = public_key_len; + temp->pub.buffer = (byte*)XMALLOC(public_key_len, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + XMEMCPY(temp->pub.buffer, public_key, public_key_len); + temp->pri.length = private_key_len; + temp->pri.buffer = (byte*)XMALLOC(private_key_len, ssl->heap, + DYNAMIC_TYPE_ARRAYS); + XMEMCPY(temp->pri.buffer, private_key, private_key_len); + temp->next = NULL; + + TLSX_AddQSHKey(&ssl->QSH_Key, temp); + + (void)ssl; + (void)type; + + return ret; +} +#endif + + +/* + Used to find a public key from the list of keys + pubLen length of array + name input the name of the scheme looking for ie WOLFSSL_NTRU_ESSXXX + + returns a pointer to public key byte* or NULL if not found + */ +static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name) +{ + QSHKey* current = qsh; + + if (qsh == NULL || pubLen == NULL) + return NULL; + + *pubLen = 0; + + while(current) { + if (current->name == name) { + *pubLen = current->pub.length; + return current->pub.buffer; + } + current = (QSHKey*)current->next; + } + + return NULL; +} +#endif /* HAVE_QSH */ + +#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \ + (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \ + && !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \ + ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES)) + +/* Populates the default supported groups / curves */ +static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) +{ + int ret = WOLFSSL_SUCCESS; +#ifdef WOLFSSL_TLS13 + int i; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.resuming && ssl->session.namedGroup != 0) { + return TLSX_UseSupportedCurve(extensions, ssl->session.namedGroup, + ssl->heap); + } +#endif + + if (ssl->numGroups != 0) { + for (i = 0; i < ssl->numGroups; i++) { + ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + return WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_TLS13 */ + +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + /* list in order by strength, since not all servers choose by strength */ + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP521R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_BRAINPOOL + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP384R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_BRAINPOOL + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif +#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ + + #ifndef HAVE_FIPS + #if defined(HAVE_CURVE448) + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_X448, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif /* HAVE_FIPS */ + +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP256R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP256K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_BRAINPOOL + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif +#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ + + #ifndef HAVE_FIPS + #if defined(HAVE_CURVE25519) + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_X25519, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif /* HAVE_FIPS */ + +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP224R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP224K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + + #ifndef HAVE_FIPS + #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP192R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP192K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP160R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_SECPR2 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP160R2, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP160K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #endif /* HAVE_FIPS */ +#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ + + /* Add FFDHE supported groups. */ + #ifdef HAVE_FFDHE_8192 + if (8192/8 >= ssl->options.minDhKeySz && + 8192/8 <= ssl->options.maxDhKeySz) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_8192, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + #endif + #ifdef HAVE_FFDHE_6144 + if (6144/8 >= ssl->options.minDhKeySz && + 6144/8 <= ssl->options.maxDhKeySz) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_6144, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + #endif + #ifdef HAVE_FFDHE_4096 + if (4096/8 >= ssl->options.minDhKeySz && + 4096/8 <= ssl->options.maxDhKeySz) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_4096, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + #endif + #ifdef HAVE_FFDHE_3072 + if (3072/8 >= ssl->options.minDhKeySz && + 3072/8 <= ssl->options.maxDhKeySz) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_3072, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + #endif + #ifdef HAVE_FFDHE_2048 + if (2048/8 >= ssl->options.minDhKeySz && + 2048/8 <= ssl->options.maxDhKeySz) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_2048, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + #endif + + (void)ssl; + (void)extensions; + + return ret; +} + +#endif + +int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) +{ + int ret = 0; + byte* public_key = NULL; + word16 public_key_len = 0; +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) + int usingPSK = 0; +#endif +#ifdef HAVE_QSH + TLSX* extension; + QSHScheme* qsh; + QSHScheme* next; + + /* add supported QSHSchemes */ + WOLFSSL_MSG("Adding supported QSH Schemes"); +#endif + + /* server will add extension depending on what is parsed from client */ + if (!isServer) { +#ifdef HAVE_QSH + /* test if user has set a specific scheme already */ + if (!ssl->user_set_QSHSchemes) { + if (ssl->sendQSHKeys && ssl->QSH_Key == NULL) { + if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS743)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return ret; + } + if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS593)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return ret; + } + if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS439)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return ret; + } + + /* add NTRU 256 */ + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, WOLFSSL_NTRU_EESS743); + } + if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS743, + public_key, public_key_len, ssl->heap) + != WOLFSSL_SUCCESS) + ret = -1; + + /* add NTRU 196 */ + if (ssl->sendQSHKeys) { + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, WOLFSSL_NTRU_EESS593); + } + if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS593, + public_key, public_key_len, ssl->heap) + != WOLFSSL_SUCCESS) + ret = -1; + + /* add NTRU 128 */ + if (ssl->sendQSHKeys) { + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, WOLFSSL_NTRU_EESS439); + } + if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS439, + public_key, public_key_len, ssl->heap) + != WOLFSSL_SUCCESS) + ret = -1; + } + else if (ssl->sendQSHKeys && ssl->QSH_Key == NULL) { + /* for each scheme make a client key */ + extension = TLSX_Find(ssl->extensions, TLSX_QUANTUM_SAFE_HYBRID); + if (extension) { + qsh = (QSHScheme*)extension->data; + + while (qsh) { + if ((ret = TLSX_CreateQSHKey(ssl, qsh->name)) != 0) + return ret; + + /* get next now because qsh could be freed */ + next = qsh->next; + + /* find the public key created and add to extension*/ + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, qsh->name); + if (TLSX_UseQSHScheme(&ssl->extensions, qsh->name, + public_key, public_key_len, + ssl->heap) != WOLFSSL_SUCCESS) + ret = -1; + qsh = next; + } + } + } +#endif + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (!ssl->options.disallowEncThenMac) { + ret = TLSX_EncryptThenMac_Use(ssl); + if (ret != 0) + return ret; + } +#endif + +#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \ + defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES) + if (!ssl->options.userCurves && !ssl->ctx->userCurves) { + if (TLSX_Find(ssl->ctx->extensions, + TLSX_SUPPORTED_GROUPS) == NULL) { + ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + } + if ((!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade) && + TLSX_Find(ssl->ctx->extensions, TLSX_EC_POINT_FORMATS) == NULL && + TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS) == NULL) { + ret = TLSX_UsePointFormat(&ssl->extensions, + WOLFSSL_EC_PF_UNCOMPRESSED, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } +#endif /* (HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */ + } /* is not server */ + +#if !defined(WOLFSSL_NO_SIGALG) + WOLFSSL_MSG("Adding signature algorithms extension"); + if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, ssl, ssl->heap)) + != 0) { + return ret; + } +#else + ret = 0; +#endif + #ifdef WOLFSSL_TLS13 + if (!isServer && IsAtLeastTLSv1_3(ssl->version)) { + /* Add mandatory TLS v1.3 extension: supported version */ + WOLFSSL_MSG("Adding supported versions extension"); + if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl, + ssl->heap)) != 0) { + return ret; + } + + #if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && \ + !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES) + if (TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) { + /* Put in DH groups for TLS 1.3 only. */ + ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions); + if (ret != WOLFSSL_SUCCESS) + return ret; + ret = 0; + } + #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */ + + #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) + if (ssl->certHashSigAlgoSz > 0) { + WOLFSSL_MSG("Adding signature algorithms cert extension"); + if ((ret = TLSX_SetSignatureAlgorithmsCert(&ssl->extensions, + ssl, ssl->heap)) != 0) { + return ret; + } + } + #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */ + + if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { + word16 namedGroup; + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.resuming && ssl->session.namedGroup != 0) + namedGroup = ssl->session.namedGroup; + else + #endif + { + #if defined(HAVE_ECC) && (!defined(NO_ECC256) || \ + defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) + namedGroup = WOLFSSL_ECC_SECP256R1; + #elif defined(HAVE_CURVE25519) + namedGroup = WOLFSSL_ECC_X25519; + #elif defined(HAVE_CURVE448) + namedGroup = WOLFSSL_ECC_X448; + #elif defined(HAVE_ECC) && (!defined(NO_ECC384) || \ + defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) + namedGroup = WOLFSSL_ECC_SECP384R1; + #elif defined(HAVE_ECC) && (!defined(NO_ECC521) || \ + defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) + namedGroup = WOLFSSL_ECC_SECP521R1; + #elif defined(HAVE_FFDHE_2048) + namedGroup = WOLFSSL_FFDHE_2048; + #elif defined(HAVE_FFDHE_3072) + namedGroup = WOLFSSL_FFDHE_3072; + #elif defined(HAVE_FFDHE_4096) + namedGroup = WOLFSSL_FFDHE_4096; + #elif defined(HAVE_FFDHE_6144) + namedGroup = WOLFSSL_FFDHE_6144; + #elif defined(HAVE_FFDHE_8192) + namedGroup = WOLFSSL_FFDHE_8192; + #else + return KEY_SHARE_ERROR; + #endif + } + ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL); + if (ret != 0) + return ret; + } + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap); + #endif + #if defined(HAVE_SESSION_TICKET) + if (ssl->options.resuming && ssl->session.ticketLen > 0) { + WOLFSSL_SESSION* sess = &ssl->session; + word32 milli; + + if (sess->ticketLen > MAX_PSK_ID_LEN) { + WOLFSSL_MSG("Session ticket length for PSK ext is too large"); + return BUFFER_ERROR; + } + + /* Determine the MAC algorithm for the cipher suite used. */ + ssl->options.cipherSuite0 = sess->cipherSuite0; + ssl->options.cipherSuite = sess->cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + milli = TimeNowInMilliseconds() - sess->ticketSeen + + sess->ticketAdd; + /* Pre-shared key is mandatory extension for resumption. */ + ret = TLSX_PreSharedKey_Use(ssl, sess->ticket, sess->ticketLen, + milli, ssl->specs.mac_algorithm, + ssl->options.cipherSuite0, + ssl->options.cipherSuite, 1, + NULL); + if (ret != 0) + return ret; + + usingPSK = 1; + } + #endif + #ifndef NO_PSK + if (ssl->options.client_psk_cb != NULL || + ssl->options.client_psk_tls13_cb != NULL) { + /* Default ciphersuite. */ + byte cipherSuite0 = TLS13_BYTE; + byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + const char* cipherName = NULL; + + if (ssl->options.client_psk_tls13_cb != NULL) { + ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb( + ssl, ssl->arrays->server_hint, + ssl->arrays->client_identity, MAX_PSK_ID_LEN, + ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName); + if (GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) != 0) { + return PSK_KEY_ERROR; + } + } + else { + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays->server_hint, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + } + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + return PSK_KEY_ERROR; + } + ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; + /* TODO: Callback should be able to change ciphersuite. */ + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + ret = TLSX_PreSharedKey_Use(ssl, + (byte*)ssl->arrays->client_identity, + (word16)XSTRLEN(ssl->arrays->client_identity), + 0, ssl->specs.mac_algorithm, + cipherSuite0, cipherSuite, 0, + NULL); + if (ret != 0) + return ret; + + usingPSK = 1; + } + #endif + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (usingPSK) { + byte modes; + + /* Pre-shared key modes: mandatory extension for resumption. */ + modes = 1 << PSK_KE; + #if !defined(NO_DH) || defined(HAVE_ECC) || \ + defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) + if (!ssl->options.noPskDheKe) + modes |= 1 << PSK_DHE_KE; + #endif + ret = TLSX_PskKeModes_Use(ssl, modes); + if (ret != 0) + return ret; + } + #endif + #if defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (!isServer && ssl->options.postHandshakeAuth) { + ret = TLSX_PostHandAuth_Use(ssl); + if (ret != 0) + return ret; + } + #endif + } + + #endif + + (void)isServer; + (void)public_key; + (void)public_key_len; + (void)ssl; + + return ret; +} + + +#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT) + +/** Tells the buffered size of extensions to be sent into the client hello. */ +int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength) +{ + int ret = 0; + word16 length = 0; + byte semaphore[SEMAPHORE_SIZE] = {0}; + + if (!TLSX_SupportExtensions(ssl)) + return 0; + if (msgType == client_hello) { + EC_VALIDATE_REQUEST(ssl, semaphore); + PF_VALIDATE_REQUEST(ssl, semaphore); + QSH_VALIDATE_REQUEST(ssl, semaphore); + WOLF_STK_VALIDATE_REQUEST(ssl); +#if !defined(WOLFSSL_NO_SIGALG) + if (ssl->suites->hashSigAlgoSz == 0) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); +#endif +#if defined(WOLFSSL_TLS13) + if (!IsAtLeastTLSv1_2(ssl)) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + if (!IsAtLeastTLSv1_3(ssl->version)) { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); + #endif + #ifdef WOLFSSL_EARLY_DATA + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); + #endif + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE)); + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH)); + #endif + } +#endif + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + if (!ssl->ctx->cm->ocspStaplingEnabled) { + /* mark already sent, so it won't send it */ + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2)); + } + #endif + } + +#ifdef WOLFSSL_TLS13 + #ifndef NO_CERTS + else if (msgType == certificate_request) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); +#if !defined(WOLFSSL_NO_SIGALG) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); +#endif + /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, + * TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS + * TLSX_STATUS_REQUEST + */ + } + #endif +#endif + if (ssl->extensions) { + ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length); + if (ret != 0) + return ret; + } + if (ssl->ctx && ssl->ctx->extensions) { + ret = TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType, &length); + if (ret != 0) + return ret; + } + +#ifdef HAVE_EXTENDED_MASTER + if (msgType == client_hello && ssl->options.haveEMS && + (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) { + length += HELLO_EXT_SZ; + } +#endif + + if (length) + length += OPAQUE16_LEN; /* for total length storage. */ + + *pLength += length; + + return ret; +} + +/** Writes the extensions to be sent into the client hello. */ +int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset) +{ + int ret = 0; + word16 offset = 0; + byte semaphore[SEMAPHORE_SIZE] = {0}; + + if (!TLSX_SupportExtensions(ssl) || output == NULL) + return 0; + + offset += OPAQUE16_LEN; /* extensions length */ + + if (msgType == client_hello) { + EC_VALIDATE_REQUEST(ssl, semaphore); + PF_VALIDATE_REQUEST(ssl, semaphore); + WOLF_STK_VALIDATE_REQUEST(ssl); + QSH_VALIDATE_REQUEST(ssl, semaphore); +#if !defined(WOLFSSL_NO_SIGALG) + if (ssl->suites->hashSigAlgoSz == 0) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); +#endif +#ifdef WOLFSSL_TLS13 + if (!IsAtLeastTLSv1_2(ssl)) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + if (!IsAtLeastTLSv1_3(ssl->version)) { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); + #endif + #ifdef WOLFSSL_EARLY_DATA + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); + #endif + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE)); + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH)); + #endif + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Must write Pre-shared Key extension at the end in TLS v1.3. + * Must not write out Pre-shared Key extension in earlier versions of + * protocol. + */ + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif +#endif + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + /* mark already sent, so it won't send it */ + if (!ssl->ctx->cm->ocspStaplingEnabled) { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2)); + } + #endif + } +#ifdef WOLFSSL_TLS13 + #ifndef NO_CERTS + else if (msgType == certificate_request) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); +#if !defined(WOLFSSL_NO_SIGALG) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); +#endif + /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, + * TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS + * TLSX_STATUS_REQUEST + */ + } + #endif +#endif + if (ssl->extensions) { + ret = TLSX_Write(ssl->extensions, output + offset, semaphore, + msgType, &offset); + if (ret != 0) + return ret; + } + if (ssl->ctx && ssl->ctx->extensions) { + ret = TLSX_Write(ssl->ctx->extensions, output + offset, semaphore, + msgType, &offset); + if (ret != 0) + return ret; + } + +#ifdef HAVE_EXTENDED_MASTER + if (msgType == client_hello && ssl->options.haveEMS && + (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) { + WOLFSSL_MSG("EMS extension to write"); + c16toa(HELLO_EXT_EXTMS, output + offset); + offset += HELLO_EXT_TYPE_SZ; + c16toa(0, output + offset); + offset += HELLO_EXT_SZ_SZ; + } +#endif + +#ifdef WOLFSSL_TLS13 + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (msgType == client_hello && IsAtLeastTLSv1_3(ssl->version)) { + /* Write out what we can of Pre-shared key extension. */ + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + ret = TLSX_Write(ssl->extensions, output + offset, semaphore, + client_hello, &offset); + if (ret != 0) + return ret; + } + #endif +#endif + + if (offset > OPAQUE16_LEN || msgType != client_hello) + c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ + + *pOffset += offset; + + return ret; +} + +#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */ + +#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER) + +/** Tells the buffered size of extensions to be sent into the server hello. */ +int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) +{ + int ret = 0; + word16 length = 0; + byte semaphore[SEMAPHORE_SIZE] = {0}; + + switch (msgType) { +#ifndef NO_WOLFSSL_SERVER + case server_hello: + PF_VALIDATE_RESPONSE(ssl, semaphore); + #ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + #ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, + TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + #endif + if (!ssl->options.noPskDheKe) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + } + else { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + } + #endif + break; + + #ifdef WOLFSSL_TLS13 + case hello_retry_request: + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + #ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + #endif + if (!ssl->options.noPskDheKe) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE)); + break; + #endif + + #ifdef WOLFSSL_TLS13 + case encrypted_extensions: + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); + #endif + #if defined(HAVE_SECURE_RENEGOTIATION) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO)); + #endif + break; + + #ifdef WOLFSSL_EARLY_DATA + case session_ticket: + if (ssl->options.tls1_3) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); + } + break; + #endif + #endif +#endif + +#ifdef WOLFSSL_TLS13 + #ifndef NO_CERTS + case certificate: + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); + /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, + * TLSX_SERVER_CERTIFICATE_TYPE + */ + break; + #endif +#endif + } + + #ifdef HAVE_QSH + /* change response if not using TLS_QSH */ + if (!ssl->options.haveQSH) { + TLSX* ext = TLSX_Find(ssl->extensions, TLSX_QUANTUM_SAFE_HYBRID); + if (ext) + ext->resp = 0; + } + #endif + +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS && msgType == server_hello && + !IsAtLeastTLSv1_3(ssl->version)) { + length += HELLO_EXT_SZ; + } +#endif + + if (TLSX_SupportExtensions(ssl)) { + ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length); + if (ret != 0) + return ret; + } + + /* All the response data is set at the ssl object only, so no ctx here. */ + + if (length || msgType != server_hello) + length += OPAQUE16_LEN; /* for total length storage. */ + + *pLength += length; + + return ret; +} + +/** Writes the server hello extensions into a buffer. */ +int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset) +{ + int ret = 0; + word16 offset = 0; + + if (TLSX_SupportExtensions(ssl) && output) { + byte semaphore[SEMAPHORE_SIZE] = {0}; + + switch (msgType) { +#ifndef NO_WOLFSSL_SERVER + case server_hello: + PF_VALIDATE_RESPONSE(ssl, semaphore); + #ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + #ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, + TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + #endif + if (!ssl->options.noPskDheKe) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + } + else { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + } + #endif + break; + + #ifdef WOLFSSL_TLS13 + case hello_retry_request: + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + #ifndef WOLFSSL_TLS13_DRAFT_18 + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + #endif + if (!ssl->options.noPskDheKe) + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + /* Cookie is written below as last extension. */ + break; + #endif + + #ifdef WOLFSSL_TLS13 + case encrypted_extensions: + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); + #endif + #if defined(HAVE_SECURE_RENEGOTIATION) + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO)); + #endif + break; + + #ifdef WOLFSSL_EARLY_DATA + case session_ticket: + if (ssl->options.tls1_3) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); + } + break; + #endif + #endif +#endif + + #ifdef WOLFSSL_TLS13 + #ifndef NO_CERTS + case certificate: + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); + /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, + * TLSX_SERVER_CERTIFICATE_TYPE + */ + break; + #endif + #endif + } + + offset += OPAQUE16_LEN; /* extensions length */ + + ret = TLSX_Write(ssl->extensions, output + offset, semaphore, + msgType, &offset); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_TLS13 + if (msgType == hello_retry_request) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE)); + ret = TLSX_Write(ssl->extensions, output + offset, semaphore, + msgType, &offset); + if (ret != 0) + return ret; + } +#endif + +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS && msgType == server_hello && + !IsAtLeastTLSv1_3(ssl->version)) { + WOLFSSL_MSG("EMS extension to write"); + c16toa(HELLO_EXT_EXTMS, output + offset); + offset += HELLO_EXT_TYPE_SZ; + c16toa(0, output + offset); + offset += HELLO_EXT_SZ_SZ; + } +#endif + + if (offset > OPAQUE16_LEN || msgType != server_hello) + c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ + } + + if (pOffset) + *pOffset += offset; + + return ret; +} + +#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_SERVER */ + +#ifdef WOLFSSL_TLS13 +int TLSX_ParseVersion(WOLFSSL* ssl, byte* input, word16 length, byte msgType, + int* found) +{ + int ret = 0; + int offset = 0; + + *found = 0; + while (offset < (int)length) { + word16 type; + word16 size; + + if (offset + (2 * OPAQUE16_LEN) > length) { + ret = BUFFER_ERROR; + break; + } + + ato16(input + offset, &type); + offset += HELLO_EXT_TYPE_SZ; + + ato16(input + offset, &size); + offset += OPAQUE16_LEN; + + if (offset + size > length) { + ret = BUFFER_ERROR; + break; + } + + if (type == TLSX_SUPPORTED_VERSIONS) { + *found = 1; + + WOLFSSL_MSG("Supported Versions extension received"); + + ret = SV_PARSE(ssl, input + offset, size, msgType); + break; + } + + offset += size; + } + + return ret; +} +#endif + +/** Parses a buffer of TLS extensions. */ +int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, + Suites *suites) +{ + int ret = 0; + word16 offset = 0; + byte isRequest = (msgType == client_hello || + msgType == certificate_request); + +#ifdef HAVE_EXTENDED_MASTER + byte pendingEMS = 0; +#endif +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) + int pskDone = 0; +#endif + + if (!ssl || !input || (isRequest && !suites)) + return BAD_FUNC_ARG; + + while (ret == 0 && offset < length) { + word16 type; + word16 size; + +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) + if (msgType == client_hello && pskDone) + return PSK_KEY_ERROR; +#endif + + if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input + offset, &type); + offset += HELLO_EXT_TYPE_SZ; + + ato16(input + offset, &size); + offset += OPAQUE16_LEN; + + if (offset + size > length) + return BUFFER_ERROR; + + switch (type) { + case TLSX_SERVER_NAME: + WOLFSSL_MSG("SNI extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != server_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } + else if (!IsAtLeastTLSv1_3(ssl->version) && + msgType == encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif + ret = SNI_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_TRUSTED_CA_KEYS: + WOLFSSL_MSG("Trusted CA extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif + ret = TCA_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_MAX_FRAGMENT_LENGTH: + WOLFSSL_MSG("Max Fragment Length extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } + else if (!IsAtLeastTLSv1_3(ssl->version) && + msgType == encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif + ret = MFL_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_TRUNCATED_HMAC: + WOLFSSL_MSG("Truncated HMAC extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + break; +#endif + ret = THM_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_SUPPORTED_GROUPS: + WOLFSSL_MSG("Supported Groups extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != server_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } + else if (!IsAtLeastTLSv1_3(ssl->version) && + msgType == encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif + ret = EC_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_EC_POINT_FORMATS: + WOLFSSL_MSG("Point Formats extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + break; +#endif + ret = PF_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_STATUS_REQUEST: + WOLFSSL_MSG("Certificate Status Request extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + #ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != certificate_request && + msgType != certificate) { + break; + } + #endif + ret = CSR_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_STATUS_REQUEST_V2: + WOLFSSL_MSG("Certificate Status Request v2 extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != certificate_request && + msgType != certificate) { + return EXT_NOT_ALLOWED; + } +#endif + ret = CSR2_PARSE(ssl, input + offset, size, isRequest); + break; + +#ifdef HAVE_EXTENDED_MASTER + case HELLO_EXT_EXTMS: + WOLFSSL_MSG("Extended Master Secret extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + break; +#endif + if (size != 0) + return BUFFER_ERROR; + +#ifndef NO_WOLFSSL_SERVER + if (isRequest) + ssl->options.haveEMS = 1; +#endif + pendingEMS = 1; + break; +#endif + + case TLSX_RENEGOTIATION_INFO: + WOLFSSL_MSG("Secure Renegotiation extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + break; +#endif + ret = SCR_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_SESSION_TICKET: + WOLFSSL_MSG("Session Ticket extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } +#endif + ret = WOLF_STK_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_QUANTUM_SAFE_HYBRID: + WOLFSSL_MSG("Quantum-Safe-Hybrid extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + break; +#endif + ret = QSH_PARSE(ssl, input + offset, size, isRequest); + break; + + case TLSX_APPLICATION_LAYER_PROTOCOL: + WOLFSSL_MSG("ALPN extension received"); + + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != server_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } + else if (!IsAtLeastTLSv1_3(ssl->version) && + msgType == encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif + ret = ALPN_PARSE(ssl, input + offset, size, isRequest); + break; +#if !defined(WOLFSSL_NO_SIGALG) + case TLSX_SIGNATURE_ALGORITHMS: + WOLFSSL_MSG("Signature Algorithms extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_2(ssl)) + break; +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != certificate_request) { + return EXT_NOT_ALLOWED; + } +#endif + ret = SA_PARSE(ssl, input + offset, size, isRequest, suites); + break; +#endif + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + WOLFSSL_MSG("Encrypt-Then-Mac extension received"); + + /* Ignore for TLS 1.3+ */ + if (IsAtLeastTLSv1_3(ssl->version)) + break; + + ret = ETM_PARSE(ssl, input + offset, size, msgType); + break; +#endif /* HAVE_ENCRYPT_THEN_MAC */ + +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + WOLFSSL_MSG("Skipping Supported Versions - already processed"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + break; + + case TLSX_COOKIE: + WOLFSSL_MSG("Cookie extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello && + msgType != hello_retry_request) { + return EXT_NOT_ALLOWED; + } + + ret = CKE_PARSE(ssl, input + offset, size, msgType); + break; + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + case TLSX_PRE_SHARED_KEY: + WOLFSSL_MSG("Pre-Shared Key extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello && msgType != server_hello) + return EXT_NOT_ALLOWED; + + ret = PSK_PARSE(ssl, input + offset, size, msgType); + pskDone = 1; + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + WOLFSSL_MSG("PSK Key Exchange Modes extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello) + return EXT_NOT_ALLOWED; + + ret = PKM_PARSE(ssl, input + offset, size, msgType); + break; + #endif + + #ifdef WOLFSSL_EARLY_DATA + case TLSX_EARLY_DATA: + WOLFSSL_MSG("Early Data extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello && msgType != session_ticket && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } + if (!IsAtLeastTLSv1_3(ssl->version) && + (msgType == session_ticket || + msgType == encrypted_extensions)) { + return EXT_NOT_ALLOWED; + } + ret = EDI_PARSE(ssl, input + offset, size, msgType); + break; + #endif + + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + WOLFSSL_MSG("Post Handshake Authentication extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello) + return EXT_NOT_ALLOWED; + + ret = PHA_PARSE(ssl, input + offset, size, msgType); + break; + #endif + + #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) + case TLSX_SIGNATURE_ALGORITHMS_CERT: + WOLFSSL_MSG("Signature Algorithms extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello && + msgType != certificate_request) { + return EXT_NOT_ALLOWED; + } + if (!IsAtLeastTLSv1_3(ssl->version) && + msgType == certificate_request) { + return EXT_NOT_ALLOWED; + } + + ret = SAC_PARSE(ssl, input + offset, size, isRequest); + break; + #endif + + case TLSX_KEY_SHARE: + WOLFSSL_MSG("Key Share extension received"); + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_BUFFER(input + offset, size); + #endif + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (msgType != client_hello && msgType != server_hello && + msgType != hello_retry_request) { + return EXT_NOT_ALLOWED; + } + ret = KS_PARSE(ssl, input + offset, size, msgType); + break; +#endif + default: + WOLFSSL_MSG("Unknown TLS extension type"); + } + + /* offset should be updated here! */ + offset += size; + } + +#ifdef HAVE_EXTENDED_MASTER + if (!isRequest && ssl->options.haveEMS && !pendingEMS) + ssl->options.haveEMS = 0; +#endif + + if (ret == 0) + ret = SNI_VERIFY_PARSE(ssl, isRequest); + if (ret == 0) + ret = TCA_VERIFY_PARSE(ssl, isRequest); + + return ret; +} + +/* undefining semaphore macros */ +#undef IS_OFF +#undef TURN_ON +#undef SEMAPHORE_SIZE + +#endif /* HAVE_TLS_EXTENSIONS */ + +#ifndef NO_WOLFSSL_CLIENT + + WOLFSSL_METHOD* wolfTLS_client_method(void) + { + return wolfTLS_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLS_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLS_client_method_ex"); + if (method) { + #if defined(WOLFSSL_TLS13) + InitSSL_Method(method, MakeTLSv1_3()); + #elif !defined(WOLFSSL_NO_TLS12) + InitSSL_Method(method, MakeTLSv1_2()); + #elif !defined(NO_OLD_TLS) + InitSSL_Method(method, MakeTLSv1_1()); + #elif defined(WOLFSSL_ALLOW_TLSV10) + InitSSL_Method(method, MakeTLSv1()); + #else + #error No TLS version enabled! + #endif + + method->downgrade = 1; + method->side = WOLFSSL_CLIENT_END; + } + return method; + } + +#ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + WOLFSSL_METHOD* wolfTLSv1_client_method(void) + { + return wolfTLSv1_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_client_method_ex"); + if (method) + InitSSL_Method(method, MakeTLSv1()); + return method; + } + #endif /* WOLFSSL_ALLOW_TLSV10 */ + + WOLFSSL_METHOD* wolfTLSv1_1_client_method(void) + { + return wolfTLSv1_1_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_1_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_1_client_method_ex"); + if (method) + InitSSL_Method(method, MakeTLSv1_1()); + return method; + } +#endif /* !NO_OLD_TLS */ + +#ifndef WOLFSSL_NO_TLS12 + WOLFSSL_ABI + WOLFSSL_METHOD* wolfTLSv1_2_client_method(void) + { + return wolfTLSv1_2_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_2_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_2_client_method_ex"); + if (method) + InitSSL_Method(method, MakeTLSv1_2()); + return method; + } +#endif /* WOLFSSL_NO_TLS12 */ + +#ifdef WOLFSSL_TLS13 + /* The TLS v1.3 client method data. + * + * returns the method data for a TLS v1.3 client. + */ + WOLFSSL_ABI + WOLFSSL_METHOD* wolfTLSv1_3_client_method(void) + { + return wolfTLSv1_3_client_method_ex(NULL); + } + + /* The TLS v1.3 client method data. + * + * heap The heap used for allocation. + * returns the method data for a TLS v1.3 client. + */ + WOLFSSL_METHOD* wolfTLSv1_3_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = (WOLFSSL_METHOD*) + XMALLOC(sizeof(WOLFSSL_METHOD), heap, + DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_3_client_method_ex"); + if (method) + InitSSL_Method(method, MakeTLSv1_3()); + return method; + } +#endif /* WOLFSSL_TLS13 */ + +#ifdef WOLFSSL_DTLS + + WOLFSSL_METHOD* wolfDTLS_client_method(void) + { + return wolfDTLS_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLS_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("DTLS_client_method_ex"); + if (method) { + #if !defined(WOLFSSL_NO_TLS12) + InitSSL_Method(method, MakeDTLSv1_2()); + #elif !defined(NO_OLD_TLS) + InitSSL_Method(method, MakeDTLSv1()); + #else + #error No DTLS version enabled! + #endif + + method->downgrade = 1; + method->side = WOLFSSL_CLIENT_END; + } + return method; + } + + #ifndef NO_OLD_TLS + WOLFSSL_METHOD* wolfDTLSv1_client_method(void) + { + return wolfDTLSv1_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLSv1_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("DTLSv1_client_method_ex"); + if (method) + InitSSL_Method(method, MakeDTLSv1()); + return method; + } + #endif /* NO_OLD_TLS */ + + #ifndef WOLFSSL_NO_TLS12 + WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void) + { + return wolfDTLSv1_2_client_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLSv1_2_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("DTLSv1_2_client_method_ex"); + if (method) + InitSSL_Method(method, MakeDTLSv1_2()); + (void)heap; + return method; + } + #endif /* !WOLFSSL_NO_TLS12 */ +#endif /* WOLFSSL_DTLS */ + +#endif /* NO_WOLFSSL_CLIENT */ + + +/* EITHER SIDE METHODS */ +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + /* Gets a WOLFSL_METHOD type that is not set as client or server + * + * Returns a pointer to a WOLFSSL_METHOD struct + */ + WOLFSSL_METHOD* wolfTLSv1_method(void) + { + return wolfTLSv1_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("TLSv1_method"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfTLSv1_client_method_ex(heap); + #else + m = wolfTLSv1_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + + return m; + } + #endif /* WOLFSSL_ALLOW_TLSV10 */ + + /* Gets a WOLFSL_METHOD type that is not set as client or server + * + * Returns a pointer to a WOLFSSL_METHOD struct + */ + WOLFSSL_METHOD* wolfTLSv1_1_method(void) + { + return wolfTLSv1_1_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_1_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("TLSv1_1_method"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfTLSv1_1_client_method_ex(heap); + #else + m = wolfTLSv1_1_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + #endif /* !NO_OLD_TLS */ + + #ifndef WOLFSSL_NO_TLS12 + /* Gets a WOLFSL_METHOD type that is not set as client or server + * + * Returns a pointer to a WOLFSSL_METHOD struct + */ + WOLFSSL_METHOD* wolfTLSv1_2_method(void) + { + return wolfTLSv1_2_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_2_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("TLSv1_2_method"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfTLSv1_2_client_method_ex(heap); + #else + m = wolfTLSv1_2_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + #endif /* !WOLFSSL_NO_TLS12 */ + + #ifdef WOLFSSL_TLS13 + /* Gets a WOLFSL_METHOD type that is not set as client or server + * + * Returns a pointer to a WOLFSSL_METHOD struct + */ + WOLFSSL_METHOD* wolfTLSv1_3_method(void) + { + return wolfTLSv1_3_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_3_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("TLSv1_3_method"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfTLSv1_3_client_method_ex(heap); + #else + m = wolfTLSv1_3_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + #endif /* WOLFSSL_TLS13 */ + +#ifdef WOLFSSL_DTLS + WOLFSSL_METHOD* wolfDTLS_method(void) + { + return wolfDTLS_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLS_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("DTLS_method_ex"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfDTLS_client_method_ex(heap); + #else + m = wolfDTLS_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + + #ifndef NO_OLD_TLS + WOLFSSL_METHOD* wolfDTLSv1_method(void) + { + return wolfDTLSv1_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLSv1_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("DTLSv1_method_ex"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfDTLSv1_client_method_ex(heap); + #else + m = wolfDTLSv1_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + #endif /* !NO_OLD_TLS */ + #ifndef WOLFSSL_NO_TLS12 + WOLFSSL_METHOD* wolfDTLSv1_2_method(void) + { + return wolfDTLSv1_2_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLSv1_2_method_ex(void* heap) + { + WOLFSSL_METHOD* m; + WOLFSSL_ENTER("DTLSv1_2_method"); + #ifndef NO_WOLFSSL_CLIENT + m = wolfDTLSv1_2_client_method_ex(heap); + #else + m = wolfDTLSv1_2_server_method_ex(heap); + #endif + if (m != NULL) { + m->side = WOLFSSL_NEITHER_END; + } + return m; + } + #endif /* !WOLFSSL_NO_TLS12 */ +#endif /* WOLFSSL_DTLS */ +#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + + +#ifndef NO_WOLFSSL_SERVER + + WOLFSSL_METHOD* wolfTLS_server_method(void) + { + return wolfTLS_server_method_ex(NULL); + } + + WOLFSSL_METHOD* wolfTLS_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLS_server_method_ex"); + if (method) { + #if defined(WOLFSSL_TLS13) + InitSSL_Method(method, MakeTLSv1_3()); + #elif !defined(WOLFSSL_NO_TLS12) + InitSSL_Method(method, MakeTLSv1_2()); + #elif !defined(NO_OLD_TLS) + InitSSL_Method(method, MakeTLSv1_1()); + #elif defined(WOLFSSL_ALLOW_TLSV10) + InitSSL_Method(method, MakeTLSv1()); + #else + #error No TLS version enabled! + #endif + + method->downgrade = 1; + method->side = WOLFSSL_SERVER_END; + } + return method; + } + +#ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + WOLFSSL_METHOD* wolfTLSv1_server_method(void) + { + return wolfTLSv1_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_server_method_ex"); + if (method) { + InitSSL_Method(method, MakeTLSv1()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } + #endif /* WOLFSSL_ALLOW_TLSV10 */ + + WOLFSSL_METHOD* wolfTLSv1_1_server_method(void) + { + return wolfTLSv1_1_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_1_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_1_server_method_ex"); + if (method) { + InitSSL_Method(method, MakeTLSv1_1()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } +#endif /* !NO_OLD_TLS */ + + +#ifndef WOLFSSL_NO_TLS12 + WOLFSSL_METHOD* wolfTLSv1_2_server_method(void) + { + return wolfTLSv1_2_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfTLSv1_2_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_2_server_method_ex"); + if (method) { + InitSSL_Method(method, MakeTLSv1_2()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } +#endif /* !WOLFSSL_NO_TLS12 */ + +#ifdef WOLFSSL_TLS13 + /* The TLS v1.3 server method data. + * + * returns the method data for a TLS v1.3 server. + */ + WOLFSSL_METHOD* wolfTLSv1_3_server_method(void) + { + return wolfTLSv1_3_server_method_ex(NULL); + } + + /* The TLS v1.3 server method data. + * + * heap The heap used for allocation. + * returns the method data for a TLS v1.3 server. + */ + WOLFSSL_METHOD* wolfTLSv1_3_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("TLSv1_3_server_method_ex"); + if (method) { + InitSSL_Method(method, MakeTLSv1_3()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } +#endif /* WOLFSSL_TLS13 */ + +#ifdef WOLFSSL_DTLS + WOLFSSL_METHOD* wolfDTLS_server_method(void) + { + return wolfDTLS_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLS_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("DTLS_server_method_ex"); + if (method) { + #if !defined(WOLFSSL_NO_TLS12) + InitSSL_Method(method, MakeDTLSv1_2()); + #elif !defined(NO_OLD_TLS) + InitSSL_Method(method, MakeDTLSv1()); + #else + #error No DTLS version enabled! + #endif + + method->downgrade = 1; + method->side = WOLFSSL_SERVER_END; + } + return method; + } + + #ifndef NO_OLD_TLS + WOLFSSL_METHOD* wolfDTLSv1_server_method(void) + { + return wolfDTLSv1_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLSv1_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + WOLFSSL_ENTER("DTLSv1_server_method_ex"); + if (method) { + InitSSL_Method(method, MakeDTLSv1()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } + #endif /* !NO_OLD_TLS */ + + #ifndef WOLFSSL_NO_TLS12 + WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void) + { + return wolfDTLSv1_2_server_method_ex(NULL); + } + WOLFSSL_METHOD* wolfDTLSv1_2_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + WOLFSSL_ENTER("DTLSv1_2_server_method_ex"); + (void)heap; + if (method) { + InitSSL_Method(method, MakeDTLSv1_2()); + method->side = WOLFSSL_SERVER_END; + } + (void)heap; + return method; + } + #endif /* !WOLFSSL_NO_TLS12 */ +#endif /* WOLFSSL_DTLS */ + +#endif /* NO_WOLFSSL_SERVER */ + +#endif /* NO_TLS */ +#endif /* WOLFCRYPT_ONLY */ diff --git a/client/wolfssl/src/tls13.c b/client/wolfssl/src/tls13.c new file mode 100644 index 0000000..9b9b1d1 --- /dev/null +++ b/client/wolfssl/src/tls13.c @@ -0,0 +1,9048 @@ +/* tls13.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +/* + * BUILD_GCM + * Enables AES-GCM ciphersuites. + * HAVE_AESCCM + * Enables AES-CCM ciphersuites. + * HAVE_SESSION_TICKET + * Enables session tickets - required for TLS 1.3 resumption. + * NO_PSK + * Do not enable Pre-Shared Keys. + * TLS13_SUPPORTS_EXPORTERS + * Guard to compile out any code for exporter keys. + * Feature not supported yet. + * WOLFSSL_ASYNC_CRYPT + * Enables the use of asynchronous cryptographic operations. + * This is available for ciphers and certificates. + * HAVE_CHACHA && HAVE_POLY1305 + * Enables use of CHACHA20-POLY1305 ciphersuites. + * WOLFSSL_DEBUG_TLS + * Writes out details of TLS 1.3 protocol including handshake message buffers + * and key generation input and output. + * WOLFSSL_EARLY_DATA + * Allow 0-RTT Handshake using Early Data extensions and handshake message + * WOLFSSL_EARLY_DATA_GROUP + * Group EarlyData message with ClientHello when sending + * WOLFSSL_NO_SERVER_GROUPS_EXT + * Do not send the server's groups in an extension when the server's top + * preference is not in client's list. + * WOLFSSL_POST_HANDSHAKE_AUTH + * Allow TLS v1.3 code to perform post-handshake authentication of the + * client. + * WOLFSSL_SEND_HRR_COOKIE + * Send a cookie in hello_retry_request message to enable stateless tracking + * of ClientHello replies. + * WOLFSSL_TLS13 + * Enable TLS 1.3 protocol implementation. + * WOLFSSL_TLS13_DRAFT_18 + * Conform with Draft 18 of the TLS v1.3 specification. + * WOLFSSL_TLS13_DRAFT_22 + * Conform with Draft 22 of the TLS v1.3 specification. + * WOLFSSL_TLS13_DRAFT_23 + * Conform with Draft 23 of the TLS v1.3 specification. + * WOLFSSL_TLS13_MIDDLEBOX_COMPAT + * Enable middlebox compatibility in the TLS 1.3 handshake. + * This includes sending ChangeCipherSpec before encrypted messages and + * including a session id. + * WOLFSSL_TLS13_SHA512 + * Allow generation of SHA-512 digests in handshake - no ciphersuite + * requires SHA-512 at this time. + * WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + * Allow a NewSessionTicket message to be sent by server before Client's + * Finished message. + * See TLS v1.3 specification, Section 4.6.1, Paragraph 4 (Note). + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_TLS13 +#ifdef HAVE_SESSION_TICKET + #include +#endif + +#ifndef WOLFCRYPT_ONLY + +#ifdef HAVE_ERRNO_H + #include +#endif + +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#ifdef HAVE_NTRU + #include "libntruencrypt/ntru_crypto.h" +#endif + +#ifdef __sun + #include +#endif + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef HAVE_HKDF + #error The build option HAVE_HKDF is required for TLS 1.3 +#endif + +#ifndef HAVE_TLS_EXTENSIONS + #ifndef _MSC_VER + #error "The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3" + #else + #pragma message("error: The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3") + #endif +#endif + + +/* Set ret to error value and jump to label. + * + * err The error value to set. + * eLabel The label to jump to. + */ +#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; } + + +/* Extract data using HMAC, salt and input. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + * + * prk The generated pseudorandom key. + * salt The salt. + * saltLen The length of the salt. + * ikm The input keying material. + * ikmLen The length of the input keying material. + * mac The type of digest to use. + * returns 0 on success, otherwise failure. + */ +static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, + byte* ikm, int ikmLen, int mac) +{ + int ret; + int hash = 0; + int len = 0; + + switch (mac) { + #ifndef NO_SHA256 + case sha256_mac: + hash = WC_SHA256; + len = WC_SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = WC_SHA384; + len = WC_SHA384_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hash = WC_SHA512; + len = WC_SHA512_DIGEST_SIZE; + break; + #endif + } + + /* When length is 0 then use zeroed data of digest length. */ + if (ikmLen == 0) { + ikmLen = len; + XMEMSET(ikm, 0, len); + } + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" Salt"); + WOLFSSL_BUFFER(salt, saltLen); + WOLFSSL_MSG(" IKM"); + WOLFSSL_BUFFER(ikm, ikmLen); +#endif + + ret = wc_HKDF_Extract(hash, salt, saltLen, ikm, ikmLen, prk); + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" PRK"); + WOLFSSL_BUFFER(prk, len); +#endif + + return ret; +} + +/* Expand data using HMAC, salt and label and info. + * TLS v1.3 defines this function. + * + * okm The generated pseudorandom key - output key material. + * okmLen The length of generated pseudorandom key - output key material. + * prk The salt - pseudo-random key. + * prkLen The length of the salt - pseudo-random key. + * protocol The TLS protocol label. + * protocolLen The length of the TLS protocol label. + * info The information to expand. + * infoLen The length of the information. + * digest The type of digest to use. + * returns 0 on success, otherwise failure. + */ +static int HKDF_Expand_Label(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, + const byte* protocol, word32 protocolLen, + const byte* label, word32 labelLen, + const byte* info, word32 infoLen, + int digest) +{ + int ret = 0; + int idx = 0; + byte data[MAX_HKDF_LABEL_SZ]; + + /* Output length. */ + data[idx++] = (byte)(okmLen >> 8); + data[idx++] = (byte)okmLen; + /* Length of protocol | label. */ + data[idx++] = (byte)(protocolLen + labelLen); + /* Protocol */ + XMEMCPY(&data[idx], protocol, protocolLen); + idx += protocolLen; + /* Label */ + XMEMCPY(&data[idx], label, labelLen); + idx += labelLen; + /* Length of hash of messages */ + data[idx++] = (byte)infoLen; + /* Hash of messages */ + XMEMCPY(&data[idx], info, infoLen); + idx += infoLen; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" PRK"); + WOLFSSL_BUFFER(prk, prkLen); + WOLFSSL_MSG(" Info"); + WOLFSSL_BUFFER(data, idx); +#endif + + ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen); + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" OKM"); + WOLFSSL_BUFFER(okm, okmLen); +#endif + + ForceZero(data, idx); + + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* Size of the TLS v1.3 label use when deriving keys. */ +#define TLS13_PROTOCOL_LABEL_SZ 9 +/* The protocol label for TLS v1.3. */ +static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "TLS 1.3, "; +#else +/* Size of the TLS v1.3 label use when deriving keys. */ +#define TLS13_PROTOCOL_LABEL_SZ 6 +/* The protocol label for TLS v1.3. */ +static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "tls13 "; +#endif + +#if !defined(WOLFSSL_TLS13_DRAFT_18) || defined(HAVE_SESSION_TICKET) || \ + !defined(NO_PSK) +/* Derive a key from a message. + * + * ssl The SSL/TLS object. + * output The buffer to hold the derived key. + * outputLen The length of the derived key. + * secret The secret used to derive the key (HMAC secret). + * label The label used to distinguish the context. + * labelLen The length of the label. + * msg The message data to derive key from. + * msgLen The length of the message data to derive key from. + * hashAlgo The hash algorithm to use in the HMAC. + * returns 0 on success, otherwise failure. + */ +static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, + const byte* secret, const byte* label, word32 labelLen, + byte* msg, int msgLen, int hashAlgo) +{ + byte hash[WC_MAX_DIGEST_SIZE]; + Digest digest; + word32 hashSz = 0; + const byte* protocol; + word32 protocolLen; + int digestAlg = -1; + int ret = BAD_FUNC_ARG; + + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + ret = wc_InitSha256_ex(&digest.sha256, ssl->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha256Update(&digest.sha256, msg, msgLen); + if (ret == 0) + ret = wc_Sha256Final(&digest.sha256, hash); + wc_Sha256Free(&digest.sha256); + } + hashSz = WC_SHA256_DIGEST_SIZE; + digestAlg = WC_SHA256; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_InitSha384_ex(&digest.sha384, ssl->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha384Update(&digest.sha384, msg, msgLen); + if (ret == 0) + ret = wc_Sha384Final(&digest.sha384, hash); + wc_Sha384Free(&digest.sha384); + } + hashSz = WC_SHA384_DIGEST_SIZE; + digestAlg = WC_SHA384; + break; +#endif +#ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + ret = wc_InitSha512_ex(&digest.sha512, ssl->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha512Update(&digest.sha512, msg, msgLen); + if (ret == 0) + ret = wc_Sha512Final(&digest.sha512, hash); + wc_Sha512Free(&digest.sha512); + } + hashSz = WC_SHA512_DIGEST_SIZE; + digestAlg = WC_SHA512; + break; +#endif + default: + digestAlg = -1; + break; + } + + if (digestAlg < 0) + return HASH_TYPE_E; + + if (ret != 0) + return ret; + + switch (ssl->version.minor) { + case TLSv1_3_MINOR: + protocol = tls13ProtocolLabel; + protocolLen = TLS13_PROTOCOL_LABEL_SZ; + break; + + default: + return VERSION_ERROR; + } + if (outputLen == -1) + outputLen = hashSz; + + return HKDF_Expand_Label(output, outputLen, secret, hashSz, + protocol, protocolLen, label, labelLen, + hash, hashSz, digestAlg); +} +#endif + +/* Derive a key. + * + * ssl The SSL/TLS object. + * output The buffer to hold the derived key. + * outputLen The length of the derived key. + * secret The secret used to derive the key (HMAC secret). + * label The label used to distinguish the context. + * labelLen The length of the label. + * hashAlgo The hash algorithm to use in the HMAC. + * includeMsgs Whether to include a hash of the handshake messages so far. + * returns 0 on success, otherwise failure. + */ +static int DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, + const byte* secret, const byte* label, word32 labelLen, + int hashAlgo, int includeMsgs) +{ + int ret = 0; + byte hash[WC_MAX_DIGEST_SIZE]; + word32 hashSz = 0; + word32 hashOutSz = 0; + const byte* protocol; + word32 protocolLen; + int digestAlg = 0; + + switch (hashAlgo) { + #ifndef NO_SHA256 + case sha256_mac: + hashSz = WC_SHA256_DIGEST_SIZE; + digestAlg = WC_SHA256; + if (includeMsgs) + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hashSz = WC_SHA384_DIGEST_SIZE; + digestAlg = WC_SHA384; + if (includeMsgs) + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hashSz = WC_SHA512_DIGEST_SIZE; + digestAlg = WC_SHA512; + if (includeMsgs) + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + break; + #endif + } + if (ret != 0) + return ret; + + /* Only one protocol version defined at this time. */ + protocol = tls13ProtocolLabel; + protocolLen = TLS13_PROTOCOL_LABEL_SZ; + + if (outputLen == -1) + outputLen = hashSz; + if (includeMsgs) + hashOutSz = hashSz; + + return HKDF_Expand_Label(output, outputLen, secret, hashSz, + protocol, protocolLen, label, labelLen, + hash, hashOutSz, digestAlg); +} + +#ifndef NO_PSK +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the binder key label. */ +#define BINDER_KEY_LABEL_SZ 23 +/* The binder key label. */ +static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] = + "external psk binder key"; +#else +/* The length of the binder key label. */ +#define BINDER_KEY_LABEL_SZ 10 +/* The binder key label. */ +static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] = + "ext binder"; +#endif +/* Derive the binder key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveBinderKey(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Binder Key"); + return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + binderKeyLabel, BINDER_KEY_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} +#endif /* !NO_PSK */ + +#ifdef HAVE_SESSION_TICKET +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the binder key resume label. */ +#define BINDER_KEY_RESUME_LABEL_SZ 25 +/* The binder key resume label. */ +static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] = + "resumption psk binder key"; +#else +/* The length of the binder key resume label. */ +#define BINDER_KEY_RESUME_LABEL_SZ 10 +/* The binder key resume label. */ +static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] = + "res binder"; +#endif +/* Derive the binder resumption key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Binder Key - Resumption"); + return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} +#endif /* HAVE_SESSION_TICKET */ + +#ifdef WOLFSSL_EARLY_DATA +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the early traffic label. */ +#define EARLY_TRAFFIC_LABEL_SZ 27 +/* The early traffic label. */ +static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] = + "client early traffic secret"; +#else +/* The length of the early traffic label. */ +#define EARLY_TRAFFIC_LABEL_SZ 11 +/* The early traffic label. */ +static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] = + "c e traffic"; +#endif +/* Derive the early traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Early Traffic Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_EARLY_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef TLS13_SUPPORTS_EXPORTERS +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the early exporter label. */ +#define EARLY_EXPORTER_LABEL_SZ 28 +/* The early exporter label. */ +static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] = + "early exporter master secret"; +#else +/* The length of the early exporter label. */ +#define EARLY_EXPORTER_LABEL_SZ 12 +/* The early exporter label. */ +static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] = + "e exp master"; +#endif +/* Derive the early exporter key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Early Exporter Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, EARLY_EXPORTER_SECRET, key + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} +#endif +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the client handshake label. */ +#define CLIENT_HANDSHAKE_LABEL_SZ 31 +/* The client handshake label. */ +static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = + "client handshake traffic secret"; +#else +/* The length of the client handshake label. */ +#define CLIENT_HANDSHAKE_LABEL_SZ 12 +/* The client handshake label. */ +static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = + "c hs traffic"; +#endif +/* Derive the client handshake key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Client Handshake Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_HANDSHAKE_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the server handshake label. */ +#define SERVER_HANDSHAKE_LABEL_SZ 31 +/* The server handshake label. */ +static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] = + "server handshake traffic secret"; +#else +/* The length of the server handshake label. */ +#define SERVER_HANDSHAKE_LABEL_SZ 12 +/* The server handshake label. */ +static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] = + "s hs traffic"; +#endif +/* Derive the server handshake key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Server Handshake Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, SERVER_HANDSHAKE_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the client application traffic label. */ +#define CLIENT_APP_LABEL_SZ 33 +/* The client application traffic label. */ +static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] = + "client application traffic secret"; +#else +/* The length of the client application traffic label. */ +#define CLIENT_APP_LABEL_SZ 12 +/* The client application traffic label. */ +static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] = + "c ap traffic"; +#endif +/* Derive the client application traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Client Traffic Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + clientAppLabel, CLIENT_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the server application traffic label. */ +#define SERVER_APP_LABEL_SZ 33 +/* The server application traffic label. */ +static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] = + "server application traffic secret"; +#else +/* The length of the server application traffic label. */ +#define SERVER_APP_LABEL_SZ 12 +/* The server application traffic label. */ +static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] = + "s ap traffic"; +#endif +/* Derive the server application traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Server Traffic Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + serverAppLabel, SERVER_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, SERVER_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} + +#ifdef TLS13_SUPPORTS_EXPORTERS +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the exporter master secret label. */ +#define EXPORTER_MASTER_LABEL_SZ 22 +/* The exporter master secret label. */ +static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] = + "exporter master secret"; +#else +/* The length of the exporter master secret label. */ +#define EXPORTER_MASTER_LABEL_SZ 10 +/* The exporter master secret label. */ +static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] = + "exp master"; +#endif +/* Derive the exporter secret. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveExporterSecret(WOLFSSL* ssl, byte* key) +{ + int ret; + WOLFSSL_MSG("Derive Exporter Secret"); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, EXPORTER_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; +} +#endif + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the resumption master secret label. */ +#define RESUME_MASTER_LABEL_SZ 24 +/* The resumption master secret label. */ +static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = + "resumption master secret"; +#else +/* The length of the resumption master secret label. */ +#define RESUME_MASTER_LABEL_SZ 10 +/* The resumption master secret label. */ +static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = + "res master"; +#endif +/* Derive the resumption secret. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Resumption Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + resumeMasterLabel, RESUME_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} +#endif + +/* Length of the finished label. */ +#define FINISHED_LABEL_SZ 8 +/* Finished label for generating finished key. */ +static const byte finishedLabel[FINISHED_LABEL_SZ+1] = "finished"; +/* Derive the finished secret. + * + * ssl The SSL/TLS object. + * key The key to use with the HMAC. + * secret The derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveFinishedSecret(WOLFSSL* ssl, byte* key, byte* secret) +{ + WOLFSSL_MSG("Derive Finished Secret"); + return DeriveKey(ssl, secret, -1, key, finishedLabel, FINISHED_LABEL_SZ, + ssl->specs.mac_algorithm, 0); +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* The length of the application traffic label. */ +#define APP_TRAFFIC_LABEL_SZ 26 +/* The application traffic label. */ +static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] = + "application traffic secret"; +#else +/* The length of the application traffic label. */ +#define APP_TRAFFIC_LABEL_SZ 11 +/* The application traffic label. */ +static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] = + "traffic upd"; +#endif +/* Update the traffic secret. + * + * ssl The SSL/TLS object. + * secret The previous secret and derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret) +{ + WOLFSSL_MSG("Derive New Application Traffic Secret"); + return DeriveKey(ssl, secret, -1, secret, + appTrafficLabel, APP_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 0); +} + +/* Derive the early secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveEarlySecret(WOLFSSL* ssl) +{ + WOLFSSL_MSG("Derive Early Secret"); +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->psk_key, ssl->arrays->psk_keySz, + ssl->specs.mac_algorithm); +#else + return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#endif +} + +#ifndef WOLFSSL_TLS13_DRAFT_18 +/* The length of the derived label. */ +#define DERIVED_LABEL_SZ 7 +/* The derived label. */ +static const byte derivedLabel[DERIVED_LABEL_SZ + 1] = + "derived"; +#endif +/* Derive the handshake secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveHandshakeSecret(WOLFSSL* ssl) +{ +#ifdef WOLFSSL_TLS13_DRAFT_18 + WOLFSSL_MSG("Derive Handshake Secret"); + return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, + ssl->arrays->secret, ssl->specs.hash_size, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + ssl->specs.mac_algorithm); +#else + byte key[WC_MAX_DIGEST_SIZE]; + int ret; + + WOLFSSL_MSG("Derive Handshake Secret"); + + ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + derivedLabel, DERIVED_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); + if (ret != 0) + return ret; + + return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, + key, ssl->specs.hash_size, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + ssl->specs.mac_algorithm); +#endif +} + +/* Derive the master secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveMasterSecret(WOLFSSL* ssl) +{ +#ifdef WOLFSSL_TLS13_DRAFT_18 + WOLFSSL_MSG("Derive Master Secret"); + return Tls13_HKDF_Extract(ssl->arrays->masterSecret, + ssl->arrays->preMasterSecret, ssl->specs.hash_size, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#else + byte key[WC_MAX_DIGEST_SIZE]; + int ret; + + WOLFSSL_MSG("Derive Master Secret"); + + ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->preMasterSecret, + derivedLabel, DERIVED_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); + if (ret != 0) + return ret; + + return Tls13_HKDF_Extract(ssl->arrays->masterSecret, + key, ssl->specs.hash_size, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#endif +} + +#ifndef WOLFSSL_TLS13_DRAFT_18 +#if defined(HAVE_SESSION_TICKET) +/* Length of the resumption label. */ +#define RESUMPTION_LABEL_SZ 10 +/* Resumption label for generating PSK associated with the ticket. */ +static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption"; +/* Derive the PSK associated with the ticket. + * + * ssl The SSL/TLS object. + * nonce The nonce to derive with. + * nonceLen The length of the nonce to derive with. + * secret The derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, + byte* secret) +{ + int digestAlg; + /* Only one protocol version defined at this time. */ + const byte* protocol = tls13ProtocolLabel; + word32 protocolLen = TLS13_PROTOCOL_LABEL_SZ; + + WOLFSSL_MSG("Derive Resumption PSK"); + + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + digestAlg = WC_SHA256; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + digestAlg = WC_SHA384; + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + digestAlg = WC_SHA512; + break; + #endif + + default: + return BAD_FUNC_ARG; + } + + return HKDF_Expand_Label(secret, ssl->specs.hash_size, + ssl->session.masterSecret, ssl->specs.hash_size, + protocol, protocolLen, resumptionLabel, + RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg); +} +#endif /* HAVE_SESSION_TICKET */ +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + + +/* Calculate the HMAC of message data to this point. + * + * ssl The SSL/TLS object. + * key The HMAC key. + * hash The hash result - verify data. + * returns length of verify data generated. + */ +static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash, + word32* pHashSz) +{ + Hmac verifyHmac; + int hashType = WC_SHA256; + int hashSz = WC_SHA256_DIGEST_SIZE; + int ret = BAD_FUNC_ARG; + + /* Get the hash of the previous handshake messages. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + hashType = WC_SHA256; + hashSz = WC_SHA256_DIGEST_SIZE; + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + break; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hashType = WC_SHA384; + hashSz = WC_SHA384_DIGEST_SIZE; + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hashType = WC_SHA512; + hashSz = WC_SHA512_DIGEST_SIZE; + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + break; + #endif /* WOLFSSL_TLS13_SHA512 */ + } + if (ret != 0) + return ret; + + /* Calculate the verify data. */ + ret = wc_HmacInit(&verifyHmac, ssl->heap, ssl->devId); + if (ret == 0) { + ret = wc_HmacSetKey(&verifyHmac, hashType, key, ssl->specs.hash_size); + if (ret == 0) + ret = wc_HmacUpdate(&verifyHmac, hash, hashSz); + if (ret == 0) + ret = wc_HmacFinal(&verifyHmac, hash); + wc_HmacFree(&verifyHmac); + } + + if (pHashSz) + *pHashSz = hashSz; + + return ret; +} + +/* The length of the label to use when deriving keys. */ +#define WRITE_KEY_LABEL_SZ 3 +/* The length of the label to use when deriving IVs. */ +#define WRITE_IV_LABEL_SZ 2 +/* The label to use when deriving keys. */ +static const byte writeKeyLabel[WRITE_KEY_LABEL_SZ+1] = "key"; +/* The label to use when deriving IVs. */ +static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; + +/* Derive the keys and IVs for TLS v1.3. + * + * ssl The SSL/TLS object. + * sercret early_data_key when deriving the key and IV for encrypting early + * data application data and end_of_early_data messages. + * handshake_key when deriving keys and IVs for encrypting handshake + * messages. + * traffic_key when deriving first keys and IVs for encrypting + * traffic messages. + * update_traffic_key when deriving next keys and IVs for encrypting + * traffic messages. + * side ENCRYPT_SIDE_ONLY when only encryption secret needs to be derived. + * DECRYPT_SIDE_ONLY when only decryption secret needs to be derived. + * ENCRYPT_AND_DECRYPT_SIDE when both secret needs to be derived. + * store 1 indicates to derive the keys and IVs from derived secret and + * store ready for provisioning. + * returns 0 on success, otherwise failure. + */ +static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) +{ + int ret = BAD_FUNC_ARG; /* Assume failure */ + int i = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* key_dig; +#else + byte key_dig[MAX_PRF_DIG]; +#endif + int provision; + +#ifdef WOLFSSL_SMALL_STACK + key_dig = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST); + if (key_dig == NULL) + return MEMORY_E; +#endif + + if (side == ENCRYPT_AND_DECRYPT_SIDE) { + provision = PROVISION_CLIENT_SERVER; + } + else { + provision = ((ssl->options.side != WOLFSSL_CLIENT_END) ^ + (side == ENCRYPT_SIDE_ONLY)) ? PROVISION_CLIENT : + PROVISION_SERVER; + } + + /* Derive the appropriate secret to use in the HKDF. */ + switch (secret) { +#ifdef WOLFSSL_EARLY_DATA + case early_data_key: + ret = DeriveEarlyTrafficSecret(ssl, ssl->clientSecret); + if (ret != 0) + goto end; + break; +#endif + + case handshake_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveClientHandshakeSecret(ssl, + ssl->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveServerHandshakeSecret(ssl, + ssl->serverSecret); + if (ret != 0) + goto end; + } + break; + + case traffic_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveClientTrafficSecret(ssl, ssl->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveServerTrafficSecret(ssl, ssl->serverSecret); + if (ret != 0) + goto end; + } + break; + + case update_traffic_key: + if (provision & PROVISION_CLIENT) { + ret = DeriveTrafficSecret(ssl, ssl->clientSecret); + if (ret != 0) + goto end; + } + if (provision & PROVISION_SERVER) { + ret = DeriveTrafficSecret(ssl, ssl->serverSecret); + if (ret != 0) + goto end; + } + break; + } + + if (!store) + goto end; + + /* Key data = client key | server key | client IV | server IV */ + + if (provision & PROVISION_CLIENT) { + /* Derive the client key. */ + WOLFSSL_MSG("Derive Client Key"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->clientSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + } + + if (provision & PROVISION_SERVER) { + /* Derive the server key. */ + WOLFSSL_MSG("Derive Server Key"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, + ssl->serverSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + } + + if (provision & PROVISION_CLIENT) { + /* Derive the client IV. */ + WOLFSSL_MSG("Derive Client IV"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->clientSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.iv_size; + } + + if (provision & PROVISION_SERVER) { + /* Derive the server IV. */ + WOLFSSL_MSG("Derive Server IV"); + ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, + ssl->serverSecret, writeIVLabel, + WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + } + + /* Store keys and IVs but don't activate them. */ + ret = StoreKeys(ssl, key_dig, provision); + +end: +#ifdef WOLFSSL_SMALL_STACK + XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); +#endif + + return ret; +} + +#ifdef HAVE_SESSION_TICKET +#if defined(USER_TICKS) +#if 0 + word32 TimeNowInMilliseconds(void) + { + /* + write your own clock tick function if don't want gettimeofday() + needs millisecond accuracy but doesn't have to correlated to EPOCH + */ + } +#endif + +#elif defined(TIME_OVERRIDES) + #ifndef HAVE_TIME_T_TYPE + typedef long time_t; + #endif + extern time_t XTIME(time_t * timer); + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) XTIME(0) * 1000; + } + +#elif defined(XTIME_MS) + word32 TimeNowInMilliseconds(void) + { + return (word32)XTIME_MS(0); + } + +#elif defined(USE_WINDOWS_API) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + static int init = 0; + static LARGE_INTEGER freq; + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (word32)(count.QuadPart / (freq.QuadPart / 1000)); + } + +#elif defined(HAVE_RTP_SYS) + #include "rtptime.h" + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)rtp_get_system_sec() * 1000; + } +#elif defined(WOLFSSL_DEOS) + word32 TimeNowInMilliseconds(void) + { + const uint32_t systemTickTimeInHz = 1000000 / systemTickInMicroseconds(); + uint32_t *systemTickPtr = systemTickPointer(); + + return (word32) (*systemTickPtr/systemTickTimeInHz) * 1000; + } +#elif defined(MICRIUM) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + OS_TICK ticks = 0; + OS_ERR err; + + ticks = OSTimeGet(&err); + + return (word32) (ticks / OSCfg_TickRate_Hz) * 1000; + } +#elif defined(MICROCHIP_TCPIP_V5) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) (TickGet() / (TICKS_PER_SECOND / 1000)); + } +#elif defined(MICROCHIP_TCPIP) + #if defined(MICROCHIP_MPLAB_HARMONY) + #include + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(SYS_TMR_TickCountGet() / + (SYS_TMR_TickCounterFrequencyGet() / 1000)); + } + #else + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(SYS_TICK_Get() / (SYS_TICK_TicksPerSecondGet() / 1000)); + } + + #endif + +#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + TIME_STRUCT mqxTime; + + _time_get_elapsed(&mqxTime); + + return (word32) mqxTime.SECONDS * 1000; + } +#elif defined(FREESCALE_FREE_RTOS) || defined(FREESCALE_KSDK_FREERTOS) + #include "include/task.h" + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (unsigned int)(((float)xTaskGetTickCount()) / + (configTICK_RATE_HZ / 1000)); + } +#elif defined(FREESCALE_KSDK_BM) + #include "lwip/sys.h" /* lwIP */ + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return sys_now(); + } +#elif defined(WOLFSSL_TIRTOS) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) Seconds_get() * 1000; + } +#elif defined(WOLFSSL_UTASKER) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(uTaskerSystemTick / (TICK_RESOLUTION / 1000)); + } +#else + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + struct timeval now; + + if (gettimeofday(&now, 0) < 0) + return GETTIME_ERROR; + /* Convert to milliseconds number. */ + return (word32)(now.tv_sec * 1000 + now.tv_usec / 1000); + } +#endif +#endif /* HAVE_SESSION_TICKET || !NO_PSK */ + + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) || \ + !defined(NO_PSK)) +/* Add input to all handshake hashes. + * + * ssl The SSL/TLS object. + * input The data to hash. + * sz The size of the data to hash. + * returns 0 on success, otherwise failure. + */ +static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) +{ + int ret = BAD_FUNC_ARG; + +#ifndef NO_SHA256 + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, input, sz); + if (ret != 0) + return ret; +#endif +#ifdef WOLFSSL_SHA384 + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, input, sz); + if (ret != 0) + return ret; +#endif +#ifdef WOLFSSL_TLS13_SHA512 + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, input, sz); + if (ret != 0) + return ret; +#endif + + return ret; +} +#endif + +/* Extract the handshake header information. + * + * ssl The SSL/TLS object. + * input The buffer holding the message data. + * inOutIdx On entry, the index into the buffer of the handshake data. + * On exit, the start of the handshake data. + * type Type of handshake message. + * size The length of the handshake message data. + * totalSz The total size of data in the buffer. + * returns BUFFER_E if there is not enough input data and 0 on success. + */ +static int GetHandshakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + byte* type, word32* size, word32 totalSz) +{ + const byte* ptr = input + *inOutIdx; + (void)ssl; + + *inOutIdx += HANDSHAKE_HEADER_SZ; + if (*inOutIdx > totalSz) + return BUFFER_E; + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} + +/* Add record layer header to message. + * + * output The buffer to write the record layer header into. + * length The length of the record data. + * type The type of record message. + * ssl The SSL/TLS object. + */ +static void AddTls13RecordHeader(byte* output, word32 length, byte type, + WOLFSSL* ssl) +{ + RecordLayerHeader* rl; + + rl = (RecordLayerHeader*)output; + rl->type = type; + rl->pvMajor = ssl->version.major; +#ifdef WOLFSSL_TLS13_DRAFT_18 + rl->pvMinor = TLSv1_MINOR; +#else + /* NOTE: May be TLSv1_MINOR when sending first ClientHello. */ + rl->pvMinor = TLSv1_2_MINOR; +#endif + c16toa((word16)length, rl->length); +} + +/* Add handshake header to message. + * + * output The buffer to write the handshake header into. + * length The length of the handshake data. + * fragOffset The offset of the fragment data. (DTLS) + * fragLength The length of the fragment data. (DTLS) + * type The type of handshake message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13HandShakeHeader(byte* output, word32 length, + word32 fragOffset, word32 fragLength, + byte type, WOLFSSL* ssl) +{ + HandShakeHeader* hs; + (void)fragOffset; + (void)fragLength; + (void)ssl; + + /* handshake header */ + hs = (HandShakeHeader*)output; + hs->type = type; + c32to24(length, hs->length); +} + + +/* Add both record layer and handshake header to message. + * + * output The buffer to write the headers into. + * length The length of the handshake data. + * type The type of record layer message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13Headers(byte* output, word32 length, byte type, + WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + + AddTls13RecordHeader(output, length + lengthAdj, handshake, ssl); + AddTls13HandShakeHeader(output + outputAdj, length, 0, length, type, ssl); +} + + +#ifndef NO_CERTS +/* Add both record layer and fragment handshake header to message. + * + * output The buffer to write the headers into. + * fragOffset The offset of the fragment data. (DTLS) + * fragLength The length of the fragment data. (DTLS) + * length The length of the handshake data. + * type The type of record layer message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13FragHeaders(byte* output, word32 fragSz, word32 fragOffset, + word32 length, byte type, WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + (void)fragSz; + + AddTls13RecordHeader(output, fragSz + lengthAdj, handshake, ssl); + AddTls13HandShakeHeader(output + outputAdj, length, fragOffset, fragSz, + type, ssl); +} +#endif /* NO_CERTS */ + +/* Write the sequence number into the buffer. + * No DTLS v1.3 support. + * + * ssl The SSL/TLS object. + * verifyOrder Which set of sequence numbers to use. + * out The buffer to write into. + */ +static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) +{ + word32 seq[2] = {0, 0}; + + if (verifyOrder) { + seq[0] = ssl->keys.peer_sequence_number_hi; + seq[1] = ssl->keys.peer_sequence_number_lo++; + /* handle rollover */ + if (seq[1] > ssl->keys.peer_sequence_number_lo) + ssl->keys.peer_sequence_number_hi++; + } + else { + seq[0] = ssl->keys.sequence_number_hi; + seq[1] = ssl->keys.sequence_number_lo++; + /* handle rollover */ + if (seq[1] > ssl->keys.sequence_number_lo) + ssl->keys.sequence_number_hi++; + } + + c32toa(seq[0], out); + c32toa(seq[1], out + OPAQUE32_LEN); +} + +/* Build the nonce for TLS v1.3 encryption and decryption. + * + * ssl The SSL/TLS object. + * nonce The nonce data to use when encrypting or decrypting. + * iv The derived IV. + * order The side on which the message is to be or was sent. + */ +static WC_INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte* nonce, const byte* iv, + int order) +{ + int i; + + /* The nonce is the IV with the sequence XORed into the last bytes. */ + WriteSEQ(ssl, order, nonce + AEAD_NONCE_SZ - SEQ_SZ); + for (i = 0; i < AEAD_NONCE_SZ - SEQ_SZ; i++) + nonce[i] = iv[i]; + for (; i < AEAD_NONCE_SZ; i++) + nonce[i] ^= iv[i]; +} + +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) +/* Encrypt with ChaCha20 and create authenication tag with Poly1305. + * + * ssl The SSL/TLS object. + * output The buffer to write encrypted data and authentication tag into. + * May be the same pointer as input. + * input The data to encrypt. + * sz The number of bytes to encrypt. + * nonce The nonce to use with ChaCha20. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tag The authentication tag buffer. + * returns 0 on success, otherwise failure. + */ +static int ChaCha20Poly1305_Encrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, byte* nonce, + const byte* aad, word16 aadSz, byte* tag) +{ + int ret = 0; + byte poly[CHACHA20_256_KEY_SIZE]; + + /* Poly1305 key is 256 bits of zero encrypted with ChaCha20. */ + XMEMSET(poly, 0, sizeof(poly)); + + /* Set the nonce for ChaCha and get Poly1305 key. */ + ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0); + if (ret != 0) + return ret; + /* Create Poly1305 key using ChaCha20 keystream. */ + ret = wc_Chacha_Process(ssl->encrypt.chacha, poly, poly, sizeof(poly)); + if (ret != 0) + return ret; + ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 1); + if (ret != 0) + return ret; + /* Encrypt the plain text. */ + ret = wc_Chacha_Process(ssl->encrypt.chacha, output, input, sz); + if (ret != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + + /* Set key for Poly1305. */ + ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + if (ret != 0) + return ret; + /* Add authentication code of encrypted data to end. */ + ret = wc_Poly1305_MAC(ssl->auth.poly1305, (byte*)aad, aadSz, output, sz, + tag, POLY1305_AUTH_SZ); + + return ret; +} +#endif + +#ifdef HAVE_NULL_CIPHER +/* Create authenication tag and copy data over input. + * + * ssl The SSL/TLS object. + * output The buffer to copy data into. + * May be the same pointer as input. + * input The data. + * sz The number of bytes of data. + * nonce The nonce to use with authentication. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tag The authentication tag buffer. + * returns 0 on success, otherwise failure. + */ +static int Tls13IntegrityOnly_Encrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, + const byte* nonce, + const byte* aad, word16 aadSz, byte* tag) +{ + int ret; + + /* HMAC: nonce | aad | input */ + ret = wc_HmacUpdate(ssl->encrypt.hmac, nonce, HMAC_NONCE_SZ); + if (ret == 0) + ret = wc_HmacUpdate(ssl->encrypt.hmac, aad, aadSz); + if (ret == 0) + ret = wc_HmacUpdate(ssl->encrypt.hmac, input, sz); + if (ret == 0) + ret = wc_HmacFinal(ssl->encrypt.hmac, tag); + /* Copy the input to output if not the same buffer */ + if (ret == 0 && output != input) + XMEMCPY(output, input, sz); + + return ret; +} +#endif + +/* Encrypt data for TLS v1.3. + * + * ssl The SSL/TLS object. + * output The buffer to write encrypted data and authentication tag into. + * May be the same pointer as input. + * input The record header and data to encrypt. + * sz The number of bytes to encrypt. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto + * returns 0 on success, otherwise failure. + */ +static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, + word16 sz, const byte* aad, word16 aadSz, int asyncOkay) +{ + int ret = 0; + word16 dataSz = sz - ssl->specs.aead_mac_size; + word16 macSz = ssl->specs.aead_mac_size; + word32 nonceSz = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV* asyncDev = NULL; + word32 event_flags = WC_ASYNC_FLAG_CALL_AGAIN; +#endif + + WOLFSSL_ENTER("EncryptTls13"); + + (void)output; + (void)input; + (void)sz; + (void)dataSz; + (void)macSz; + (void)asyncOkay; + (void)nonceSz; + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ssl->error == WC_PENDING_E) { + ssl->error = 0; /* clear async */ + } +#endif + + switch (ssl->encrypt.state) { + case CIPHER_STATE_BEGIN: + { + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Data to encrypt"); + WOLFSSL_BUFFER(input, dataSz); +#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \ + !defined(WOLFSSL_TLS13_DRAFT_23) + WOLFSSL_MSG("Additional Authentication Data"); + WOLFSSL_BUFFER(aad, aadSz); +#endif + #endif + + #ifdef CIPHER_NONCE + if (ssl->encrypt.nonce == NULL) + ssl->encrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->encrypt.nonce == NULL) + return MEMORY_E; + + BuildTls13Nonce(ssl, ssl->encrypt.nonce, ssl->keys.aead_enc_imp_IV, + CUR_ORDER); + #endif + + /* Advance state and proceed */ + ssl->encrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.aes->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + + nonceSz = AESGCM_NONCE_SZ; + #if ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) + ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, + dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + #else + ret = wc_AesGcmSetExtIV(ssl->encrypt.aes, + ssl->encrypt.nonce, nonceSz); + if (ret == 0) { + ret = wc_AesGcmEncrypt_ex(ssl->encrypt.aes, output, + input, dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + } + #endif + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + asyncDev = &ssl->encrypt.aes->asyncDev; + ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags); + if (ret != 0) + break; + #endif + + nonceSz = AESCCM_NONCE_SZ; + #if ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) + ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, + dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + #else + ret = wc_AesCcmSetNonce(ssl->encrypt.aes, + ssl->encrypt.nonce, nonceSz); + if (ret == 0) { + ret = wc_AesCcmEncrypt_ex(ssl->encrypt.aes, output, + input, dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + } + #endif + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz, + ssl->encrypt.nonce, aad, aadSz, output + dataSz); + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + ret = Tls13IntegrityOnly_Encrypt(ssl, output, input, dataSz, + ssl->encrypt.nonce, aad, aadSz, output + dataSz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Encrypt programming error"); + return ENCRYPT_ERROR; + } + + /* Advance state */ + ssl->encrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + /* if async is not okay, then block */ + if (!asyncOkay) { + ret = wc_AsyncWait(ret, asyncDev, event_flags); + } + else { + /* If pending, then leave and return will resume below */ + return wolfSSL_AsyncPush(ssl, asyncDev); + } + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + #ifdef WOLFSSL_DEBUG_TLS + #ifdef CIPHER_NONCE + WOLFSSL_MSG("Nonce"); + WOLFSSL_BUFFER(ssl->encrypt.nonce, ssl->specs.iv_size); + #endif + WOLFSSL_MSG("Encrypted data"); + WOLFSSL_BUFFER(output, dataSz); + WOLFSSL_MSG("Authentication Tag"); + WOLFSSL_BUFFER(output + dataSz, macSz); + #endif + + #ifdef CIPHER_NONCE + ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); + #endif + + break; + } + } + + /* Reset state */ + ssl->encrypt.state = CIPHER_STATE_BEGIN; + + return ret; +} + +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) +/* Decrypt with ChaCha20 and check authenication tag with Poly1305. + * + * ssl The SSL/TLS object. + * output The buffer to write decrypted data into. + * May be the same pointer as input. + * input The data to decrypt. + * sz The number of bytes to decrypt. + * nonce The nonce to use with ChaCha20. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tagIn The authentication tag data from packet. + * returns 0 on success, otherwise failure. + */ +static int ChaCha20Poly1305_Decrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, byte* nonce, + const byte* aad, word16 aadSz, + const byte* tagIn) +{ + int ret; + byte tag[POLY1305_AUTH_SZ]; + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ + + /* Poly1305 key is 256 bits of zero encrypted with ChaCha20. */ + XMEMSET(poly, 0, sizeof(poly)); + + /* Set nonce and get Poly1305 key. */ + ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0); + if (ret != 0) + return ret; + /* Use ChaCha20 keystream to get Poly1305 key for tag. */ + ret = wc_Chacha_Process(ssl->decrypt.chacha, poly, poly, sizeof(poly)); + if (ret != 0) + return ret; + ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 1); + if (ret != 0) + return ret; + + /* Set key for Poly1305. */ + ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + if (ret != 0) + return ret; + /* Generate authentication tag for encrypted data. */ + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, (byte*)aad, aadSz, + (byte*)input, sz, tag, sizeof(tag))) != 0) { + return ret; + } + + /* Check tag sent along with packet. */ + if (ConstantCompare(tagIn, tag, POLY1305_AUTH_SZ) != 0) { + WOLFSSL_MSG("MAC did not match"); + return VERIFY_MAC_ERROR; + } + + /* If the tag was good decrypt message. */ + ret = wc_Chacha_Process(ssl->decrypt.chacha, output, input, sz); + + return ret; +} +#endif + +#ifdef HAVE_NULL_CIPHER +/* Check HMAC tag and copy over input. + * + * ssl The SSL/TLS object. + * output The buffer to copy data into. + * May be the same pointer as input. + * input The data. + * sz The number of bytes of data. + * nonce The nonce to use with authentication. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tagIn The authentication tag data from packet. + * returns 0 on success, otherwise failure. + */ +static int Tls13IntegrityOnly_Decrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, + const byte* nonce, + const byte* aad, word16 aadSz, + const byte* tagIn) +{ + int ret; + byte hmac[WC_MAX_DIGEST_SIZE]; + + /* HMAC: nonce | aad | input */ + ret = wc_HmacUpdate(ssl->decrypt.hmac, nonce, HMAC_NONCE_SZ); + if (ret == 0) + ret = wc_HmacUpdate(ssl->decrypt.hmac, aad, aadSz); + if (ret == 0) + ret = wc_HmacUpdate(ssl->decrypt.hmac, input, sz); + if (ret == 0) + ret = wc_HmacFinal(ssl->decrypt.hmac, hmac); + /* Check authentication tag matches */ + if (ret == 0 && ConstantCompare(tagIn, hmac, ssl->specs.hash_size) != 0) + ret = DECRYPT_ERROR; + /* Copy the input to output if not the same buffer */ + if (ret == 0 && output != input) + XMEMCPY(output, input, sz); + + return ret; +} +#endif + +/* Decrypt data for TLS v1.3. + * + * ssl The SSL/TLS object. + * output The buffer to write decrypted data into. + * May be the same pointer as input. + * input The data to decrypt and authentication tag. + * sz The length of the encrypted data plus authentication tag. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * returns 0 on success, otherwise failure. + */ +int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz, + const byte* aad, word16 aadSz) +{ + int ret = 0; + word16 dataSz = sz - ssl->specs.aead_mac_size; + word16 macSz = ssl->specs.aead_mac_size; + word32 nonceSz = 0; + + WOLFSSL_ENTER("DecryptTls13"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->decrypt.state); + if (ret != WC_NOT_PENDING_E) { + /* check for still pending */ + if (ret == WC_PENDING_E) + return ret; + + ssl->error = 0; /* clear async */ + + /* let failures through so CIPHER_STATE_END logic is run */ + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->decrypt.state = CIPHER_STATE_BEGIN; + } + + (void)output; + (void)input; + (void)sz; + (void)dataSz; + (void)macSz; + (void)nonceSz; + + switch (ssl->decrypt.state) { + case CIPHER_STATE_BEGIN: + { + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Data to decrypt"); + WOLFSSL_BUFFER(input, dataSz); +#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \ + !defined(WOLFSSL_TLS13_DRAFT_23) + WOLFSSL_MSG("Additional Authentication Data"); + WOLFSSL_BUFFER(aad, aadSz); +#endif + WOLFSSL_MSG("Authentication tag"); + WOLFSSL_BUFFER(input + dataSz, macSz); + #endif + + #ifdef CIPHER_NONCE + if (ssl->decrypt.nonce == NULL) + ssl->decrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES_BUFFER); + if (ssl->decrypt.nonce == NULL) + return MEMORY_E; + + BuildTls13Nonce(ssl, ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV, + PEER_ORDER); + #endif + + /* Advance state and proceed */ + ssl->decrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + + nonceSz = AESGCM_NONCE_SZ; + ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input, + dataSz, ssl->decrypt.nonce, nonceSz, + input + dataSz, macSz, aad, aadSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, + &ssl->decrypt.aes->asyncDev); + } + #endif + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + #ifdef WOLFSSL_ASYNC_CRYPT + /* initialize event */ + ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + + nonceSz = AESCCM_NONCE_SZ; + ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input, + dataSz, ssl->decrypt.nonce, nonceSz, + input + dataSz, macSz, aad, aadSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, + &ssl->decrypt.aes->asyncDev); + } + #endif + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz, + ssl->decrypt.nonce, aad, aadSz, input + dataSz); + break; + #endif + + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + ret = Tls13IntegrityOnly_Decrypt(ssl, output, input, dataSz, + ssl->decrypt.nonce, aad, aadSz, input + dataSz); + break; + #endif + default: + WOLFSSL_MSG("wolfSSL Decrypt programming error"); + return DECRYPT_ERROR; + } + + /* Advance state */ + ssl->decrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* If pending, leave now */ + if (ret == WC_PENDING_E) { + return ret; + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + #ifdef WOLFSSL_DEBUG_TLS + #ifdef CIPHER_NONCE + WOLFSSL_MSG("Nonce"); + WOLFSSL_BUFFER(ssl->decrypt.nonce, ssl->specs.iv_size); + #endif + WOLFSSL_MSG("Decrypted data"); + WOLFSSL_BUFFER(output, dataSz); + #endif + + #ifdef CIPHER_NONCE + ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); + #endif + + break; + } + } + +#ifndef WOLFSSL_EARLY_DATA + if (ret < 0) { + SendAlert(ssl, alert_fatal, bad_record_mac); + ret = VERIFY_MAC_ERROR; + } +#endif + + return ret; +} + +/* Persistable BuildTls13Message arguments */ +typedef struct BuildMsg13Args { + word32 sz; + word32 idx; + word32 headerSz; + word16 size; +} BuildMsg13Args; + +static void FreeBuildMsg13Args(WOLFSSL* ssl, void* pArgs) +{ + BuildMsg13Args* args = (BuildMsg13Args*)pArgs; + + (void)ssl; + (void)args; + + /* no allocations in BuildTls13Message */ +} + +/* Build SSL Message, encrypted. + * TLS v1.3 encryption is AEAD only. + * + * ssl The SSL/TLS object. + * output The buffer to write record message to. + * outSz Size of the buffer being written into. + * input The record data to encrypt (excluding record header). + * inSz The size of the record data. + * type The recorder header content type. + * hashOutput Whether to hash the unencrypted record data. + * sizeOnly Only want the size of the record message. + * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto + * returns the size of the encrypted record message or negative value on error. + */ +int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, + int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay) +{ + int ret = 0; + BuildMsg13Args* args; + BuildMsg13Args lcl_args; +#ifdef WOLFSSL_ASYNC_CRYPT + args = (BuildMsg13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#endif + + WOLFSSL_ENTER("BuildTls13Message"); + + ret = WC_NOT_PENDING_E; +#ifdef WOLFSSL_ASYNC_CRYPT + if (asyncOkay) { + ret = wolfSSL_AsyncPop(ssl, &ssl->options.buildMsgState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_buildmsg; + } + } + else +#endif + { + args = &lcl_args; + } + + /* Reset state */ + if (ret == WC_NOT_PENDING_E) { + ret = 0; + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + XMEMSET(args, 0, sizeof(BuildMsg13Args)); + + args->sz = RECORD_HEADER_SZ + inSz; + args->idx = RECORD_HEADER_SZ; + args->headerSz = RECORD_HEADER_SZ; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeBuildMsg13Args; + #endif + } + + switch (ssl->options.buildMsgState) { + case BUILD_MSG_BEGIN: + { + /* catch mistaken sizeOnly parameter */ + if (sizeOnly) { + if (output || input) { + WOLFSSL_MSG("BuildTls13Message with sizeOnly " + "doesn't need input or output"); + return BAD_FUNC_ARG; + } + } + else if (output == NULL || input == NULL) { + return BAD_FUNC_ARG; + } + + /* Record layer content type at the end of record data. */ + args->sz++; + /* Authentication data at the end. */ + args->sz += ssl->specs.aead_mac_size; + + if (sizeOnly) + return args->sz; + + if (args->sz > (word32)outSz) { + WOLFSSL_MSG("Oops, want to write past output buffer size"); + return BUFFER_E; + } + + /* Record data length. */ + args->size = (word16)(args->sz - args->headerSz); + /* Write/update the record header with the new size. + * Always have the content type as application data for encrypted + * messages in TLS v1.3. + */ + AddTls13RecordHeader(output, args->size, application_data, ssl); + + /* TLS v1.3 can do in place encryption. */ + if (input != output + args->idx) + XMEMCPY(output + args->idx, input, inSz); + args->idx += inSz; + + ssl->options.buildMsgState = BUILD_MSG_HASH; + } + FALL_THROUGH; + + case BUILD_MSG_HASH: + { + if (hashOutput) { + ret = HashOutput(ssl, output, args->headerSz + inSz, 0); + if (ret != 0) + goto exit_buildmsg; + } + + /* The real record content type goes at the end of the data. */ + output[args->idx++] = (byte)type; + + ssl->options.buildMsgState = BUILD_MSG_ENCRYPT; + } + FALL_THROUGH; + + case BUILD_MSG_ENCRYPT: + { + #ifdef ATOMIC_USER + if (ssl->ctx->MacEncryptCb) { + /* User Record Layer Callback handling */ + byte* mac = output + args->idx; + output += args->headerSz; + + ret = ssl->ctx->MacEncryptCb(ssl, mac, output, inSz, type, 0, + output, output, args->size, ssl->MacEncryptCtx); + } + else + #endif + { +#if defined(WOLFSSL_TLS13_DRAFT_18) || defined(WOLFSSL_TLS13_DRAFT_22) || \ + defined(WOLFSSL_TLS13_DRAFT_23) + output += args->headerSz; + ret = EncryptTls13(ssl, output, output, args->size, NULL, 0, + asyncOkay); +#else + const byte* aad = output; + output += args->headerSz; + ret = EncryptTls13(ssl, output, output, args->size, aad, + RECORD_HEADER_SZ, asyncOkay); +#endif + } + break; + } + } + +exit_buildmsg: + + WOLFSSL_LEAVE("BuildTls13Message", ret); + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + return ret; + } +#endif + + /* make sure build message state is reset */ + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + + /* return sz on success */ + if (ret == 0) + ret = args->sz; + + /* Final cleanup */ + FreeBuildMsg13Args(ssl, args); +#ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = NULL; +#endif + + return ret; +} + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Find the cipher suite in the suites set in the SSL. + * + * ssl SSL/TLS object. + * suite Cipher suite to look for. + * returns 1 when suite is found in SSL/TLS object's list and 0 otherwise. + */ +static int FindSuiteSSL(WOLFSSL* ssl, byte* suite) +{ + word16 i; + + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + if (ssl->suites->suites[i+0] == suite[0] && + ssl->suites->suites[i+1] == suite[1]) { + return 1; + } + } + + return 0; +} +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 +#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER) +/* Create Cookie extension using the hash of the first ClientHello. + * + * ssl SSL/TLS object. + * hash The hash data. + * hashSz The size of the hash data in bytes. + * returns 0 on success, otherwise failure. + */ +static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz) +{ + int ret; + byte mac[WC_MAX_DIGEST_SIZE] = {0}; + Hmac cookieHmac; + byte cookieType = 0; + byte macSz = 0; + +#if !defined(NO_SHA) && defined(NO_SHA256) + cookieType = SHA; + macSz = WC_SHA_DIGEST_SIZE; +#endif /* NO_SHA */ +#ifndef NO_SHA256 + cookieType = WC_SHA256; + macSz = WC_SHA256_DIGEST_SIZE; +#endif /* NO_SHA256 */ + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); + + ret = wc_HmacSetKey(&cookieHmac, cookieType, + ssl->buffers.tls13CookieSecret.buffer, + ssl->buffers.tls13CookieSecret.length); + if (ret != 0) + return ret; + if ((ret = wc_HmacUpdate(&cookieHmac, hash, hashSz)) != 0) + return ret; + if ((ret = wc_HmacFinal(&cookieHmac, mac)) != 0) + return ret; + + /* The cookie data is the hash and the integrity check. */ + return TLSX_Cookie_Use(ssl, hash, hashSz, mac, macSz, 1); +} +#endif + +/* Restart the handshake hash with a hash of the previous messages. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int RestartHandshakeHash(WOLFSSL* ssl) +{ + int ret; + Hashes hashes; + byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte* hash = NULL; + byte hashSz = 0; + + ret = BuildCertHashes(ssl, &hashes); + if (ret != 0) + return ret; + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + hash = hashes.sha256; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = hashes.sha384; + break; + #endif + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hash = hashes.sha512; + break; + #endif + } + hashSz = ssl->specs.hash_size; + + /* check hash */ + if (hash == NULL && hashSz > 0) + return BAD_FUNC_ARG; + + AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); + + WOLFSSL_MSG("Restart Hash"); + WOLFSSL_BUFFER(hash, hashSz); + +#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER) + if (ssl->options.sendCookie) { + byte cookie[OPAQUE8_LEN + WC_MAX_DIGEST_SIZE + OPAQUE16_LEN * 2]; + TLSX* ext; + word32 idx = 0; + + /* Cookie Data = Hash Len | Hash | CS | KeyShare Group */ + cookie[idx++] = hashSz; + if (hash) + XMEMCPY(cookie + idx, hash, hashSz); + idx += hashSz; + cookie[idx++] = ssl->options.cipherSuite0; + cookie[idx++] = ssl->options.cipherSuite; + if ((ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE)) != NULL) { + KeyShareEntry* kse = (KeyShareEntry*)ext->data; + c16toa(kse->group, cookie + idx); + idx += OPAQUE16_LEN; + } + return CreateCookie(ssl, cookie, idx); + } +#endif + + ret = InitHandshakeHashes(ssl); + if (ret != 0) + return ret; + ret = HashOutputRaw(ssl, header, sizeof(header)); + if (ret != 0) + return ret; + return HashOutputRaw(ssl, hash, hashSz); +} + +/* The value in the random field of a ServerHello to indicate + * HelloRetryRequest. + */ +static byte helloRetryRequestRandom[] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C +}; +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + +#ifndef NO_WOLFSSL_CLIENT +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Setup pre-shared key based on the details in the extension data. + * + * ssl SSL/TLS object. + * psk Pre-shared key extension data. + * returns 0 on success, PSK_KEY_ERROR when the client PSK callback fails and + * other negative value on failure. + */ +static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) +{ + int ret; + byte suite[2]; + + if (psk == NULL) + return BAD_FUNC_ARG; + + suite[0] = psk->cipherSuite0; + suite[1] = psk->cipherSuite; + if (!FindSuiteSSL(ssl, suite)) + return PSK_KEY_ERROR; + + ssl->options.cipherSuite0 = psk->cipherSuite0; + ssl->options.cipherSuite = psk->cipherSuite; + if ((ret = SetCipherSpecs(ssl)) != 0) + return ret; + +#ifdef HAVE_SESSION_TICKET + if (psk->resumption) { + #ifdef WOLFSSL_EARLY_DATA + if (ssl->session.maxEarlyDataSz == 0) + ssl->earlyData = no_early_data; + #endif + /* Resumption PSK is master secret. */ + ssl->arrays->psk_keySz = ssl->specs.hash_size; +#ifdef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->arrays->psk_keySz); +#else + if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, + ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { + return ret; + } +#endif + } +#endif +#ifndef NO_PSK + if (!psk->resumption) { + #ifndef WOLFSSL_PSK_ONE_ID + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE, cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + + /* Get the pre-shared key. */ + if (ssl->options.client_psk_tls13_cb != NULL) { + ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb(ssl, + (char *)psk->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, + &cipherName); + if (GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) != 0) { + return PSK_KEY_ERROR; + } + } + else { + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + (char *)psk->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + } + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + return PSK_KEY_ERROR; + } + + if (psk->cipherSuite0 != cipherSuite0 || + psk->cipherSuite != cipherSuite) { + return PSK_KEY_ERROR; + } + #else + /* PSK information loaded during setting of default TLS extensions. */ + #endif + } +#endif + + if (ssl->options.noPskDheKe) + ssl->arrays->preMasterSz = 0; + + /* Derive the early secret using the PSK. */ + return DeriveEarlySecret(ssl); +} + +/* Derive and write the binders into the ClientHello in space left when + * writing the Pre-Shared Key extension. + * + * ssl The SSL/TLS object. + * output The buffer containing the ClientHello. + * idx The index at the end of the completed ClientHello. + * returns 0 on success and otherwise failure. + */ +static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) +{ + int ret; + TLSX* ext; + PreSharedKey* current; + byte binderKey[WC_MAX_DIGEST_SIZE]; + word16 len; + + WOLFSSL_ENTER("WritePSKBinders"); + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) + return SANITY_MSG_E; + + /* Get the size of the binders to determine where to write binders. */ + ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, + client_hello, &len); + if (ret < 0) + return ret; + idx -= len; + + /* Hash truncated ClientHello - up to binders. */ + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + current = (PreSharedKey*)ext->data; + /* Calculate the binder for each identity based on previous handshake data. + */ + while (current != NULL) { + if ((ret = SetupPskKey(ssl, current)) != 0) + return ret; + + #ifdef HAVE_SESSION_TICKET + if (current->resumption) + ret = DeriveBinderKeyResume(ssl, binderKey); + #endif + #ifndef NO_PSK + if (!current->resumption) + ret = DeriveBinderKey(ssl, binderKey); + #endif + if (ret != 0) + return ret; + + /* Derive the Finished message secret. */ + ret = DeriveFinishedSecret(ssl, binderKey, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + /* Build the HMAC of the handshake message data = binder. */ + ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret, + current->binder, ¤t->binderLen); + if (ret != 0) + return ret; + + current = current->next; + } + + /* Data entered into extension, now write to message. */ + ret = TLSX_PreSharedKey_WriteBinders((PreSharedKey*)ext->data, output + idx, + client_hello, &len); + if (ret < 0) + return ret; + + /* Hash binders to complete the hash of the ClientHello. */ + ret = HashOutputRaw(ssl, output + idx, len); + if (ret < 0) + return ret; + + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 0) + return ret; + + /* Derive early data encryption key. */ + ret = DeriveTls13Keys(ssl, early_data_key, ENCRYPT_SIDE_ONLY, 1); + if (ret != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + } + #endif + + WOLFSSL_LEAVE("WritePSKBinders", ret); + + return ret; +} +#endif + +/* handle generation of TLS 1.3 client_hello (1) */ +/* Send a ClientHello message to the server. + * Include the information required to start a handshake with servers using + * protocol versions less than TLS v1.3. + * Only a client will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +int SendTls13ClientHello(WOLFSSL* ssl) +{ + byte* output; + word16 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int ret; + + WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND); + WOLFSSL_ENTER("SendTls13ClientHello"); + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.resuming && + (ssl->session.version.major != ssl->version.major || + ssl->session.version.minor != ssl->version.minor)) { + #ifndef WOLFSSL_NO_TLS12 + if (ssl->session.version.major == ssl->version.major && + ssl->session.version.minor < ssl->version.minor) { + /* Cannot resume with a different protocol version. */ + ssl->options.resuming = 0; + ssl->version.major = ssl->session.version.major; + ssl->version.minor = ssl->session.version.minor; + return SendClientHello(ssl); + } + else + #endif + return VERSION_ERROR; + } +#endif + + if (ssl->suites == NULL) { + WOLFSSL_MSG("Bad suites pointer in SendTls13ClientHello"); + return SUITES_ERROR; + } + + /* Version | Random | Session Id | Cipher Suites | Compression */ + length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz + + SUITE_LEN + COMP_LEN + ENUM_LEN; +#ifndef WOLFSSL_TLS13_DRAFT_18 + #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + length += ID_LEN; + #else + if (ssl->session.sessionIDSz > 0) + length += ssl->session.sessionIDSz; + #endif +#endif + + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) + return ret; +#ifdef WOLFSSL_EARLY_DATA + #ifndef NO_PSK + if (!ssl->options.resuming && + ssl->options.client_psk_tls13_cb == NULL && + ssl->options.client_psk_cb == NULL) + #else + if (!ssl->options.resuming) + #endif + ssl->earlyData = no_early_data; + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) + ssl->earlyData = no_early_data; + if (ssl->earlyData == no_early_data) + TLSX_Remove(&ssl->extensions, TLSX_EARLY_DATA, ssl->heap); + if (ssl->earlyData != no_early_data && + (ret = TLSX_EarlyData_Use(ssl, 0)) < 0) { + return ret; + } +#endif + /* Include length of TLS extensions. */ + ret = TLSX_GetRequestSize(ssl, client_hello, &length); + if (ret != 0) + return ret; + + /* Total message size. */ + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, client_hello, ssl); + + /* Protocol version - negotiation now in extension: supported_versions. */ + output[idx++] = SSLv3_MAJOR; + output[idx++] = TLSv1_2_MINOR; + /* Keep for downgrade. */ + ssl->chVersion = ssl->version; + + /* Client Random */ + if (ssl->options.connectState == CONNECT_BEGIN) { + ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + if (ret != 0) + return ret; + + /* Store random for possible second ClientHello. */ + XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN); + } + else + XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); + idx += RAN_LEN; + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* TLS v1.3 does not use session id - 0 length. */ + output[idx++] = 0; +#else + if (ssl->session.sessionIDSz > 0) { + /* Session resumption for old versions of protocol. */ + output[idx++] = ID_LEN; + XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); + idx += ID_LEN; + } + else { + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + output[idx++] = ID_LEN; + XMEMCPY(output + idx, ssl->arrays->clientRandom, ID_LEN); + idx += ID_LEN; + #else + /* TLS v1.3 does not use session id - 0 length. */ + output[idx++] = 0; + #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ + } +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + + /* Cipher suites */ + c16toa(ssl->suites->suiteSz, output + idx); + idx += OPAQUE16_LEN; + XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); + idx += ssl->suites->suiteSz; + + /* Compression not supported in TLS v1.3. */ + output[idx++] = COMP_LEN; + output[idx++] = NO_COMPRESSION; + + /* Write out extensions for a request. */ + length = 0; + ret = TLSX_WriteRequest(ssl, output + idx, client_hello, &length); + if (ret != 0) + return ret; + idx += length; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Resumption has a specific set of extensions and binder is calculated + * for each identity. + */ + if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY)) + ret = WritePSKBinders(ssl, output, idx); + else +#endif + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "ClientHello", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } +#endif + + ssl->buffers.outputBuffer.length += sendSz; + +#ifdef WOLFSSL_EARLY_DATA_GROUP + if (ssl->earlyData == no_early_data) +#endif + ret = SendBuffered(ssl); + + + WOLFSSL_LEAVE("SendTls13ClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND); + + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* handle rocessing of TLS 1.3 hello_retry_request (6) */ +/* Parse and handle a HelloRetryRequest message. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * HelloRetryRequest. + * On exit, the index of byte after the HelloRetryRequest message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret; + word32 begin = *inOutIdx; + word32 i = begin; + word16 totalExtSz; + ProtocolVersion pv; + + WOLFSSL_ENTER("DoTls13HelloRetryRequest"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "HelloRetryRequest"); + if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo); +#endif + + /* Version info and length field of extension data. */ + if (totalSz < i - begin + OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_ERROR; + + /* Protocol version. */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + + /* Length of extension data. */ + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if (totalExtSz == 0) { + WOLFSSL_MSG("HelloRetryRequest must contain extensions"); + return MISSING_HANDSHAKE_DATA; + } + + /* Extension data. */ + if (i - begin + totalExtSz > totalSz) + return BUFFER_ERROR; + if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, + hello_retry_request, NULL)) != 0) + return ret; + /* The KeyShare extension parsing fails when not valid. */ + + /* Move index to byte after message. */ + *inOutIdx = i + totalExtSz; + + ssl->options.tls1_3 = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + + WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret); + + return ret; +} +#endif + + +/* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */ +/* Handle the ServerHello message from the server. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of ServerHello. + * On exit, the index of byte after the ServerHello message. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz, byte* extMsgType) +{ + ProtocolVersion pv; + word32 i = *inOutIdx; + word32 begin = i; + int ret; +#ifndef WOLFSSL_TLS13_DRAFT_18 + byte sessIdSz; + const byte* sessId; + byte b; + int foundVersion; +#endif + word16 totalExtSz; +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TLSX* ext; + PreSharedKey* psk = NULL; +#endif + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_DO); + WOLFSSL_ENTER("DoTls13ServerHello"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ServerHello"); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + + /* Protocol version length check. */ + if (OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + /* Protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; +#ifdef WOLFSSL_TLS13_DRAFT_18 + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + if (!IsAtLeastTLSv1_3(pv) && pv.major != TLS_DRAFT_MAJOR) { +#ifndef WOLFSSL_NO_TLS12 + if (ssl->options.downgrade) { + ssl->version = pv; + return DoServerHello(ssl, input, inOutIdx, helloSz); + } +#endif + + WOLFSSL_MSG("Client using higher version, fatal error"); + return VERSION_ERROR; + } +#else +#ifndef WOLFSSL_NO_TLS12 + if (pv.major == ssl->version.major && pv.minor < TLSv1_2_MINOR && + ssl->options.downgrade) { + /* Force client hello version 1.2 to work for static RSA. */ + ssl->chVersion.minor = TLSv1_2_MINOR; + ssl->version.minor = TLSv1_2_MINOR; + return DoServerHello(ssl, input, inOutIdx, helloSz); + } +#endif + if (pv.major != ssl->version.major || pv.minor != TLSv1_2_MINOR) + return VERSION_ERROR; +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Random length check */ + if ((i - begin) + RAN_LEN > helloSz) + return BUFFER_ERROR; +#else + /* Random and session id length check */ + if ((i - begin) + RAN_LEN + ENUM_LEN > helloSz) + return BUFFER_ERROR; + + if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0) + *extMsgType = hello_retry_request; +#endif + + /* Server random - keep for debugging. */ + XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); + i += RAN_LEN; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Session id */ + sessIdSz = input[i++]; + if ((i - begin) + sessIdSz > helloSz) + return BUFFER_ERROR; + sessId = input + i; + i += sessIdSz; +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + ssl->options.haveSessionId = 1; + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Ciphersuite check */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; +#else + /* Ciphersuite and compression check */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; +#endif + + /* Set the cipher suite from the message. */ + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Compression */ + b = input[i++]; + if (b != 0) { + WOLFSSL_MSG("Must be no compression types in list"); + return INVALID_PARAMETER; + } +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 + if ((i - begin) + OPAQUE16_LEN > helloSz) { + if (!ssl->options.downgrade) + return BUFFER_ERROR; +#ifndef WOLFSSL_NO_TLS12 + ssl->version.minor = TLSv1_2_MINOR; +#endif + ssl->options.haveEMS = 0; + } + if ((i - begin) < helloSz) +#endif + { + /* Get extension length and length check. */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Need to negotiate version first. */ + if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz, + *extMsgType, &foundVersion))) { + return ret; + } + if (!foundVersion) { + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Server trying to downgrade to version less than " + "TLS v1.3"); + return VERSION_ERROR; + } + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + ssl->version.minor = pv.minor; + } +#endif + + /* Parse and handle extensions. */ + ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, *extMsgType, + NULL); + if (ret != 0) + return ret; + + i += totalExtSz; + } + *inOutIdx = i; + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + +#ifdef HAVE_SECRET_CALLBACK + if (ssl->sessionSecretCb != NULL) { + int secretSz = SECRET_LEN; + ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, + &secretSz, ssl->sessionSecretCtx); + if (ret != 0 || secretSz != SECRET_LEN) { + return SESSION_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Version only negotiated in extensions for TLS v1.3. + * Only now do we know how to deal with session id. + */ + if (!IsAtLeastTLSv1_3(ssl->version)) { +#ifndef WOLFSSL_NO_TLS12 + ssl->arrays->sessionIDSz = sessIdSz; + + if (ssl->arrays->sessionIDSz > ID_LEN) { + WOLFSSL_MSG("Invalid session ID size"); + ssl->arrays->sessionIDSz = 0; + return BUFFER_ERROR; + } + else if (ssl->arrays->sessionIDSz) { + XMEMCPY(ssl->arrays->sessionID, sessId, ssl->arrays->sessionIDSz); + ssl->options.haveSessionId = 1; + } + + /* Force client hello version 1.2 to work for static RSA. */ + ssl->chVersion.minor = TLSv1_2_MINOR; + /* Complete TLS v1.2 processing of ServerHello. */ + ret = CompleteServerHello(ssl); +#else + WOLFSSL_MSG("Client using higher version, fatal error"); + ret = VERSION_ERROR; +#endif + + WOLFSSL_LEAVE("DoTls13ServerHello", ret); + + return ret; + } + + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + if (sessIdSz == 0) + return INVALID_PARAMETER; + if (ssl->session.sessionIDSz != 0) { + if (ssl->session.sessionIDSz != sessIdSz || + XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0) { + return INVALID_PARAMETER; + } + } + else if (XMEMCMP(ssl->arrays->clientRandom, sessId, sessIdSz) != 0) + return INVALID_PARAMETER; + #else + if (sessIdSz != ssl->session.sessionIDSz || (sessIdSz > 0 && + XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0)) { + WOLFSSL_MSG("Server sent different session id"); + return INVALID_PARAMETER; + } + #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ +#endif + + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; +#ifdef HAVE_NULL_CIPHER + if (ssl->options.cipherSuite0 == ECC_BYTE && + (ssl->options.cipherSuite == TLS_SHA256_SHA256 || + ssl->options.cipherSuite == TLS_SHA384_SHA384)) { + ; + } + else +#endif + /* Check that the negotiated ciphersuite matches protocol version. */ + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + WOLFSSL_MSG("Server sent non-TLS13 cipher suite in TLS 1.3 packet"); + return INVALID_PARAMETER; + } + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (*extMsgType == server_hello) +#endif + { + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext != NULL) + psk = (PreSharedKey*)ext->data; + while (psk != NULL && !psk->chosen) + psk = psk->next; + if (psk == NULL) { + ssl->options.resuming = 0; + ssl->arrays->psk_keySz = 0; + XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN); + } + else if ((ret = SetupPskKey(ssl, psk)) != 0) + return ret; + } +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + ssl->keys.encryptionOn = 1; +#else + if (*extMsgType == server_hello) { + ssl->keys.encryptionOn = 1; + ssl->options.serverState = SERVER_HELLO_COMPLETE; + } + else { + ssl->options.tls1_3 = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + + ret = RestartHandshakeHash(ssl); + } +#endif + + WOLFSSL_LEAVE("DoTls13ServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_DO); + + return ret; +} + +/* handle processing TLS 1.3 encrypted_extensions (8) */ +/* Parse and handle an EncryptedExtensions message. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * EncryptedExtensions. + * On exit, the index of byte after the EncryptedExtensions + * message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret; + word32 begin = *inOutIdx; + word32 i = begin; + word16 totalExtSz; + + WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_DO); + WOLFSSL_ENTER("DoTls13EncryptedExtensions"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "EncryptedExtensions"); + if (ssl->toInfoOn) AddLateName("EncryptedExtensions", &ssl->timeoutInfo); +#endif + + /* Length field of extension data. */ + if (totalSz < i - begin + OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + /* Extension data. */ + if (i - begin + totalExtSz > totalSz) + return BUFFER_ERROR; + if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, + encrypted_extensions, NULL))) + return ret; + + /* Move index to byte after message. */ + *inOutIdx = i + totalExtSz; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + TLSX* ext = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (ext == NULL || !ext->val) + ssl->earlyData = no_early_data; + } +#endif + +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData == no_early_data) { + ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY); + if (ret != 0) + return ret; + } +#endif + + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + + WOLFSSL_LEAVE("DoTls13EncryptedExtensions", ret); + WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_DO); + + return ret; +} + +/* handle processing TLS v1.3 certificate_request (13) */ +/* Handle a TLS v1.3 CertificateRequest message. + * This message is always encrypted. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of CertificateRequest. + * On exit, the index of byte after the CertificateRequest message. + * size The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ + word16 len; + word32 begin = *inOutIdx; + int ret = 0; +#ifndef WOLFSSL_TLS13_DRAFT_18 + Suites peerSuites; +#endif +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + CertReqCtx* certReqCtx; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_DO); + WOLFSSL_ENTER("DoTls13CertificateRequest"); + +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMSET(&peerSuites, 0, sizeof(Suites)); +#endif +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateRequest"); + if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); +#endif + + if ((*inOutIdx - begin) + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + /* Length of the request context. */ + len = input[(*inOutIdx)++]; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + if (ssl->options.connectState < FINISHED_DONE && len > 0) + return BUFFER_ERROR; + +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + /* CertReqCtx has one byte at end for context value. + * Increase size to handle other implementations sending more than one byte. + * That is, allocate extra space, over one byte, to hold the context value. + */ + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = len; + XMEMCPY(&certReqCtx->ctx, input + *inOutIdx, len); + ssl->certReqCtx = certReqCtx; +#endif + *inOutIdx += len; + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Signature and hash algorithms. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + if (PickHashSigAlgo(ssl, input + *inOutIdx, len) != 0 && + ssl->buffers.certificate && ssl->buffers.certificate->buffer && + ssl->buffers.key && ssl->buffers.key->buffer) { + return INVALID_PARAMETER; + } + *inOutIdx += len; + + /* Length of certificate authority data. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + /* Certificate authorities. */ + while (len) { + word16 dnSz; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &dnSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + dnSz > size) + return BUFFER_ERROR; + + *inOutIdx += dnSz; + len -= OPAQUE16_LEN + dnSz; + } + + /* Certificate extensions */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + *inOutIdx += len; +#else + /* TODO: Add support for more extensions: + * signed_certificate_timestamp, certificate_authorities, oid_filters. + */ + /* Certificate extensions */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + if (len == 0) + return INVALID_PARAMETER; + if ((ret = TLSX_Parse(ssl, (byte *)(input + *inOutIdx), len, + certificate_request, &peerSuites))) { + return ret; + } + *inOutIdx += len; +#endif + + if (ssl->buffers.certificate && ssl->buffers.certificate->buffer && + ((ssl->buffers.key && ssl->buffers.key->buffer) + #ifdef HAVE_PK_CALLBACKS + || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) + #endif + )) { +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (PickHashSigAlgo(ssl, peerSuites.hashSigAlgo, + peerSuites.hashSigAlgoSz) != 0) { + return INVALID_PARAMETER; + } +#endif + ssl->options.sendVerify = SEND_CERT; + } + else { + ssl->options.sendVerify = SEND_BLANK_CERT; + } + + /* This message is always encrypted so add encryption padding. */ + *inOutIdx += ssl->keys.padSz; + + WOLFSSL_LEAVE("DoTls13CertificateRequest", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO); + + return ret; +} + +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Refine list of supported cipher suites to those common to server and client. + * + * ssl SSL/TLS object. + * peerSuites The peer's advertised list of supported cipher suites. + */ +static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites) +{ + byte suites[WOLFSSL_MAX_SUITE_SZ]; + int suiteSz = 0; + word16 i, j; + + XMEMSET(suites, 0, WOLFSSL_MAX_SUITE_SZ); + + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + for (j = 0; j < peerSuites->suiteSz; j += 2) { + if (ssl->suites->suites[i+0] == peerSuites->suites[j+0] && + ssl->suites->suites[i+1] == peerSuites->suites[j+1]) { + suites[suiteSz++] = peerSuites->suites[j+0]; + suites[suiteSz++] = peerSuites->suites[j+1]; + } + } + } + + ssl->suites->suiteSz = suiteSz; + XMEMCPY(ssl->suites->suites, &suites, sizeof(suites)); +} + +/* Handle any Pre-Shared Key (PSK) extension. + * Must do this in ClientHello as it requires a hash of the truncated message. + * Don't know size of binders until Pre-Shared Key extension has been parsed. + * + * ssl The SSL/TLS object. + * input The ClientHello message. + * helloSz The size of the ClientHello message (including binders if present). + * usingPSK Indicates handshake is using Pre-Shared Keys. + * returns 0 on success and otherwise failure. + */ +static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, + int* usingPSK) +{ + int ret; + TLSX* ext; + word16 bindersLen; + PreSharedKey* current; + byte binderKey[WC_MAX_DIGEST_SIZE]; + byte binder[WC_MAX_DIGEST_SIZE]; + word32 binderLen; + word16 modes; + byte suite[2]; +#ifdef WOLFSSL_EARLY_DATA + int pskCnt = 0; + TLSX* extEarlyData; +#endif +#ifndef NO_PSK + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE; + byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; +#endif + + WOLFSSL_ENTER("DoPreSharedKeys"); + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) { + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz); + return ret; + } + + /* Extensions pushed on stack/list and PSK must be last. */ + if (ssl->extensions != ext) + return PSK_KEY_ERROR; + + /* Assume we are going to resume with a pre-shared key. */ + ssl->options.resuming = 1; + + /* Find the pre-shared key extension and calculate hash of truncated + * ClientHello for binders. + */ + ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, + client_hello, &bindersLen); + if (ret < 0) + return ret; + + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz - bindersLen); + if (ret != 0) + return ret; + + /* Look through all client's pre-shared keys for a match. */ + current = (PreSharedKey*)ext->data; + while (current != NULL) { + #ifdef WOLFSSL_EARLY_DATA + pskCnt++; + #endif + + #ifndef NO_PSK + if (current->identityLen > MAX_PSK_ID_LEN) { + return BUFFER_ERROR; + } + XMEMCPY(ssl->arrays->client_identity, current->identity, + current->identityLen); + ssl->arrays->client_identity[current->identityLen] = '\0'; + #endif + + #ifdef HAVE_SESSION_TICKET + /* Decode the identity. */ + if ((ret = DoClientTicket(ssl, current->identity, current->identityLen)) + == WOLFSSL_TICKET_RET_OK) { + word32 now; + int diff; + + now = TimeNowInMilliseconds(); + if (now == (word32)GETTIME_ERROR) + return now; + diff = now - ssl->session.ticketSeen; + diff -= current->ticketAge - ssl->session.ticketAdd; + /* Check session and ticket age timeout. + * Allow +/- 1000 milliseconds on ticket age. + */ + if (diff > (int)ssl->timeout * 1000 || diff < -1000 || + diff - MAX_TICKET_AGE_SECS * 1000 > 1000) { + /* Invalid difference, fallback to full handshake. */ + ssl->options.resuming = 0; + break; + } + + /* Check whether resumption is possible based on suites in SSL and + * ciphersuite in ticket. + */ + suite[0] = ssl->session.cipherSuite0; + suite[1] = ssl->session.cipherSuite; + if (!FindSuiteSSL(ssl, suite)) { + current = current->next; + continue; + } + + #ifdef WOLFSSL_EARLY_DATA + ssl->options.maxEarlyDataSz = ssl->session.maxEarlyDataSz; + #endif + /* Use the same cipher suite as before and set up for use. */ + ssl->options.cipherSuite0 = ssl->session.cipherSuite0; + ssl->options.cipherSuite = ssl->session.cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + /* Resumption PSK is resumption master secret. */ + ssl->arrays->psk_keySz = ssl->specs.hash_size; + #ifdef WOLFSSL_TLS13_DRAFT_18 + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->arrays->psk_keySz); + #else + if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, + ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { + return ret; + } + #endif + + /* Derive the early secret using the PSK. */ + ret = DeriveEarlySecret(ssl); + if (ret != 0) + return ret; + /* Derive the binder key to use to with HMAC. */ + ret = DeriveBinderKeyResume(ssl, binderKey); + if (ret != 0) + return ret; + } + else + #endif + #ifndef NO_PSK + if ((ssl->options.server_psk_tls13_cb != NULL && + (ssl->arrays->psk_keySz = ssl->options.server_psk_tls13_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN, &cipherName)) != 0 && + GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) == 0) || + (ssl->options.server_psk_cb != NULL && + (ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN)) != 0)) { + if (ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) + return PSK_KEY_ERROR; + + /* Check whether PSK ciphersuite is in SSL. */ + suite[0] = cipherSuite0; + suite[1] = cipherSuite; + if (!FindSuiteSSL(ssl, suite)) { + current = current->next; + continue; + } + + /* Default to ciphersuite if cb doesn't specify. */ + ssl->options.resuming = 0; + + /* PSK age is always zero. */ + if (current->ticketAge != ssl->session.ticketAdd) + return PSK_KEY_ERROR; + + /* Set PSK ciphersuite into SSL. */ + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + /* Derive the early secret using the PSK. */ + ret = DeriveEarlySecret(ssl); + if (ret != 0) + return ret; + /* Derive the binder key to use to with HMAC. */ + ret = DeriveBinderKey(ssl, binderKey); + if (ret != 0) + return ret; + } + else + #endif + { + current = current->next; + continue; + } + + ssl->options.sendVerify = 0; + + /* Derive the Finished message secret. */ + ret = DeriveFinishedSecret(ssl, binderKey, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + /* Derive the binder and compare with the one in the extension. */ + ret = BuildTls13HandshakeHmac(ssl, + ssl->keys.client_write_MAC_secret, binder, &binderLen); + if (ret != 0) + return ret; + if (binderLen != current->binderLen || + XMEMCMP(binder, current->binder, binderLen) != 0) { + return BAD_BINDER; + } + + /* This PSK works, no need to try any more. */ + current->chosen = 1; + ext->resp = 1; + break; + } + + /* Hash the rest of the ClientHello. */ + ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); + if (ret != 0) + return ret; + + if (current == NULL) { +#ifdef WOLFSSL_PSK_ID_PROTECTION + #ifndef NO_CERTS + if (ssl->buffers.certChainCnt != 0) + return 0; + #endif + return BAD_BINDER; +#else + return 0; +#endif + } + +#ifdef WOLFSSL_EARLY_DATA + extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extEarlyData != NULL) { + if (ssl->earlyData != no_early_data && current == ext->data) { + extEarlyData->resp = 1; + + /* Derive early data decryption key. */ + ret = DeriveTls13Keys(ssl, early_data_key, DECRYPT_SIDE_ONLY, 1); + if (ret != 0) + return ret; + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + ssl->earlyData = process_early_data; + } + else + extEarlyData->resp = 0; + } +#endif + + /* Get the PSK key exchange modes the client wants to negotiate. */ + ext = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (ext == NULL) + return MISSING_HANDSHAKE_DATA; + modes = ext->val; + + ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + /* Use (EC)DHE for forward-security if possible. */ + if ((modes & (1 << PSK_DHE_KE)) != 0 && !ssl->options.noPskDheKe && + ext != NULL) { + /* Only use named group used in last session. */ + ssl->namedGroup = ssl->session.namedGroup; + + /* Pick key share and Generate a new key if not present. */ + ret = TLSX_KeyShare_Establish(ssl); + if (ret == KEY_SHARE_ERROR) { + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + ret = 0; + } + else if (ret < 0) + return ret; + + /* Send new public key to client. */ + ext->resp = 1; + } + else { + if ((modes & (1 << PSK_KE)) == 0) + return PSK_KEY_ERROR; + ssl->options.noPskDheKe = 1; + ssl->arrays->preMasterSz = 0; + } + + *usingPSK = 1; + + WOLFSSL_LEAVE("DoPreSharedKeys", ret); + + return ret; +} +#endif + +#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) +/* Check that the Cookie data's integrity. + * + * ssl SSL/TLS object. + * cookie The cookie data - hash and MAC. + * cookieSz The length of the cookie data in bytes. + * returns Length of the hash on success, otherwise failure. + */ +static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz) +{ + int ret; + byte mac[WC_MAX_DIGEST_SIZE] = {0}; + Hmac cookieHmac; + byte cookieType = 0; + byte macSz = 0; + +#if !defined(NO_SHA) && defined(NO_SHA256) + cookieType = SHA; + macSz = WC_SHA_DIGEST_SIZE; +#endif /* NO_SHA */ +#ifndef NO_SHA256 + cookieType = WC_SHA256; + macSz = WC_SHA256_DIGEST_SIZE; +#endif /* NO_SHA256 */ + + if (cookieSz < ssl->specs.hash_size + macSz) + return HRR_COOKIE_ERROR; + cookieSz -= macSz; + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); + + ret = wc_HmacSetKey(&cookieHmac, cookieType, + ssl->buffers.tls13CookieSecret.buffer, + ssl->buffers.tls13CookieSecret.length); + if (ret != 0) + return ret; + if ((ret = wc_HmacUpdate(&cookieHmac, cookie, cookieSz)) != 0) + return ret; + if ((ret = wc_HmacFinal(&cookieHmac, mac)) != 0) + return ret; + + if (ConstantCompare(cookie + cookieSz, mac, macSz) != 0) + return HRR_COOKIE_ERROR; + return cookieSz; +} + +/* Length of the KeyShare Extension */ +#define HRR_KEY_SHARE_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* Length of the Supported Vresions Extension */ +#define HRR_VERSIONS_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* Length of the Cookie Extension excluding cookie data */ +#define HRR_COOKIE_HDR_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* PV | CipherSuite | Ext Len */ +#define HRR_BODY_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) +/* HH | PV | CipherSuite | Ext Len | Key Share | Cookie */ +#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ + HRR_BODY_SZ + \ + HRR_KEY_SHARE_SZ + \ + HRR_COOKIE_HDR_SZ) +#else +/* PV | Random | Session Id | CipherSuite | Compression | Ext Len */ +#define HRR_BODY_SZ (VERSION_SZ + RAN_LEN + ENUM_LEN + ID_LEN + \ + SUITE_LEN + COMP_LEN + OPAQUE16_LEN) +/* HH | PV | CipherSuite | Ext Len | Key Share | Supported Version | Cookie */ +#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ + HRR_BODY_SZ + \ + HRR_KEY_SHARE_SZ + \ + HRR_VERSIONS_SZ + \ + HRR_COOKIE_HDR_SZ) +#endif + +/* Restart the handshake hash from the cookie value. + * + * ssl SSL/TLS object. + * cookie Cookie data from client. + * returns 0 on success, otherwise failure. + */ +static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) +{ + byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte hrr[MAX_HRR_SZ] = {0}; + int hrrIdx; + word32 idx; + byte hashSz; + byte* cookieData; + byte cookieDataSz; + word16 length; + int keyShareExt = 0; + int ret; + + cookieDataSz = ret = CheckCookie(ssl, &cookie->data, cookie->len); + if (ret < 0) + return ret; + hashSz = cookie->data; + cookieData = &cookie->data; + idx = OPAQUE8_LEN; + + /* Restart handshake hash with synthetic message hash. */ + AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); + if ((ret = InitHandshakeHashes(ssl)) != 0) + return ret; + if ((ret = HashOutputRaw(ssl, header, sizeof(header))) != 0) + return ret; + if ((ret = HashOutputRaw(ssl, cookieData + idx, hashSz)) != 0) + return ret; + + /* Reconstruct the HelloRetryMessage for handshake hash. */ +#ifdef WOLFSSL_TLS13_DRAFT_18 + length = HRR_BODY_SZ + HRR_COOKIE_HDR_SZ + cookie->len; +#else + length = HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz + + HRR_COOKIE_HDR_SZ + cookie->len; + length += HRR_VERSIONS_SZ; +#endif + if (cookieDataSz > hashSz + OPAQUE16_LEN) { + keyShareExt = 1; + length += HRR_KEY_SHARE_SZ; + } +#ifdef WOLFSSL_TLS13_DRAFT_18 + AddTls13HandShakeHeader(hrr, length, 0, 0, hello_retry_request, ssl); + + idx += hashSz; + hrrIdx = HANDSHAKE_HEADER_SZ; + /* The negotiated protocol version. */ + hrr[hrrIdx++] = TLS_DRAFT_MAJOR; + hrr[hrrIdx++] = TLS_DRAFT_MINOR; + /* Cipher Suite */ + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + + /* Extensions' length */ + length -= HRR_BODY_SZ; + c16toa(length, hrr + hrrIdx); + hrrIdx += 2; +#else + AddTls13HandShakeHeader(hrr, length, 0, 0, server_hello, ssl); + + idx += hashSz; + hrrIdx = HANDSHAKE_HEADER_SZ; + + /* The negotiated protocol version. */ + hrr[hrrIdx++] = ssl->version.major; + hrr[hrrIdx++] = TLSv1_2_MINOR; + + /* HelloRetryRequest message has fixed value for random. */ + XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN); + hrrIdx += RAN_LEN; + + hrr[hrrIdx++] = ssl->session.sessionIDSz; + if (ssl->session.sessionIDSz > 0) { + XMEMCPY(hrr + hrrIdx, ssl->session.sessionID, ssl->session.sessionIDSz); + hrrIdx += ssl->session.sessionIDSz; + } + + /* Cipher Suite */ + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + + /* Compression not supported in TLS v1.3. */ + hrr[hrrIdx++] = 0; + + /* Extensions' length */ + length -= HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz; + c16toa(length, hrr + hrrIdx); + hrrIdx += 2; + +#endif + /* Optional KeyShare Extension */ + if (keyShareExt) { + c16toa(TLSX_KEY_SHARE, hrr + hrrIdx); + hrrIdx += 2; + c16toa(OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + hrr[hrrIdx++] = cookieData[idx++]; + hrr[hrrIdx++] = cookieData[idx++]; + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + c16toa(TLSX_SUPPORTED_VERSIONS, hrr + hrrIdx); + hrrIdx += 2; + c16toa(OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + #ifdef WOLFSSL_TLS13_DRAFT + hrr[hrrIdx++] = TLS_DRAFT_MAJOR; + hrr[hrrIdx++] = TLS_DRAFT_MINOR; + #else + hrr[hrrIdx++] = ssl->version.major; + hrr[hrrIdx++] = ssl->version.minor; + #endif +#endif + /* Mandatory Cookie Extension */ + c16toa(TLSX_COOKIE, hrr + hrrIdx); + hrrIdx += 2; + c16toa(cookie->len + OPAQUE16_LEN, hrr + hrrIdx); + hrrIdx += 2; + c16toa(cookie->len, hrr + hrrIdx); + hrrIdx += 2; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Reconstucted HelloRetryRequest"); + WOLFSSL_BUFFER(hrr, hrrIdx); + WOLFSSL_MSG("Cookie"); + WOLFSSL_BUFFER(cookieData, cookie->len); +#endif + + if ((ret = HashOutputRaw(ssl, hrr, hrrIdx)) != 0) + return ret; + return HashOutputRaw(ssl, cookieData, cookie->len); +} +#endif + +/* Do SupportedVersion extension for TLS v1.3+ otherwise it is not. + * + * ssl The SSL/TLS object. + * input The message buffer. + * i The index into the message buffer of ClientHello. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13SupportedVersions(WOLFSSL* ssl, const byte* input, word32 i, + word32 helloSz, int* wantDowngrade) +{ + int ret; + byte b; + word16 suiteSz; + word16 totalExtSz; + int foundVersion = 0; + + /* Client random */ + i += RAN_LEN; + /* Session id - not used in TLS v1.3 */ + b = input[i++]; + if (i + b > helloSz) { + return BUFFER_ERROR; + } + i += b; + /* Cipher suites */ + if (i + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(input + i, &suiteSz); + i += OPAQUE16_LEN; + if (i + suiteSz + 1 > helloSz) + return BUFFER_ERROR; + i += suiteSz; + /* Compression */ + b = input[i++]; + if (i + b > helloSz) + return BUFFER_ERROR; + i += b; + + /* TLS 1.3 must have extensions */ + if (i < helloSz) { + if (i + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if (totalExtSz != helloSz - i) + return BUFFER_ERROR; + + /* Need to negotiate version first. */ + if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz, + client_hello, &foundVersion))) { + return ret; + } + } + *wantDowngrade = !foundVersion || !IsAtLeastTLSv1_3(ssl->version); + + return 0; +} + +/* Handle a ClientHello handshake message. + * If the protocol version in the message is not TLS v1.3 or higher, use + * DoClientHello() + * Only a server will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of ClientHello. + * On exit, the index of byte after the ClientHello message and + * padding. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) +{ + int ret = VERSION_ERROR; + byte b = 0; + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + word16 totalExtSz = 0; + int usingPSK = 0; + byte sessIdSz = 0; + int wantDowngrade = 0; + + WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); + WOLFSSL_ENTER("DoTls13ClientHello"); + + XMEMSET(&pv, 0, sizeof(ProtocolVersion)); + XMEMSET(&clSuites, 0, sizeof(Suites)); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); + if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* Protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + ssl->chVersion = pv; /* store */ + i += OPAQUE16_LEN; + if (pv.major < SSLv3_MAJOR) { + WOLFSSL_MSG("Legacy version field contains unsupported value"); + #ifdef WOLFSSL_MYSQL_COMPATIBLE + SendAlert(ssl, alert_fatal, wc_protocol_version); + #else + SendAlert(ssl, alert_fatal, protocol_version); + #endif + return INVALID_PARAMETER; + } + /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */ + if (pv.major > SSLv3_MAJOR || (pv.major == SSLv3_MAJOR && + pv.minor >= TLSv1_3_MINOR)) { + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_2_MINOR; + wantDowngrade = 1; + ssl->version.minor = pv.minor; + } + /* Legacy version must be [ SSLv3_MAJOR, TLSv1_2_MINOR ] for TLS v1.3 */ + else if (pv.major == SSLv3_MAJOR && pv.minor < TLSv1_2_MINOR) { + wantDowngrade = 1; + ssl->version.minor = pv.minor; + } + else { + ret = DoTls13SupportedVersions(ssl, input + begin, i - begin, helloSz, + &wantDowngrade); + if (ret < 0) + return ret; + } + if (wantDowngrade) { +#ifndef WOLFSSL_NO_TLS12 + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Client trying to connect with lesser version than " + "TLS v1.3"); + return VERSION_ERROR; + } + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; + return DoClientHello(ssl, input, inOutIdx, helloSz); +#else + WOLFSSL_MSG("Client trying to connect with lesser version than " + "TLS v1.3"); + return VERSION_ERROR; +#endif + } + + /* Client random */ + XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); + i += RAN_LEN; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("client random"); + WOLFSSL_BUFFER(ssl->arrays->clientRandom, RAN_LEN); +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Session id - empty in TLS v1.3 */ + sessIdSz = input[i++]; + if (sessIdSz > 0 && !ssl->options.downgrade) { + WOLFSSL_MSG("Client sent session id - not supported"); + return BUFFER_ERROR; + } +#else + sessIdSz = input[i++]; + if (sessIdSz != ID_LEN && sessIdSz != 0) + return INVALID_PARAMETER; +#endif + + if (sessIdSz + i > helloSz) { + return BUFFER_ERROR; + } + + ssl->session.sessionIDSz = sessIdSz; + if (sessIdSz == ID_LEN) { + XMEMCPY(ssl->session.sessionID, input + i, sessIdSz); + i += ID_LEN; + } + + /* Cipher suites */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &clSuites.suiteSz); + i += OPAQUE16_LEN; + /* suites and compression length check */ + if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ) + return BUFFER_ERROR; + XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); + i += clSuites.suiteSz; + clSuites.hashSigAlgoSz = 0; + +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + ret = FindSuite(&clSuites, 0, TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + if (ret == SUITES_ERROR) + return BUFFER_ERROR; + if (ret >= 0) { + TLSX* extension; + + /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */ + ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (extension) { + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; + ssl->secure_renegotiation->enabled = 1; + } + } +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ + + /* Compression */ + b = input[i++]; + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + if (b != COMP_LEN) { + WOLFSSL_MSG("Must be one compression type in list"); + return INVALID_PARAMETER; + } + b = input[i++]; + if (b != NO_COMPRESSION) { + WOLFSSL_MSG("Must be no compression type in list"); + return INVALID_PARAMETER; + } + + /* Extensions */ + if ((i - begin) == helloSz) + return BUFFER_ERROR; + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) + return ret; + + /* Parse extensions */ + if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, + &clSuites))) { + return ret; + } + +#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) + if ((ret = SNI_Callback(ssl)) != 0) + return ret; + ssl->options.side = WOLFSSL_SERVER_END; +#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + + i += totalExtSz; + *inOutIdx = i; + + ssl->options.sendVerify = SEND_CERT; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.haveSessionId = 1; + +#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) + if (ssl->options.sendCookie && + ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + TLSX* ext; + + if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL) + return HRR_COOKIE_ERROR; + /* Ensure the cookie came from client and isn't the one in the + * response - HelloRetryRequest. + */ + if (ext->resp == 1) + return HRR_COOKIE_ERROR; + ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data); + if (ret != 0) + return ret; + } +#endif + +#if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ + defined(HAVE_TLS_EXTENSIONS) + if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY) != NULL) { + /* Refine list for PSK processing. */ + RefineSuites(ssl, &clSuites); + + /* Process the Pre-Shared Key extension if present. */ + ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); + if (ret != 0) + return ret; + } + else +#endif + { +#ifdef WOLFSSL_EARLY_DATA + ssl->earlyData = no_early_data; +#endif + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; + + } + + if (!usingPSK) { + if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { + WOLFSSL_MSG("Client did not send a KeyShare extension"); + SendAlert(ssl, alert_fatal, missing_extension); + return INCOMPLETE_DATA; + } + if (TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS) == NULL) { + WOLFSSL_MSG("Client did not send a SignatureAlgorithms extension"); + SendAlert(ssl, alert_fatal, missing_extension); + return INCOMPLETE_DATA; + } + + if ((ret = MatchSuite(ssl, &clSuites)) < 0) { + WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); + SendAlert(ssl, alert_fatal, handshake_failure); + return ret; + } + +#ifdef HAVE_NULL_CIPHER + if (ssl->options.cipherSuite0 == ECC_BYTE && + (ssl->options.cipherSuite == TLS_SHA256_SHA256 || + ssl->options.cipherSuite == TLS_SHA384_SHA384)) { + ; + } + else +#endif + /* Check that the negotiated ciphersuite matches protocol version. */ + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + WOLFSSL_MSG("Negotiated ciphersuite from lesser version than " + "TLS v1.3"); + SendAlert(ssl, alert_fatal, handshake_failure); + return VERSION_ERROR; + } + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.resuming) { + ssl->options.resuming = 0; + XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); + } +#endif + + /* Derive early secret for handshake secret. */ + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + } + + WOLFSSL_LEAVE("DoTls13ClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); + + return ret; +} + +#ifdef WOLFSSL_TLS13_DRAFT_18 +/* handle generation of TLS 1.3 hello_retry_request (6) */ +/* Send the HelloRetryRequest message to indicate the negotiated protocol + * version and security parameters the server is willing to use. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13HelloRetryRequest(WOLFSSL* ssl) +{ + int ret; + byte* output; + word32 length; + word16 len; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + WOLFSSL_ENTER("SendTls13HelloRetryRequest"); + + /* Get the length of the extensions that will be written. */ + len = 0; + ret = TLSX_GetResponseSize(ssl, hello_retry_request, &len); + /* There must be extensions sent to indicate what client needs to do. */ + if (ret != 0) + return MISSING_HANDSHAKE_DATA; + + /* Protocol version + Extensions */ + length = OPAQUE16_LEN + len; + sendSz = idx + length; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + /* Add record and handshake headers. */ + AddTls13Headers(output, length, hello_retry_request, ssl); + + /* The negotiated protocol version. */ + output[idx++] = TLS_DRAFT_MAJOR; + output[idx++] = TLS_DRAFT_MINOR; + + /* Add TLS extensions. */ + ret = TLSX_WriteResponse(ssl, output + idx, hello_retry_request, NULL); + if (ret != 0) + return ret; + idx += len; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "HelloRetryRequest"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "HelloRetryRequest", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } +#endif + if ((ret = HashOutput(ssl, output, idx, 0)) != 0) + return ret; + + ssl->buffers.outputBuffer.length += sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13HelloRetryRequest", ret); + + return ret; +} +#endif /* WOLFSSL_TLS13_DRAFT_18 */ + +/* Send TLS v1.3 ServerHello message to client. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +#ifdef WOLFSSL_TLS13_DRAFT_18 +static +#endif +/* handle generation of TLS 1.3 server_hello (2) */ +int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) +{ + int ret; + byte* output; + word16 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND); + WOLFSSL_ENTER("SendTls13ServerHello"); + +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (extMsgType == hello_retry_request) { + WOLFSSL_MSG("wolfSSL Doing HelloRetryRequest"); + if ((ret = RestartHandshakeHash(ssl)) < 0) + return ret; + } +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Protocol version, server random, cipher suite and extensions. */ + length = VERSION_SZ + RAN_LEN + SUITE_LEN; + ret = TLSX_GetResponseSize(ssl, server_hello, &length); + if (ret != 0) + return ret; +#else + /* Protocol version, server random, session id, cipher suite, compression + * and extensions. + */ + length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->session.sessionIDSz + + SUITE_LEN + COMP_LEN; + ret = TLSX_GetResponseSize(ssl, extMsgType, &length); + if (ret != 0) + return ret; +#endif + sendSz = idx + length; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, server_hello, ssl); + +#ifdef WOLFSSL_TLS13_DRAFT_18 + /* The negotiated protocol version. */ + output[idx++] = TLS_DRAFT_MAJOR; + output[idx++] = TLS_DRAFT_MINOR; +#else + /* The protocol version must be TLS v1.2 for middleboxes. */ + output[idx++] = ssl->version.major; + output[idx++] = TLSv1_2_MINOR; +#endif + + if (extMsgType == server_hello) { + /* Generate server random. */ + if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0) + return ret; + } +#ifndef WOLFSSL_TLS13_DRAFT_18 + else { + /* HelloRetryRequest message has fixed value for random. */ + XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN); + } +#endif + /* Store in SSL for debugging. */ + XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); + idx += RAN_LEN; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Server random"); + WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN); +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 + output[idx++] = ssl->session.sessionIDSz; + if (ssl->session.sessionIDSz > 0) { + XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); + idx += ssl->session.sessionIDSz; + } +#endif + + /* Chosen cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Compression not supported in TLS v1.3. */ + output[idx++] = 0; +#endif + + /* Extensions */ + ret = TLSX_WriteResponse(ssl, output + idx, extMsgType, NULL); + if (ret != 0) + return ret; + + ssl->buffers.outputBuffer.length += sendSz; + + if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0) + return ret; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "ServerHello"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "ServerHello", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } + #endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + ssl->options.serverState = SERVER_HELLO_COMPLETE; +#else + if (extMsgType == server_hello) + ssl->options.serverState = SERVER_HELLO_COMPLETE; +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + if (!ssl->options.groupMessages) +#else + if (!ssl->options.groupMessages || extMsgType != server_hello) +#endif + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13ServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_SEND); + + return ret; +} + +/* handle generation of TLS 1.3 encrypted_extensions (8) */ +/* Send the rest of the extensions encrypted under the handshake key. + * This message is always encrypted in TLS v1.3. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13EncryptedExtensions(WOLFSSL* ssl) +{ + int ret; + byte* output; + word16 length = 0; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); + WOLFSSL_ENTER("SendTls13EncryptedExtensions"); + + ssl->keys.encryptionOn = 1; + +#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT + if ((ret = TLSX_SupportedCurve_CheckPriority(ssl)) != 0) + return ret; +#endif + + /* Derive the handshake secret now that we are at first message to be + * encrypted under the keys. + */ + if ((ret = DeriveHandshakeSecret(ssl)) != 0) + return ret; + if ((ret = DeriveTls13Keys(ssl, handshake_key, + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) + return ret; + + /* Setup encrypt/decrypt keys for following messages. */ +#ifdef WOLFSSL_EARLY_DATA + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + if (ssl->earlyData != process_early_data) { + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + } +#else + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; +#endif + + ret = TLSX_GetResponseSize(ssl, encrypted_extensions, &length); + if (ret != 0) + return ret; + + sendSz = idx + length; + /* Encryption always on. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + ret = CheckAvailableSize(ssl, sendSz); + if (ret != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, encrypted_extensions, ssl); + + ret = TLSX_WriteResponse(ssl, output + idx, encrypted_extensions, NULL); + if (ret != 0) + return ret; + idx += length; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "EncryptedExtensions"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "EncryptedExtensions", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); + } +#endif + + /* This handshake message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13EncryptedExtensions", ret); + WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); + + return ret; +} + +#ifndef NO_CERTS +/* handle generation TLS v1.3 certificate_request (13) */ +/* Send the TLS v1.3 CertificateRequest message. + * This message is always encrypted in TLS v1.3. + * Only a server will send this message. + * + * ssl SSL/TLS object. + * reqCtx Request context. + * reqCtxLen Length of context. 0 when sending as part of handshake. + * returns 0 on success, otherwise failure. + */ +static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, + int reqCtxLen) +{ + byte* output; + int ret; + int sendSz; + word32 i; + word16 reqSz; +#ifndef WOLFSSL_TLS13_DRAFT_18 + TLSX* ext; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND); + WOLFSSL_ENTER("SendTls13CertificateRequest"); + + if (ssl->options.side == WOLFSSL_SERVER_END) + InitSuitesHashSigAlgo(ssl->suites, 1, 1, 0, 1, ssl->buffers.keySz); + +#ifdef WOLFSSL_TLS13_DRAFT_18 + i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + reqSz = OPAQUE8_LEN + reqCtxLen + REQ_HEADER_SZ + REQ_HEADER_SZ; + reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + /* Always encrypted and make room for padding. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, reqSz, certificate_request, ssl); + + /* Certificate request context. */ + output[i++] = reqCtxLen; + if (reqCtxLen != 0) { + XMEMCPY(output + i, reqCtx, reqCtxLen); + i += reqCtxLen; + } + + /* supported hash/sig */ + c16toa(ssl->suites->hashSigAlgoSz, &output[i]); + i += LENGTH_SZ; + + XMEMCPY(&output[i], ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz); + i += ssl->suites->hashSigAlgoSz; + + /* Certificate authorities not supported yet - empty buffer. */ + c16toa(0, &output[i]); + i += REQ_HEADER_SZ; + + /* Certificate extensions. */ + c16toa(0, &output[i]); /* auth's */ + i += REQ_HEADER_SZ; +#else + ext = TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS); + if (ext == NULL) + return EXT_MISSING; + ext->resp = 0; + + i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + reqSz = (word16)(OPAQUE8_LEN + reqCtxLen); + ret = TLSX_GetRequestSize(ssl, certificate_request, &reqSz); + if (ret != 0) + return ret; + + sendSz = i + reqSz; + /* Always encrypted and make room for padding. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, reqSz, certificate_request, ssl); + + /* Certificate request context. */ + output[i++] = (byte)reqCtxLen; + if (reqCtxLen != 0) { + XMEMCPY(output + i, reqCtx, reqCtxLen); + i += reqCtxLen; + } + + /* Certificate extensions. */ + reqSz = 0; + ret = TLSX_WriteRequest(ssl, output + i, certificate_request, &reqSz); + if (ret != 0) + return ret; + i += reqSz; +#endif + + /* Always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + i - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateRequest"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "CertificateRequest", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13CertificateRequest", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_SEND); + + return ret; +} +#endif /* NO_CERTS */ +#endif /* NO_WOLFSSL_SERVER */ + +#ifndef NO_CERTS +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) +/* Encode the signature algorithm into buffer. + * + * hashalgo The hash algorithm. + * hsType The signature type. + * output The buffer to encode into. + */ +static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) +{ + switch (hsType) { +#ifdef HAVE_ECC + case ecc_dsa_sa_algo: + output[0] = hashAlgo; + output[1] = ecc_dsa_sa_algo; + break; +#endif +#ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + case ed25519_sa_algo: + output[0] = ED25519_SA_MAJOR; + output[1] = ED25519_SA_MINOR; + (void)hashAlgo; + break; +#endif +#ifdef HAVE_ED448 + /* ED448: 0x0808 */ + case ed448_sa_algo: + output[0] = ED448_SA_MAJOR; + output[1] = ED448_SA_MINOR; + (void)hashAlgo; + break; +#endif +#ifndef NO_RSA + /* PSS signatures: 0x080[4-6] */ + case rsa_pss_sa_algo: + output[0] = rsa_pss_sa_algo; + output[1] = hashAlgo; + break; +#endif + } +} + +/* Decode the signature algorithm. + * + * input The encoded signature algorithm. + * hashalgo The hash algorithm. + * hsType The signature type. + * returns INVALID_PARAMETER if not recognized and 0 otherwise. + */ +static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, + byte* hsType) +{ + int ret = 0; + + switch (input[0]) { + case NEW_SA_MAJOR: + /* PSS signatures: 0x080[4-6] */ + if (input[1] >= sha256_mac && input[1] <= sha512_mac) { + *hsType = input[0]; + *hashAlgo = input[1]; + } + #ifdef HAVE_ED25519 + /* ED25519: 0x0807 */ + else if (input[1] == ED25519_SA_MINOR) { + *hsType = ed25519_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + #ifdef HAVE_ED448 + /* ED448: 0x0808 */ + else if (input[1] == ED448_SA_MINOR) { + *hsType = ed448_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + else + ret = INVALID_PARAMETER; + break; + default: + *hashAlgo = input[0]; + *hsType = input[1]; + break; + } + + return ret; +} + +/* Get the hash of the messages so far. + * + * ssl The SSL/TLS object. + * hash The buffer to write the hash to. + * returns the length of the hash. + */ +static WC_INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash) +{ + int ret = 0; + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + if (ret == 0) + ret = WC_SHA256_DIGEST_SIZE; + break; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + if (ret == 0) + ret = WC_SHA384_DIGEST_SIZE; + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + if (ret == 0) + ret = WC_SHA512_DIGEST_SIZE; + break; + #endif /* WOLFSSL_TLS13_SHA512 */ + } + return ret; +} + +/* The length of the certificate verification label - client and server. */ +#define CERT_VFY_LABEL_SZ 34 +/* The server certificate verification label. */ +static const byte serverCertVfyLabel[CERT_VFY_LABEL_SZ] = + "TLS 1.3, server CertificateVerify"; +/* The client certificate verification label. */ +static const byte clientCertVfyLabel[CERT_VFY_LABEL_SZ] = + "TLS 1.3, client CertificateVerify"; + +/* The number of prefix bytes for signature data. */ +#define SIGNING_DATA_PREFIX_SZ 64 +/* The prefix byte in the signature data. */ +#define SIGNING_DATA_PREFIX_BYTE 0x20 +/* Maximum length of the signature data. */ +#define MAX_SIG_DATA_SZ (SIGNING_DATA_PREFIX_SZ + \ + CERT_VFY_LABEL_SZ + \ + WC_MAX_DIGEST_SIZE) + +/* Create the signature data for TLS v1.3 certificate verification. + * + * ssl The SSL/TLS object. + * sigData The signature data. + * sigDataSz The length of the signature data. + * check Indicates this is a check not create. + */ +static int CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, + int check) +{ + word16 idx; + int side = ssl->options.side; + int ret; + + /* Signature Data = Prefix | Label | Handshake Hash */ + XMEMSET(sigData, SIGNING_DATA_PREFIX_BYTE, SIGNING_DATA_PREFIX_SZ); + idx = SIGNING_DATA_PREFIX_SZ; + + if ((side == WOLFSSL_SERVER_END && check) || + (side == WOLFSSL_CLIENT_END && !check)) { + XMEMCPY(&sigData[idx], clientCertVfyLabel, CERT_VFY_LABEL_SZ); + } + if ((side == WOLFSSL_CLIENT_END && check) || + (side == WOLFSSL_SERVER_END && !check)) { + XMEMCPY(&sigData[idx], serverCertVfyLabel, CERT_VFY_LABEL_SZ); + } + idx += CERT_VFY_LABEL_SZ; + + ret = GetMsgHash(ssl, &sigData[idx]); + if (ret < 0) + return ret; + + *sigDataSz = (word16)(idx + ret); + ret = 0; + + return ret; +} + +#ifndef NO_RSA +/* Encode the PKCS #1.5 RSA signature. + * + * sig The buffer to place the encoded signature into. + * sigData The data to be signed. + * sigDataSz The size of the data to be signed. + * hashAlgo The hash algorithm to use when signing. + * returns the length of the encoded signature or negative on error. + */ +static int CreateRSAEncodedSig(byte* sig, byte* sigData, int sigDataSz, + int sigAlgo, int hashAlgo) +{ + Digest digest; + int hashSz = 0; + int ret = BAD_FUNC_ARG; + byte* hash; + + (void)sigAlgo; + + hash = sig; + + /* Digest the signature data. */ + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + ret = wc_InitSha256(&digest.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&digest.sha256, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha256Final(&digest.sha256, hash); + wc_Sha256Free(&digest.sha256); + } + hashSz = WC_SHA256_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_InitSha384(&digest.sha384); + if (ret == 0) { + ret = wc_Sha384Update(&digest.sha384, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha384Final(&digest.sha384, hash); + wc_Sha384Free(&digest.sha384); + } + hashSz = WC_SHA384_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + ret = wc_InitSha512(&digest.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&digest.sha512, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha512Final(&digest.sha512, hash); + wc_Sha512Free(&digest.sha512); + } + hashSz = WC_SHA512_DIGEST_SIZE; + break; +#endif + } + + if (ret != 0) + return ret; + + return hashSz; +} +#endif /* !NO_RSA */ + +#ifdef HAVE_ECC +/* Encode the ECC signature. + * + * sigData The data to be signed. + * sigDataSz The size of the data to be signed. + * hashAlgo The hash algorithm to use when signing. + * returns the length of the encoded signature or negative on error. + */ +static int CreateECCEncodedSig(byte* sigData, int sigDataSz, int hashAlgo) +{ + Digest digest; + int hashSz = 0; + int ret = BAD_FUNC_ARG; + + /* Digest the signature data. */ + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + ret = wc_InitSha256(&digest.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&digest.sha256, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha256Final(&digest.sha256, sigData); + wc_Sha256Free(&digest.sha256); + } + hashSz = WC_SHA256_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_InitSha384(&digest.sha384); + if (ret == 0) { + ret = wc_Sha384Update(&digest.sha384, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha384Final(&digest.sha384, sigData); + wc_Sha384Free(&digest.sha384); + } + hashSz = WC_SHA384_DIGEST_SIZE; + break; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + ret = wc_InitSha512(&digest.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&digest.sha512, sigData, sigDataSz); + if (ret == 0) + ret = wc_Sha512Final(&digest.sha512, sigData); + wc_Sha512Free(&digest.sha512); + } + hashSz = WC_SHA512_DIGEST_SIZE; + break; +#endif + } + + if (ret != 0) + return ret; + + return hashSz; +} +#endif /* HAVE_ECC */ + +#ifndef NO_RSA +/* Check that the decrypted signature matches the encoded signature + * based on the digest of the signature data. + * + * ssl The SSL/TLS object. + * sigAlgo The signature algorithm used to generate signature. + * hashAlgo The hash algorithm used to generate signature. + * decSig The decrypted signature. + * decSigSz The size of the decrypted signature. + * returns 0 on success, otherwise failure. + */ +static int CheckRSASignature(WOLFSSL* ssl, int sigAlgo, int hashAlgo, + byte* decSig, word32 decSigSz) +{ + int ret = 0; + byte sigData[MAX_SIG_DATA_SZ]; + word16 sigDataSz; + word32 sigSz; + + ret = CreateSigData(ssl, sigData, &sigDataSz, 1); + if (ret != 0) + return ret; + + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + + ret = ConvertHashPss(hashAlgo, &hashType, NULL); + if (ret < 0) + return ret; + + /* PSS signature can be done in-place */ + ret = CreateRSAEncodedSig(sigData, sigData, sigDataSz, + sigAlgo, hashAlgo); + if (ret < 0) + return ret; + sigSz = ret; + + ret = wc_RsaPSS_CheckPadding(sigData, sigSz, decSig, decSigSz, + hashType); + } + + return ret; +} +#endif /* !NO_RSA */ +#endif /* !NO_RSA || HAVE_ECC */ + +/* Get the next certificate from the list for writing into the TLS v1.3 + * Certificate message. + * + * data The certificate list. + * length The length of the certificate data in the list. + * idx The index of the next certificate. + * returns the length of the certificate data. 0 indicates no more certificates + * in the list. + */ +static word32 NextCert(byte* data, word32 length, word32* idx) +{ + word32 len; + + /* Is index at end of list. */ + if (*idx == length) + return 0; + + /* Length of the current ASN.1 encoded certificate. */ + c24to32(data + *idx, &len); + /* Include the length field. */ + len += 3; + + /* Move index to next certificate and return the current certificate's + * length. + */ + *idx += len; + return len; +} + +/* Add certificate data and empty extension to output up to the fragment size. + * + * ssl SSL/TLS object. + * cert The certificate data to write out. + * len The length of the certificate data. + * extSz Length of the extension data with the certificate. + * idx The start of the certificate data to write out. + * fragSz The maximum size of this fragment. + * output The buffer to write to. + * returns the number of bytes written. + */ +static word32 AddCertExt(WOLFSSL* ssl, byte* cert, word32 len, word16 extSz, + word32 idx, word32 fragSz, byte* output) +{ + word32 i = 0; + word32 copySz = min(len - idx, fragSz); + + if (idx < len) { + XMEMCPY(output, cert + idx, copySz); + i = copySz; + if (copySz == fragSz) + return i; + } + copySz = len + extSz - idx - i; + + if (extSz == OPAQUE16_LEN) { + if (copySz <= fragSz) { + /* Empty extension */ + output[i++] = 0; + output[i++] = 0; + } + } + else { + byte* certExts = ssl->buffers.certExts->buffer + idx + i - len; + /* Put out as much of the extensions' data as will fit in fragment. */ + if (copySz > fragSz - i) + copySz = fragSz - i; + XMEMCPY(output + i, certExts, copySz); + i += copySz; + } + + return i; +} + +/* handle generation TLS v1.3 certificate (11) */ +/* Send the certificate for this end and any CAs that help with validation. + * This message is always encrypted in TLS v1.3. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13Certificate(WOLFSSL* ssl) +{ + int ret = 0; + word32 certSz, certChainSz, headerSz, listSz, payloadSz; + word16 extSz = 0; + word32 length, maxFragment; + word32 len = 0; + word32 idx = 0; + word32 offset = OPAQUE16_LEN; + byte* p = NULL; + byte certReqCtxLen = 0; + byte* certReqCtx = NULL; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_SEND); + WOLFSSL_ENTER("SendTls13Certificate"); + +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->certReqCtx != NULL) { + certReqCtxLen = ssl->certReqCtx->len; + certReqCtx = &ssl->certReqCtx->ctx; + } +#endif + + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + certSz = 0; + certChainSz = 0; + headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ; + length = headerSz; + listSz = 0; + } + else { + if (!ssl->buffers.certificate) { + WOLFSSL_MSG("Send Cert missing certificate buffer"); + return BUFFER_ERROR; + } + /* Certificate Data */ + certSz = ssl->buffers.certificate->length; + /* Cert Req Ctx Len | Cert Req Ctx | Cert List Len | Cert Data Len */ + headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ + + CERT_HEADER_SZ; + + ret = TLSX_GetResponseSize(ssl, certificate, &extSz); + if (ret < 0) + return ret; + + /* Create extensions' data if none already present. */ + if (extSz > OPAQUE16_LEN && ssl->buffers.certExts == NULL) { + ret = AllocDer(&ssl->buffers.certExts, extSz, CERT_TYPE, ssl->heap); + if (ret < 0) + return ret; + + extSz = 0; + ret = TLSX_WriteResponse(ssl, ssl->buffers.certExts->buffer, + certificate, &extSz); + if (ret < 0) + return ret; + } + + /* Length of message data with one certificate and extensions. */ + length = headerSz + certSz + extSz; + /* Length of list data with one certificate and extensions. */ + listSz = CERT_HEADER_SZ + certSz + extSz; + + /* Send rest of chain if sending cert (chain has leading size/s). */ + if (certSz > 0 && ssl->buffers.certChainCnt > 0) { + p = ssl->buffers.certChain->buffer; + /* Chain length including extensions. */ + certChainSz = ssl->buffers.certChain->length + + OPAQUE16_LEN * ssl->buffers.certChainCnt; + length += certChainSz; + listSz += certChainSz; + } + else + certChainSz = 0; + } + + payloadSz = length; + + if (ssl->fragOffset != 0) + length -= (ssl->fragOffset + headerSz); + + maxFragment = wolfSSL_GetMaxRecordSize(ssl, MAX_RECORD_SIZE); + + while (length > 0 && ret == 0) { + byte* output = NULL; + word32 fragSz = 0; + word32 i = RECORD_HEADER_SZ; + int sendSz = RECORD_HEADER_SZ; + + if (ssl->fragOffset == 0) { + if (headerSz + certSz + extSz + certChainSz <= + maxFragment - HANDSHAKE_HEADER_SZ) { + fragSz = headerSz + certSz + extSz + certChainSz; + } + else + fragSz = maxFragment - HANDSHAKE_HEADER_SZ; + + sendSz += fragSz + HANDSHAKE_HEADER_SZ; + i += HANDSHAKE_HEADER_SZ; + } + else { + fragSz = min(length, maxFragment); + sendSz += fragSz; + } + + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + if (ssl->fragOffset == 0) { + AddTls13FragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); + + /* Request context. */ + output[i++] = certReqCtxLen; + if (certReqCtxLen > 0) { + XMEMCPY(output + i, certReqCtx, certReqCtxLen); + i += certReqCtxLen; + } + length -= OPAQUE8_LEN + certReqCtxLen; + fragSz -= OPAQUE8_LEN + certReqCtxLen; + /* Certificate list length. */ + c32to24(listSz, output + i); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + /* Leaf certificate data length. */ + if (certSz > 0) { + c32to24(certSz, output + i); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + } + } + else + AddTls13RecordHeader(output, fragSz, handshake, ssl); + + if (certSz > 0 && ssl->fragOffset < certSz + extSz) { + /* Put in the leaf certificate with extensions. */ + word32 copySz = AddCertExt(ssl, ssl->buffers.certificate->buffer, + certSz, extSz, ssl->fragOffset, fragSz, output + i); + i += copySz; + ssl->fragOffset += copySz; + length -= copySz; + fragSz -= copySz; + if (ssl->fragOffset == certSz + extSz) + FreeDer(&ssl->buffers.certExts); + } + if (certChainSz > 0 && fragSz > 0) { + /* Put in the CA certificates with empty extensions. */ + while (fragSz > 0) { + word32 l; + + if (offset == len + OPAQUE16_LEN) { + /* Find next CA certificate to write out. */ + offset = 0; + /* Point to the start of current cert in chain buffer. */ + p = ssl->buffers.certChain->buffer + idx; + len = NextCert(ssl->buffers.certChain->buffer, + ssl->buffers.certChain->length, &idx); + if (len == 0) + break; + } + + /* Write out certificate and empty extension. */ + l = AddCertExt(ssl, p, len, OPAQUE16_LEN, offset, fragSz, + output + i); + i += l; + ssl->fragOffset += l; + length -= l; + fragSz -= l; + offset += l; + } + } + + if ((int)i - RECORD_HEADER_SZ < 0) { + WOLFSSL_MSG("Send Cert bad inputSz"); + return BUFFER_E; + } + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, + output + RECORD_HEADER_SZ, + i - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "Certificate"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "Certificate", handshake, output, + sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + } + + if (ret != WANT_WRITE) { + /* Clean up the fragment offset. */ + ssl->fragOffset = 0; + if (ssl->options.side == WOLFSSL_SERVER_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + } + +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->certReqCtx != NULL) { + CertReqCtx* ctx = ssl->certReqCtx; + ssl->certReqCtx = ssl->certReqCtx->next; + XFREE(ctx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + + WOLFSSL_LEAVE("SendTls13Certificate", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_SEND); + + return ret; +} + +typedef struct Scv13Args { + byte* output; /* not allocated */ + byte* verify; /* not allocated */ + word32 idx; + word32 sigLen; + int sendSz; + word16 length; + + byte sigAlgo; + byte* sigData; + word16 sigDataSz; +} Scv13Args; + +static void FreeScv13Args(WOLFSSL* ssl, void* pArgs) +{ + Scv13Args* args = (Scv13Args*)pArgs; + + (void)ssl; + + if (args->sigData) { + XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->sigData = NULL; + } +} + +/* handle generation TLS v1.3 certificate_verify (15) */ +/* Send the TLS v1.3 CertificateVerify message. + * A hash of all the message so far is used. + * The signed data is: + * 0x20 * 64 | context string | 0x00 | hash of messages + * This message is always encrypted in TLS v1.3. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13CertificateVerify(WOLFSSL* ssl) +{ + int ret = 0; + buffer* sig = &ssl->buffers.sig; +#ifdef WOLFSSL_ASYNC_CRYPT + Scv13Args* args = (Scv13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + Scv13Args args[1]; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND); + WOLFSSL_ENTER("SendTls13CertificateVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_scv; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(Scv13Args)); + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeScv13Args; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + return 0; /* sent blank cert, can't verify */ + } + + args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA; + /* Always encrypted. */ + args->sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_scv; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + /* idx is used to track verify pointer offset to output */ + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->verify = + &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; + + if (ssl->buffers.key == NULL) { + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) + args->length = GetPrivateKeySigSize(ssl); + else + #endif + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + else { + ret = DecodePrivateKey(ssl, &args->length); + if (ret != 0) + goto exit_scv; + } + + if (args->length <= 0) { + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + + /* Add signature algorithm. */ + if (ssl->hsType == DYNAMIC_TYPE_RSA) + args->sigAlgo = rsa_pss_sa_algo; + else if (ssl->hsType == DYNAMIC_TYPE_ECC) + args->sigAlgo = ecc_dsa_sa_algo; + #ifdef HAVE_ED25519 + else if (ssl->hsType == DYNAMIC_TYPE_ED25519) + args->sigAlgo = ed25519_sa_algo; + #endif + #ifdef HAVE_ED448 + else if (ssl->hsType == DYNAMIC_TYPE_ED448) + args->sigAlgo = ed448_sa_algo; + #endif + EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify); + + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + int sigLen = MAX_SIG_DATA_SZ; + if (args->length > MAX_SIG_DATA_SZ) + sigLen = args->length; + args->sigData = (byte*)XMALLOC(sigLen, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + } + else { + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + } + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + /* Create the data to be signed. */ + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); + if (ret != 0) + goto exit_scv; + + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + /* build encoded signature buffer */ + sig->length = WC_MAX_DIGEST_SIZE; + sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (sig->buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + ret = CreateRSAEncodedSig(sig->buffer, args->sigData, + args->sigDataSz, args->sigAlgo, ssl->suites->hashAlgo); + if (ret < 0) + goto exit_scv; + sig->length = ret; + ret = 0; + + /* Maximum size of RSA Signature. */ + args->sigLen = args->length; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) { + sig->length = args->sendSz - args->idx - HASH_SIG_SIZE - + VERIFY_HEADER; + ret = CreateECCEncodedSig(args->sigData, + args->sigDataSz, ssl->suites->hashAlgo); + if (ret < 0) + goto exit_scv; + args->sigDataSz = (word16)ret; + ret = 0; + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ret = Ed25519CheckPubKey(ssl); + if (ret < 0) { + ERROR_OUT(ret, exit_scv); + } + sig->length = ED25519_SIG_SIZE; + } + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ret = Ed448CheckPubKey(ssl); + if (ret < 0) { + ERROR_OUT(ret, exit_scv); + } + sig->length = ED448_SIG_SIZE; + } + #endif /* HAVE_ED448 */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) { + + ret = EccSign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ecc_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->hsType == DYNAMIC_TYPE_ED25519) { + ret = Ed25519Sign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ed25519_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; + } + #endif + #ifdef HAVE_ED448 + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ret = Ed448Sign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ed448_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; + } + #endif + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + ret = RsaSign(ssl, sig->buffer, (word32)sig->length, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigLen, + args->sigAlgo, ssl->suites->hashAlgo, + (RsaKey*)ssl->hsKey, + ssl->buffers.key + ); + if (ret == 0) { + args->length = (word16)args->sigLen; + + XMEMCPY(args->sigData, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + args->sigLen); + } + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Add signature length. */ + c16toa(args->length, args->verify + HASH_SIG_SIZE); + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + /* check for signature faults */ + ret = VerifyRsaSign(ssl, args->sigData, args->sigLen, + sig->buffer, (word32)sig->length, args->sigAlgo, + ssl->suites->hashAlgo, (RsaKey*)ssl->hsKey, + ssl->buffers.key + ); + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + /* Put the record and handshake headers on. */ + AddTls13Headers(args->output, args->length + HASH_SIG_SIZE + + VERIFY_HEADER, certificate_verify, ssl); + + args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + + args->length + HASH_SIG_SIZE + VERIFY_HEADER; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + FALL_THROUGH; + + case TLS_ASYNC_END: + { + /* This message is always encrypted. */ + ret = BuildTls13Message(ssl, args->output, + MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, + args->output + RECORD_HEADER_SZ, + args->sendSz - RECORD_HEADER_SZ, handshake, + 1, 0, 0); + + if (ret < 0) { + goto exit_scv; + } + else { + args->sendSz = ret; + ret = 0; + } + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName(ssl, "CertificateVerify"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "CertificateVerify", handshake, + args->output, args->sendSz, WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += args->sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_scv: + + WOLFSSL_LEAVE("SendTls13CertificateVerify", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + return ret; + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Final cleanup */ + FreeScv13Args(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} + +/* handle processing TLS v1.3 certificate (11) */ +/* Parse and handle a TLS v1.3 Certificate message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Certificate. + * On exit, the index of byte after the Certificate message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret; + + WOLFSSL_START(WC_FUNC_CERTIFICATE_DO); + WOLFSSL_ENTER("DoTls13Certificate"); + + ret = ProcessPeerCerts(ssl, input, inOutIdx, totalSz); + if (ret == 0) { +#if !defined(NO_WOLFSSL_CLIENT) + if (ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; +#endif +#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->options.acceptState = TICKET_SENT; + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + } +#endif + } + + WOLFSSL_LEAVE("DoTls13Certificate", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_DO); + + return ret; +} + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + +typedef struct Dcv13Args { + byte* output; /* not allocated */ + word32 sendSz; + word16 sz; + word32 sigSz; + word32 idx; + word32 begin; + byte hashAlgo; + byte sigAlgo; + + byte* sigData; + word16 sigDataSz; +} Dcv13Args; + +static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) +{ + Dcv13Args* args = (Dcv13Args*)pArgs; + + if (args->sigData != NULL) { + XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->sigData = NULL; + } + + (void)ssl; +} + +/* handle processing TLS v1.3 certificate_verify (15) */ +/* Parse and handle a TLS v1.3 CertificateVerify message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * CertificateVerify. + * On exit, the index of byte after the CertificateVerify message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret = 0; + buffer* sig = &ssl->buffers.sig; +#ifdef WOLFSSL_ASYNC_CRYPT + Dcv13Args* args = (Dcv13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + Dcv13Args args[1]; +#endif + + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_DO); + WOLFSSL_ENTER("DoTls13CertificateVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_dcv; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(Dcv13Args)); + args->hashAlgo = sha_mac; + args->sigAlgo = anonymous_sa_algo; + args->idx = *inOutIdx; + args->begin = *inOutIdx; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeDcv13Args; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateVerify"); + if (ssl->toInfoOn) AddLateName("CertificateVerify", + &ssl->timeoutInfo); + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + FALL_THROUGH; + + case TLS_ASYNC_BUILD: + { + /* Signature algorithm. */ + if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + ret = DecodeTls13SigAlg(input + args->idx, &args->hashAlgo, + &args->sigAlgo); + if (ret < 0) + goto exit_dcv; + args->idx += OPAQUE16_LEN; + + /* Signature length. */ + if ((args->idx - args->begin) + OPAQUE16_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + ato16(input + args->idx, &args->sz); + args->idx += OPAQUE16_LEN; + + /* Signature data. */ + if ((args->idx - args->begin) + args->sz > totalSz || + args->sz > ENCRYPT_LEN) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + + /* Check for public key of required type. */ + #ifdef HAVE_ED25519 + if (args->sigAlgo == ed25519_sa_algo && + !ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Oops, peer sent ED25519 key but not in verify"); + } + #endif + #ifdef HAVE_ED448 + if (args->sigAlgo == ed448_sa_algo && !ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Oops, peer sent ED448 key but not in verify"); + } + #endif + #ifdef HAVE_ECC + if (args->sigAlgo == ecc_dsa_sa_algo && + !ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); + } + #endif + #ifndef NO_RSA + if (args->sigAlgo == rsa_sa_algo) { + WOLFSSL_MSG("Oops, peer sent PKCS#1.5 signature"); + ERROR_OUT(INVALID_PARAMETER, exit_dcv); + } + if (args->sigAlgo == rsa_pss_sa_algo && + (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { + WOLFSSL_MSG("Oops, peer sent RSA key but not in verify"); + } + #endif + + sig->buffer = (byte*)XMALLOC(args->sz, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (sig->buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + sig->length = args->sz; + XMEMCPY(sig->buffer, input + args->idx, args->sz); + + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Doing ECC peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + if (ret != 0) + goto exit_dcv; + ret = CreateECCEncodedSig(args->sigData, + args->sigDataSz, args->hashAlgo); + if (ret < 0) + goto exit_dcv; + args->sigDataSz = (word16)ret; + ret = 0; + } + #endif + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = 0; + } + #endif + #ifdef HAVE_ED448 + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = 0; + } + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + FALL_THROUGH; + + case TLS_ASYNC_DO: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + WOLFSSL_MSG("Doing RSA peer cert verify"); + + ret = RsaVerify(ssl, sig->buffer, (word32)sig->length, &args->output, + args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerRsaKey + #else + NULL + #endif + ); + if (ret >= 0) { + args->sendSz = ret; + ret = 0; + } + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Doing ECC peer cert verify"); + + ret = EccVerify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEccDsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEccDsaKey + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + } + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + if (ssl->peerEd25519KeyPresent) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + + ret = Ed25519Verify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEd25519Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd25519Key + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ED25519, + (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + } + } + #endif + #ifdef HAVE_ED448 + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + + ret = Ed448Verify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEd448Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd448Key + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ED448, + (void**)&ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; + } + } + #endif + + /* Check for error */ + if (ret != 0) { + goto exit_dcv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + FALL_THROUGH; + + case TLS_ASYNC_VERIFY: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + ret = CheckRSASignature(ssl, args->sigAlgo, args->hashAlgo, + args->output, args->sendSz); + if (ret != 0) + goto exit_dcv; + + FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; + } + #endif /* !NO_RSA */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + FALL_THROUGH; + + case TLS_ASYNC_FINALIZE: + { + ssl->options.havePeerVerify = 1; + + /* Set final index */ + args->idx += args->sz; + *inOutIdx = args->idx; + + /* Encryption is always on: add padding */ + *inOutIdx += ssl->keys.padSz; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + + case TLS_ASYNC_END: + { + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_dcv: + + WOLFSSL_LEAVE("DoTls13CertificateVerify", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_DO); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + /* Mark message as not received so it can process again */ + ssl->msgsReceived.got_certificate_verify = 0; + + return ret; + } + else +#endif /* WOLFSSL_ASYNC_CRYPT */ + if (ret != 0 && ret != INVALID_PARAMETER) + SendAlert(ssl, alert_fatal, decrypt_error); + + /* Final cleanup */ + FreeDcv13Args(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} +#endif /* !NO_RSA || HAVE_ECC */ + +/* Parse and handle a TLS v1.3 Finished message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * size Length of message data. + * totalSz Length of remaining data in the message buffer. + * sniff Indicates whether we are sniffing packets. + * returns 0 on success and otherwise failure. + */ +static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz, int sniff) +{ + int ret; + word32 finishedSz = 0; + byte* secret; + byte mac[WC_MAX_DIGEST_SIZE]; + + WOLFSSL_START(WC_FUNC_FINISHED_DO); + WOLFSSL_ENTER("DoTls13Finished"); + + /* check against totalSz */ + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return BUFFER_E; + + if (ssl->options.handShakeDone) { + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.client_write_MAC_secret; + } + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* All the handshake messages have been received to calculate + * client and server finished keys. + */ + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + ret = DeriveFinishedSecret(ssl, ssl->serverSecret, + ssl->keys.server_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.server_write_MAC_secret; + } + else + secret = ssl->keys.client_write_MAC_secret; + + ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz); + if (ret != 0) + return ret; + if (size != finishedSz) + return BUFFER_ERROR; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); + #endif + + if (sniff == NO_SNIFF) { + /* Actually check verify data. */ + if (XMEMCMP(input + *inOutIdx, mac, size) != 0){ + WOLFSSL_MSG("Verify finished error on hashes"); + SendAlert(ssl, alert_fatal, decrypt_error); + return VERIFY_FINISHED_ERROR; + } + } + + /* Force input exhaustion at ProcessReply by consuming padSz. */ + *inOutIdx += size + ssl->keys.padSz; + + if (ssl->options.side == WOLFSSL_SERVER_END && + !ssl->options.handShakeDone) { +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + if ((ret = DeriveTls13Keys(ssl, no_key, DECRYPT_SIDE_ONLY, 1)) != 0) + return ret; + } +#endif + /* Setup keys for application data messages from client. */ + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + } + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_FINISHED_COMPLETE; +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } +#endif + + WOLFSSL_LEAVE("DoTls13Finished", 0); + WOLFSSL_END(WC_FUNC_FINISHED_DO); + + return 0; +} +#endif /* NO_CERTS */ + +/* Send the TLS v1.3 Finished message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13Finished(WOLFSSL* ssl) +{ + int sendSz; + int finishedSz = ssl->specs.hash_size; + byte* input; + byte* output; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + byte* secret; + + WOLFSSL_START(WC_FUNC_FINISHED_SEND); + WOLFSSL_ENTER("SendTls13Finished"); + + outputSz = WC_MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA; + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + input = output + RECORD_HEADER_SZ; + + AddTls13HandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl); + + /* make finished hashes */ + if (ssl->options.handShakeDone) { + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.client_write_MAC_secret; + } + else if (ssl->options.side == WOLFSSL_CLIENT_END) + secret = ssl->keys.client_write_MAC_secret; + else { + /* All the handshake messages have been done to calculate client and + * server finished keys. + */ + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + ret = DeriveFinishedSecret(ssl, ssl->serverSecret, + ssl->keys.server_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.server_write_MAC_secret; + } + ret = BuildTls13HandshakeHmac(ssl, secret, &input[headerSz], NULL); + if (ret != 0) + return ret; + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, outputSz, input, + headerSz + finishedSz, handshake, 1, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + +#ifndef NO_SESSION_CACHE + if (!ssl->options.resuming && (ssl->options.side == WOLFSSL_SERVER_END || + (ssl->options.side == WOLFSSL_SERVER_END && ssl->arrays != NULL))) { + AddSession(ssl); /* just try */ + } +#endif + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "Finished", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Can send application data now. */ + if ((ret = DeriveMasterSecret(ssl)) != 0) + return ret; +#ifdef WOLFSSL_EARLY_DATA + if ((ret = DeriveTls13Keys(ssl, traffic_key, ENCRYPT_SIDE_ONLY, 1)) + != 0) { + return ret; + } + if ((ret = DeriveTls13Keys(ssl, traffic_key, DECRYPT_SIDE_ONLY, + ssl->earlyData == no_early_data)) != 0) { + return ret; + } +#else + if ((ret = DeriveTls13Keys(ssl, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, + 1)) != 0) { + return ret; + } +#endif + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && + !ssl->options.handShakeDone) { +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + if ((ret = DeriveTls13Keys(ssl, no_key, ENCRYPT_AND_DECRYPT_SIDE, + 1)) != 0) { + return ret; + } + } +#endif + /* Setup keys for application data messages. */ + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); + if (ret != 0) + return ret; +#endif + } + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + } +#endif + + if ((ret = SendBuffered(ssl)) != 0) + return ret; + + WOLFSSL_LEAVE("SendTls13Finished", ret); + WOLFSSL_END(WC_FUNC_FINISHED_SEND); + + return ret; +} + +/* handle generation TLS v1.3 key_update (24) */ +/* Send the TLS v1.3 KeyUpdate message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13KeyUpdate(WOLFSSL* ssl) +{ + int sendSz; + byte* input; + byte* output; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + WOLFSSL_START(WC_FUNC_KEY_UPDATE_SEND); + WOLFSSL_ENTER("SendTls13KeyUpdate"); + + outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA; + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + input = output + RECORD_HEADER_SZ; + + AddTls13Headers(output, OPAQUE8_LEN, key_update, ssl); + + /* If: + * 1. I haven't sent a KeyUpdate requesting a response and + * 2. This isn't responding to peer KeyUpdate requiring a response then, + * I want a response. + */ + ssl->keys.updateResponseReq = output[i++] = + !ssl->keys.updateResponseReq && !ssl->keys.keyUpdateRespond; + /* Sent response, no longer need to respond. */ + ssl->keys.keyUpdateRespond = 0; + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, outputSz, input, + headerSz + OPAQUE8_LEN, handshake, 0, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "KeyUpdate"); + if (ssl->toInfoOn) { + AddPacketInfo(ssl, "KeyUpdate", handshake, output, sendSz, + WRITE_PROTO, ssl->heap); + } + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + if (ret != 0 && ret != WANT_WRITE) + return ret; + + /* Future traffic uses new encryption keys. */ + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY, 1)) + != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + + WOLFSSL_LEAVE("SendTls13KeyUpdate", ret); + WOLFSSL_END(WC_FUNC_KEY_UPDATE_SEND); + + return ret; +} + +/* handle processing TLS v1.3 key_update (24) */ +/* Parse and handle a TLS v1.3 KeyUpdate message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret; + word32 i = *inOutIdx; + + WOLFSSL_START(WC_FUNC_KEY_UPDATE_DO); + WOLFSSL_ENTER("DoTls13KeyUpdate"); + + /* check against totalSz */ + if (OPAQUE8_LEN != totalSz) + return BUFFER_E; + + switch (input[i]) { + case update_not_requested: + /* This message in response to any outstanding request. */ + ssl->keys.keyUpdateRespond = 0; + ssl->keys.updateResponseReq = 0; + break; + case update_requested: + /* New key update requiring a response. */ + ssl->keys.keyUpdateRespond = 1; + break; + default: + return INVALID_PARAMETER; + } + + /* Move index to byte after message. */ + *inOutIdx += totalSz; + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + /* Future traffic uses new decryption keys. */ + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, DECRYPT_SIDE_ONLY, 1)) + != 0) { + return ret; + } + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + if (ssl->keys.keyUpdateRespond) + return SendTls13KeyUpdate(ssl); + + WOLFSSL_LEAVE("DoTls13KeyUpdate", ret); + WOLFSSL_END(WC_FUNC_KEY_UPDATE_DO); + + return 0; +} + +#ifdef WOLFSSL_EARLY_DATA +#ifndef NO_WOLFSSL_CLIENT +/* Send the TLS v1.3 EndOfEarlyData message to indicate that there will be no + * more early application data. + * The encryption key now changes to the pre-calculated handshake key. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +static int SendTls13EndOfEarlyData(WOLFSSL* ssl) +{ + byte* output; + int ret; + int sendSz; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + WOLFSSL_START(WC_FUNC_END_OF_EARLY_DATA_SEND); + WOLFSSL_ENTER("SendTls13EndOfEarlyData"); + + length = 0; + sendSz = idx + length + MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, end_of_early_data, ssl); + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 1, 0, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); + WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_SEND); + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER +/* handle processing of TLS 1.3 end_of_early_data (5) */ +/* Parse the TLS v1.3 EndOfEarlyData message that indicates that there will be + * no more early application data. + * The decryption key now changes to the pre-calculated handshake key. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +static int DoTls13EndOfEarlyData(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ + int ret; + word32 begin = *inOutIdx; + + (void)input; + + WOLFSSL_START(WC_FUNC_END_OF_EARLY_DATA_DO); + WOLFSSL_ENTER("DoTls13EndOfEarlyData"); + + if ((*inOutIdx - begin) != size) + return BUFFER_ERROR; + + if (ssl->earlyData == no_early_data) { + WOLFSSL_MSG("EndOfEarlyData received unexpectedly"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + ssl->earlyData = done_early_data; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY); + + WOLFSSL_LEAVE("DoTls13EndOfEarlyData", ret); + WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_DO); + + return ret; +} +#endif /* !NO_WOLFSSL_SERVER */ +#endif /* WOLFSSL_EARLY_DATA */ + +#ifndef NO_WOLFSSL_CLIENT +/* Handle a New Session Ticket handshake message. + * Message contains the information required to perform resumption. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * size The length of the current handshake message. + * returns 0 on success, otherwise failure. + */ +static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ +#ifdef HAVE_SESSION_TICKET + int ret; + word32 begin = *inOutIdx; + word32 lifetime; + word32 ageAdd; + word16 length; + word32 now; +#ifndef WOLFSSL_TLS13_DRAFT_18 + const byte* nonce; + byte nonceLength; +#endif + + WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO); + WOLFSSL_ENTER("DoTls13NewSessionTicket"); + + /* Lifetime hint. */ + if ((*inOutIdx - begin) + SESSION_HINT_SZ > size) + return BUFFER_ERROR; + ato32(input + *inOutIdx, &lifetime); + *inOutIdx += SESSION_HINT_SZ; + if (lifetime > MAX_LIFETIME) + return SERVER_HINT_ERROR; + + /* Age add. */ + if ((*inOutIdx - begin) + SESSION_ADD_SZ > size) + return BUFFER_ERROR; + ato32(input + *inOutIdx, &ageAdd); + *inOutIdx += SESSION_ADD_SZ; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Ticket nonce. */ + if ((*inOutIdx - begin) + 1 > size) + return BUFFER_ERROR; + nonceLength = input[*inOutIdx]; + if (nonceLength > MAX_TICKET_NONCE_SZ) { + WOLFSSL_MSG("Nonce length not supported"); + return INVALID_PARAMETER; + } + *inOutIdx += 1; + if ((*inOutIdx - begin) + nonceLength > size) + return BUFFER_ERROR; + nonce = input + *inOutIdx; + *inOutIdx += nonceLength; +#endif + + /* Ticket length. */ + if ((*inOutIdx - begin) + LENGTH_SZ > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &length); + *inOutIdx += LENGTH_SZ; + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + if ((ret = SetTicket(ssl, input + *inOutIdx, length)) != 0) + return ret; + *inOutIdx += length; + + now = TimeNowInMilliseconds(); + if (now == (word32)GETTIME_ERROR) + return now; + /* Copy in ticket data (server identity). */ + ssl->timeout = lifetime; + ssl->session.timeout = lifetime; + ssl->session.cipherSuite0 = ssl->options.cipherSuite0; + ssl->session.cipherSuite = ssl->options.cipherSuite; + ssl->session.ticketSeen = now; + ssl->session.ticketAdd = ageAdd; + #ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + #endif +#ifndef WOLFSSL_TLS13_DRAFT_18 + ssl->session.ticketNonce.len = nonceLength; + if (nonceLength > 0) + XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength); +#endif + ssl->session.namedGroup = ssl->namedGroup; + + if ((*inOutIdx - begin) + EXTS_SZ > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &length); + *inOutIdx += EXTS_SZ; + if ((*inOutIdx - begin) + length != size) + return BUFFER_ERROR; + #ifdef WOLFSSL_EARLY_DATA + ret = TLSX_Parse(ssl, (byte *)input + (*inOutIdx), length, session_ticket, + NULL); + if (ret != 0) + return ret; + #endif + *inOutIdx += length; + + #ifndef NO_SESSION_CACHE + AddSession(ssl); + #endif + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + ssl->expect_session_ticket = 0; +#else + (void)ssl; + (void)input; + + WOLFSSL_ENTER("DoTls13NewSessionTicket"); + + *inOutIdx += size + ssl->keys.padSz; +#endif /* HAVE_SESSION_TICKET */ + + WOLFSSL_LEAVE("DoTls13NewSessionTicket", 0); + WOLFSSL_END(WC_FUNC_NEW_SESSION_TICKET_DO); + + return 0; +} +#endif /* NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER + #ifdef HAVE_SESSION_TICKET + +#ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED +/* Offset of the MAC size in the finished message. */ +#define FINISHED_MSG_SIZE_OFFSET 3 + +/* Calculate the resumption secret which includes the unseen client finished + * message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int ExpectedResumptionSecret(WOLFSSL* ssl) +{ + int ret; + word32 finishedSz = 0; + byte mac[WC_MAX_DIGEST_SIZE]; + Digest digest; + static byte header[] = { 0x14, 0x00, 0x00, 0x00 }; + + /* Copy the running hash so we can restore it after. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + ret = wc_Sha256Copy(&ssl->hsHashes->hashSha256, &digest.sha256); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_Sha384Copy(&ssl->hsHashes->hashSha384, &digest.sha384); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + ret = wc_Sha512Copy(&ssl->hsHashes->hashSha512, &digest.sha512); + if (ret != 0) + return ret; + break; + #endif + } + + /* Generate the Client's Finished message and hash it. */ + ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret, mac, + &finishedSz); + if (ret != 0) + return ret; + header[FINISHED_MSG_SIZE_OFFSET] = finishedSz; +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 }; + ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData)); + if (ret != 0) + return ret; + } +#endif + if ((ret = HashInputRaw(ssl, header, sizeof(header))) != 0) + return ret; + if ((ret = HashInputRaw(ssl, mac, finishedSz)) != 0) + return ret; + + if ((ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret)) != 0) + return ret; + + /* Restore the hash inline with currently seen messages. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + ret = wc_Sha256Copy(&digest.sha256, &ssl->hsHashes->hashSha256); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + ret = wc_Sha384Copy(&digest.sha384, &ssl->hsHashes->hashSha384); + if (ret != 0) + return ret; + break; + #endif + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + ret = wc_Sha512Copy(&digest.sha512, &ssl->hsHashes->hashSha384); + if (ret != 0) + return ret; + break; + #endif + } + + return ret; +} +#endif + +/* Send New Session Ticket handshake message. + * Message contains the information required to perform resumption. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13NewSessionTicket(WOLFSSL* ssl) +{ + byte* output; + int ret; + int sendSz; + word16 extSz; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_SEND); + WOLFSSL_ENTER("SendTls13NewSessionTicket"); + +#ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->msgsReceived.got_finished) { + if ((ret = ExpectedResumptionSecret(ssl)) != 0) + return ret; + } +#endif + +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Start ticket nonce at 0 and go up to 255. */ + if (ssl->session.ticketNonce.len == 0) { + ssl->session.ticketNonce.len = DEF_TICKET_NONCE_SZ; + ssl->session.ticketNonce.data[0] = 0; + } + else + ssl->session.ticketNonce.data[0]++; +#endif + + if (!ssl->options.noTicketTls13) { + if ((ret = CreateTicket(ssl)) != 0) + return ret; + } + +#ifdef WOLFSSL_EARLY_DATA + ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz; + if (ssl->session.maxEarlyDataSz > 0) + TLSX_EarlyData_Use(ssl, ssl->session.maxEarlyDataSz); + extSz = 0; + ret = TLSX_GetResponseSize(ssl, session_ticket, &extSz); + if (ret != 0) + return ret; +#else + extSz = EXTS_SZ; +#endif + + /* Lifetime | Age Add | Ticket | Extensions */ + length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ + + ssl->session.ticketLen + extSz; +#ifndef WOLFSSL_TLS13_DRAFT_18 + /* Nonce */ + length += TICKET_NONCE_LEN_SZ + DEF_TICKET_NONCE_SZ; +#endif + sendSz = idx + length + MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, session_ticket, ssl); + + /* Lifetime hint */ + c32toa(ssl->ctx->ticketHint, output + idx); + idx += SESSION_HINT_SZ; + /* Age add - obfuscator */ + c32toa(ssl->session.ticketAdd, output + idx); + idx += SESSION_ADD_SZ; + +#ifndef WOLFSSL_TLS13_DRAFT_18 + output[idx++] = ssl->session.ticketNonce.len; + output[idx++] = ssl->session.ticketNonce.data[0]; +#endif + + /* length */ + c16toa(ssl->session.ticketLen, output + idx); + idx += LENGTH_SZ; + /* ticket */ + XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen); + idx += ssl->session.ticketLen; + +#ifdef WOLFSSL_EARLY_DATA + extSz = 0; + ret = TLSX_WriteResponse(ssl, output + idx, session_ticket, &extSz); + if (ret != 0) + return ret; + idx += extSz; +#else + /* No extension support - empty extensions. */ + c16toa(0, output + idx); + idx += EXTS_SZ; +#endif + + ssl->options.haveSessionId = 1; + +#ifndef NO_SESSION_CACHE + AddSession(ssl); +#endif + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 0, 0, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + + WOLFSSL_LEAVE("SendTls13NewSessionTicket", 0); + WOLFSSL_END(WC_FUNC_NEW_SESSION_TICKET_SEND); + + return ret; +} + #endif /* HAVE_SESSION_TICKET */ +#endif /* NO_WOLFSSL_SERVER */ + +/* Make sure no duplicates, no fast forward, or other problems + * + * ssl The SSL/TLS object. + * type Type of handshake message received. + * returns 0 on success, otherwise failure. + */ +static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) +{ + /* verify not a duplicate, mark received, check state */ + switch (type) { + +#ifndef NO_WOLFSSL_SERVER + case client_hello: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_MSG("ClientHello received by client"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState >= CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("ClientHello received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_client_hello == 2) { + WOLFSSL_MSG("Too many ClientHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_client_hello++; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case server_hello: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("ServerHello received by server"); + return OUT_OF_ORDER_E; + } + #endif + #ifdef WOLFSSL_TLS13_DRAFT_18 + if (ssl->msgsReceived.got_server_hello) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello = 1; + #else + if (ssl->msgsReceived.got_server_hello == 2) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello++; + #endif + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case session_ticket: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("NewSessionTicket received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("NewSessionTicket received out of order"); + return OUT_OF_ORDER_E; + } + ssl->msgsReceived.got_session_ticket = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_SERVER + #ifdef WOLFSSL_EARLY_DATA + case end_of_early_data: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_MSG("EndOfEarlyData received by client"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("EndOfEarlyData received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState >= CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("EndOfEarlyData received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_end_of_early_data == 1) { + WOLFSSL_MSG("Too many EndOfEarlyData received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_end_of_early_data++; + + break; + #endif +#endif + +#ifdef WOLFSSL_TLS13_DRAFT_18 + #ifndef NO_WOLFSSL_CLIENT + case hello_retry_request: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("HelloRetryRequest received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState > CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("HelloRetryRequest received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_hello_retry_request) { + WOLFSSL_MSG("Duplicate HelloRetryRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_hello_retry_request = 1; + + break; + #endif +#endif + +#ifndef NO_WOLFSSL_CLIENT + case encrypted_extensions: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("EncryptedExtensions received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.serverState != SERVER_HELLO_COMPLETE) { + WOLFSSL_MSG("EncryptedExtensions received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->msgsReceived.got_encrypted_extensions) { + WOLFSSL_MSG("Duplicate EncryptedExtensions received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_encrypted_extensions = 1; + + break; +#endif + + case certificate: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("Certificate received out of order - Client"); + return OUT_OF_ORDER_E; + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == SERVER_CERT_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("Certificate received while using PSK"); + return SANITY_MSG_E; + } + #endif + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("Certificate received out of order - Server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("Duplicate Certificate received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate = 1; + + break; + +#ifndef NO_WOLFSSL_CLIENT + case certificate_request: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("CertificateRequest received by server"); + return OUT_OF_ORDER_E; + } + #endif + #ifndef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("CertificateRequest received out of order"); + return OUT_OF_ORDER_E; + } + #else + if (ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && + (ssl->options.serverState != SERVER_FINISHED_COMPLETE || + ssl->options.clientState != CLIENT_FINISHED_COMPLETE)) { + WOLFSSL_MSG("CertificateRequest received out of order"); + return OUT_OF_ORDER_E; + } + #endif + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.serverState == + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("CertificateRequset received while using PSK"); + return SANITY_MSG_E; + } + #endif + #ifndef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->msgsReceived.got_certificate_request) { + WOLFSSL_MSG("Duplicate CertificateRequest received"); + return DUPLICATE_MSG_E; + } + #endif + ssl->msgsReceived.got_certificate_request = 1; + + break; +#endif + + case certificate_verify: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.serverState != SERVER_CERT_COMPLETE) { + WOLFSSL_MSG("No Cert before CertVerify"); + return OUT_OF_ORDER_E; + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.serverState == SERVER_CERT_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("CertificateVerify received while using PSK"); + return SANITY_MSG_E; + } + #endif + } + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("CertificateVerify received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("CertificateVerify before ClientHello done"); + return OUT_OF_ORDER_E; + } + if (!ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("No Cert before CertificateVerify"); + return OUT_OF_ORDER_E; + } + } + #endif + if (ssl->msgsReceived.got_certificate_verify) { + WOLFSSL_MSG("Duplicate CertificateVerify received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate_verify = 1; + + break; + + case finished: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.serverState < + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + } + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData == process_early_data) { + return OUT_OF_ORDER_E; + } + #endif + } + #endif + if (ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("Duplicate Finished received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_finished = 1; + + break; + + case key_update: + if (!ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("No KeyUpdate before Finished"); + return OUT_OF_ORDER_E; + } + break; + + default: + WOLFSSL_MSG("Unknown message type"); + return SANITY_MSG_E; + } + + return 0; +} + +/* Handle a type of handshake message that has been received. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the buffer of the current message. + * On exit, the index into the buffer of the next message. + * size The length of the current handshake message. + * totalSz Length of remaining data in the message buffer. + * returns 0 on success and otherwise failure. + */ +int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, + byte type, word32 size, word32 totalSz) +{ + int ret = 0; + word32 inIdx = *inOutIdx; + + (void)totalSz; + + WOLFSSL_ENTER("DoTls13HandShakeMsgType"); + + /* make sure we can read the message */ + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + + /* sanity check msg received */ + if ((ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) { + WOLFSSL_MSG("Sanity Check on handshake message type received failed"); + SendAlert(ssl, alert_fatal, unexpected_message); + return ret; + } + +#ifdef WOLFSSL_CALLBACKS + /* add name later, add on record and handshake header part back on */ + if (ssl->toInfoOn) { + int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + AddPacketInfo(ssl, 0, handshake, input + *inOutIdx - add, + size + add, READ_PROTO, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } +#endif + + if (ssl->options.handShakeState == HANDSHAKE_DONE && + type != session_ticket && type != certificate_request && + type != certificate && type != key_update) { + WOLFSSL_MSG("HandShake message after handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == NULL_STATE && + type != server_hello && type != hello_retry_request) { + WOLFSSL_MSG("First server message not server hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.clientState == NULL_STATE && type != client_hello) { + WOLFSSL_MSG("First client message not client hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + /* above checks handshake state */ + switch (type) { +#ifndef NO_WOLFSSL_CLIENT + /* Messages only received by client. */ + #ifdef WOLFSSL_TLS13_DRAFT_18 + case hello_retry_request: + WOLFSSL_MSG("processing hello retry request"); + ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size); + break; + #endif + + case server_hello: + WOLFSSL_MSG("processing server hello"); + ret = DoTls13ServerHello(ssl, input, inOutIdx, size, &type); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) || + IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.cacheMessages = 0; + if (ssl->hsHashes->messages != NULL) { + XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } + } + #endif + break; + + case encrypted_extensions: + WOLFSSL_MSG("processing encrypted extensions"); + ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size); + break; + + #ifndef NO_CERTS + case certificate_request: + WOLFSSL_MSG("processing certificate request"); + ret = DoTls13CertificateRequest(ssl, input, inOutIdx, size); + break; + #endif + + case session_ticket: + WOLFSSL_MSG("processing new session ticket"); + ret = DoTls13NewSessionTicket(ssl, input, inOutIdx, size); + break; +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER + /* Messages only received by server. */ + case client_hello: + WOLFSSL_MSG("processing client hello"); + ret = DoTls13ClientHello(ssl, input, inOutIdx, size); + break; + + #ifdef WOLFSSL_EARLY_DATA + case end_of_early_data: + WOLFSSL_MSG("processing end of early data"); + ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size); + break; + #endif +#endif /* !NO_WOLFSSL_SERVER */ + + /* Messages received by both client and server. */ +#ifndef NO_CERTS + case certificate: + WOLFSSL_MSG("processing certificate"); + ret = DoTls13Certificate(ssl, input, inOutIdx, size); + break; +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) + case certificate_verify: + WOLFSSL_MSG("processing certificate verify"); + ret = DoTls13CertificateVerify(ssl, input, inOutIdx, size); + break; +#endif /* !NO_RSA || HAVE_ECC */ + + case finished: + WOLFSSL_MSG("processing finished"); + ret = DoTls13Finished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); + break; + + case key_update: + WOLFSSL_MSG("processing finished"); + ret = DoTls13KeyUpdate(ssl, input, inOutIdx, size); + break; + + default: + WOLFSSL_MSG("Unknown handshake message type"); + ret = UNKNOWN_HANDSHAKE_TYPE; + break; + } + + /* reset error */ + if (ret == 0 && ssl->error == WC_PENDING_E) + ssl->error = 0; + + if (ret == 0 && type != client_hello && type != session_ticket && + type != key_update) { + ret = HashInput(ssl, input + inIdx, size); + } + if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag) { + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + } + + if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA) + SendAlert(ssl, alert_fatal, decode_error); + else if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR || + ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA || + ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + + if (ret == 0 && ssl->options.tls1_3) { + /* Need to hash input message before deriving secrets. */ + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (type == server_hello) { + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + if ((ret = DeriveHandshakeSecret(ssl)) != 0) + return ret; + + if ((ret = DeriveTls13Keys(ssl, handshake_key, + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { + return ret; + } + #ifdef WOLFSSL_EARLY_DATA + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + #else + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + #endif + } + + if (type == finished) { + if ((ret = DeriveMasterSecret(ssl)) != 0) + return ret; + #ifdef WOLFSSL_EARLY_DATA + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE, + ssl->earlyData == no_early_data)) != 0) { + return ret; + } + #else + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { + return ret; + } + #endif + } + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (type == certificate_request && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.connectState = FIRST_REPLY_DONE; + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + + if (wolfSSL_connect_TLSv13(ssl) != SSL_SUCCESS) + ret = POST_HAND_AUTH_ERROR; + } + #endif + } + #endif /* NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.side == WOLFSSL_SERVER_END && type == finished) { + ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); + if (ret != 0) + return ret; + } + #endif +#endif /* NO_WOLFSSL_SERVER */ + } + +#ifdef WOLFSSL_ASYNC_CRYPT + /* if async, offset index so this msg will be processed again */ + if (ret == WC_PENDING_E && *inOutIdx > 0) { + *inOutIdx -= HANDSHAKE_HEADER_SZ; + } +#endif + + WOLFSSL_LEAVE("DoTls13HandShakeMsgType()", ret); + return ret; +} + + +/* Handle a handshake message that has been received. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the buffer of the current message. + * On exit, the index into the buffer of the next message. + * totalSz Length of remaining data in the message buffer. + * returns 0 on success and otherwise failure. + */ +int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret = 0; + word32 inputLength; + + WOLFSSL_ENTER("DoTls13HandShakeMsg()"); + + if (ssl->arrays == NULL) { + byte type; + word32 size; + + if (GetHandshakeHeader(ssl, input, inOutIdx, &type, &size, + totalSz) != 0) { + SendAlert(ssl, alert_fatal, unexpected_message); + return PARSE_ERROR; + } + + return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } + + inputLength = ssl->buffers.inputBuffer.length - *inOutIdx - ssl->keys.padSz; + + /* If there is a pending fragmented handshake message, + * pending message size will be non-zero. */ + if (ssl->arrays->pendingMsgSz == 0) { + byte type; + word32 size; + + if (GetHandshakeHeader(ssl,input, inOutIdx, &type, &size, totalSz) != 0) + return PARSE_ERROR; + + /* Cap the maximum size of a handshake message to something reasonable. + * By default is the maximum size of a certificate message assuming + * nine 2048-bit RSA certificates in the chain. */ + if (size > MAX_HANDSHAKE_SZ) { + WOLFSSL_MSG("Handshake message too large"); + return HANDSHAKE_SIZE_ERROR; + } + + /* size is the size of the certificate message payload */ + if (inputLength - HANDSHAKE_HEADER_SZ < size) { + ssl->arrays->pendingMsgType = type; + ssl->arrays->pendingMsgSz = size + HANDSHAKE_HEADER_SZ; + ssl->arrays->pendingMsg = (byte*)XMALLOC(size + HANDSHAKE_HEADER_SZ, + ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays->pendingMsg == NULL) + return MEMORY_E; + XMEMCPY(ssl->arrays->pendingMsg, + input + *inOutIdx - HANDSHAKE_HEADER_SZ, + inputLength); + ssl->arrays->pendingMsgOffset = inputLength; + *inOutIdx += inputLength + ssl->keys.padSz - HANDSHAKE_HEADER_SZ; + return 0; + } + + ret = DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } + else { + if (inputLength + ssl->arrays->pendingMsgOffset > + ssl->arrays->pendingMsgSz) { + inputLength = ssl->arrays->pendingMsgSz - + ssl->arrays->pendingMsgOffset; + } + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, + input + *inOutIdx, inputLength); + ssl->arrays->pendingMsgOffset += inputLength; + *inOutIdx += inputLength + ssl->keys.padSz; + + if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz) + { + word32 idx = 0; + ret = DoTls13HandShakeMsgType(ssl, + ssl->arrays->pendingMsg + HANDSHAKE_HEADER_SZ, + &idx, ssl->arrays->pendingMsgType, + ssl->arrays->pendingMsgSz - HANDSHAKE_HEADER_SZ, + ssl->arrays->pendingMsgSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + /* setup to process fragment again */ + ssl->arrays->pendingMsgOffset -= inputLength; + *inOutIdx -= inputLength + ssl->keys.padSz; + } + else + #endif + { + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + ssl->arrays->pendingMsgSz = 0; + } + } + } + + WOLFSSL_LEAVE("DoTls13HandShakeMsg()", ret); + return ret; +} + +#ifndef NO_WOLFSSL_CLIENT + +/* The client connecting to the server. + * The protocol version is expecting to be TLS v1.3. + * If the server downgrades, and older versions of the protocol are compiled + * in, the client will fallback to wolfSSL_connect(). + * Please see note at top of README if you get an error from connect. + * + * ssl The SSL/TLS object. + * returns WOLFSSL_SUCCESS on successful handshake, WOLFSSL_FATAL_ERROR when + * unrecoverable error occurs and 0 otherwise. + * For more error information use wolfSSL_get_error(). + */ +int wolfSSL_connect_TLSv13(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_connect_TLSv13()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl->options.side != WOLFSSL_CLIENT_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return WOLFSSL_FATAL_ERROR; + } + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { + if ((ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.connectState++; + WOLFSSL_MSG("connect state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("connect state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + switch (ssl->options.connectState) { + + case CONNECT_BEGIN: + /* Always send client hello first. */ + if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.connectState = CLIENT_HELLO_SENT; + WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + #endif + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + return WOLFSSL_SUCCESS; + } + #endif + FALL_THROUGH; + + case CLIENT_HELLO_SENT: + /* Get the response/s from the server. */ + while (ssl->options.serverState < + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.connectState = HELLO_AGAIN; + WOLFSSL_MSG("connect state: HELLO_AGAIN"); + FALL_THROUGH; + + case HELLO_AGAIN: + if (ssl->options.certOnly) + return WOLFSSL_SUCCESS; + + if (!ssl->options.tls1_3) { + #ifndef WOLFSSL_NO_TLS12 + if (ssl->options.downgrade) + return wolfSSL_connect(ssl); + #endif + + WOLFSSL_MSG("Client using higher version, fatal error"); + return VERSION_ERROR; + } + + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif + /* Try again with different security parameters. */ + if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.connectState = HELLO_AGAIN_REPLY; + WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); + FALL_THROUGH; + + case HELLO_AGAIN_REPLY: + /* Get the response/s from the server. */ + while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.connectState = FIRST_REPLY_DONE; + WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); + FALL_THROUGH; + + case FIRST_REPLY_DONE: + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: end_of_early_data"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_FIRST; + WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); + FALL_THROUGH; + + case FIRST_REPLY_FIRST: + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif + + ssl->options.connectState = FIRST_REPLY_SECOND; + WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); + FALL_THROUGH; + + case FIRST_REPLY_SECOND: + #ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + ssl->error = SendTls13Certificate(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_THIRD; + WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); + FALL_THROUGH; + + case FIRST_REPLY_THIRD: + #ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + ssl->error = SendTls13CertificateVerify(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate verify"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_FOURTH; + WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH"); + FALL_THROUGH; + + case FIRST_REPLY_FOURTH: + if ((ssl->error = SendTls13Finished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: finished"); + + ssl->options.connectState = FINISHED_DONE; + WOLFSSL_MSG("connect state: FINISHED_DONE"); + FALL_THROUGH; + + case FINISHED_DONE: + #ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb != NULL) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } + #endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + + WOLFSSL_LEAVE("wolfSSL_connect_TLSv13()", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default: + WOLFSSL_MSG("Unknown connect state ERROR"); + return WOLFSSL_FATAL_ERROR; /* unknown connect state */ + } +} +#endif + +#if defined(WOLFSSL_SEND_HRR_COOKIE) +/* Send a cookie with the HelloRetryRequest to avoid storing state. + * + * ssl SSL/TLS object. + * secret Secret to use when generating integrity check for cookie. + * A value of NULL indicates to generate a new random secret. + * secretSz Size of secret data in bytes. + * Use a value of 0 to indicate use of default size. + * returns BAD_FUNC_ARG when ssl is NULL or not using TLS v1.3, SIDE_ERROR when + * called on a client; WOLFSSL_SUCCESS on success and otherwise failure. + */ +int wolfSSL_send_hrr_cookie(WOLFSSL* ssl, const unsigned char* secret, + unsigned int secretSz) +{ + int ret; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + if (secretSz == 0) { + #if !defined(NO_SHA) && defined(NO_SHA256) + secretSz = WC_SHA_DIGEST_SIZE; + #endif /* NO_SHA */ + #ifndef NO_SHA256 + secretSz = WC_SHA256_DIGEST_SIZE; + #endif /* NO_SHA256 */ + } + + if (secretSz != ssl->buffers.tls13CookieSecret.length) { + byte* newSecret; + + if (ssl->buffers.tls13CookieSecret.buffer != NULL) { + ForceZero(ssl->buffers.tls13CookieSecret.buffer, + ssl->buffers.tls13CookieSecret.length); + XFREE(ssl->buffers.tls13CookieSecret.buffer, + ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); + } + + newSecret = (byte*)XMALLOC(secretSz, ssl->heap, + DYNAMIC_TYPE_COOKIE_PWD); + if (newSecret == NULL) { + ssl->buffers.tls13CookieSecret.buffer = NULL; + ssl->buffers.tls13CookieSecret.length = 0; + WOLFSSL_MSG("couldn't allocate new cookie secret"); + return MEMORY_ERROR; + } + ssl->buffers.tls13CookieSecret.buffer = newSecret; + ssl->buffers.tls13CookieSecret.length = secretSz; + } + + /* If the supplied secret is NULL, randomly generate a new secret. */ + if (secret == NULL) { + ret = wc_RNG_GenerateBlock(ssl->rng, + ssl->buffers.tls13CookieSecret.buffer, secretSz); + if (ret < 0) + return ret; + } + else + XMEMCPY(ssl->buffers.tls13CookieSecret.buffer, secret, secretSz); + + ssl->options.sendCookie = 1; + + ret = WOLFSSL_SUCCESS; +#else + (void)secret; + (void)secretSz; + + ret = SIDE_ERROR; +#endif + + return ret; +} +#endif + +/* Create a key share entry from group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * group The named group. + * returns 0 on success, otherwise failure. + */ +int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group) +{ + int ret; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL); + if (ret != 0) + return ret; + + return WOLFSSL_SUCCESS; +} + +/* Send no key share entries - use HelloRetryRequest to negotiate shared group. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int wolfSSL_NoKeyShares(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ret = TLSX_KeyShare_Empty(ssl); + if (ret != 0) + return ret; + + return WOLFSSL_SUCCESS; +} + +/* Do not send a ticket after TLS v1.3 handshake for resumption. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL and 0 on success. + */ +int wolfSSL_CTX_no_ticket_TLSv13(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + +#ifdef HAVE_SESSION_TICKET + ctx->noTicketTls13 = 1; +#endif + + return 0; +} + +/* Do not send a ticket after TLS v1.3 handshake for resumption. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, not using TLS v1.3, or called on + * a client and 0 on success. + */ +int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + +#ifdef HAVE_SESSION_TICKET + ssl->options.noTicketTls13 = 1; +#endif + + return 0; +} + +/* Disallow (EC)DHE key exchange when using pre-shared keys. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL and 0 on success. + */ +int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + + ctx->noPskDheKe = 1; + + return 0; +} + +/* Disallow (EC)DHE key exchange when using pre-shared keys. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3 and 0 on + * success. + */ +int wolfSSL_no_dhe_psk(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + ssl->options.noPskDheKe = 1; + + return 0; +} + +/* Update the keys for encryption and decryption. + * If using non-blocking I/O and WOLFSSL_ERROR_WANT_WRITE is returned then + * calling wolfSSL_write() will have the message sent when ready. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * WOLFSSL_ERROR_WANT_WRITE when non-blocking I/O is not ready to write, + * WOLFSSL_SUCCESS on success and otherwise failure. + */ +int wolfSSL_update_keys(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + ret = SendTls13KeyUpdate(ssl); + if (ret == WANT_WRITE) + ret = WOLFSSL_ERROR_WANT_WRITE; + else if (ret == 0) + ret = WOLFSSL_SUCCESS; + return ret; +} + +#if !defined(NO_CERTS) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* Allow post-handshake authentication in TLS v1.3 connections. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a client and + * 0 on success. + */ +int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ctx->postHandshakeAuth = 1; + + return 0; +} + +/* Allow post-handshake authentication in TLS v1.3 connection. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SIDE_ERROR when not a client and 0 on success. + */ +int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.postHandshakeAuth = 1; + + return 0; +} + +/* Request a certificate of the client. + * Can be called any time after handshake completion. + * A maximum of 256 requests can be sent on a connection. + * + * ssl SSL/TLS object. + */ +int wolfSSL_request_certificate(WOLFSSL* ssl) +{ + int ret; +#ifndef NO_WOLFSSL_SERVER + CertReqCtx* certReqCtx; +#endif + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + if (ssl->options.handShakeState != HANDSHAKE_DONE) + return NOT_READY_ERROR; + if (!ssl->options.postHandshakeAuth) + return POST_HAND_AUTH_ERROR; + + certReqCtx = (CertReqCtx*)XMALLOC(sizeof(CertReqCtx), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + XMEMSET(certReqCtx, 0, sizeof(CertReqCtx)); + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = 1; + if (certReqCtx->next != NULL) + certReqCtx->ctx = certReqCtx->next->ctx + 1; + ssl->certReqCtx = certReqCtx; + + ssl->msgsReceived.got_certificate = 0; + ssl->msgsReceived.got_certificate_verify = 0; + ssl->msgsReceived.got_finished = 0; + + ret = SendTls13CertificateRequest(ssl, &certReqCtx->ctx, certReqCtx->len); + if (ret == WANT_WRITE) + ret = WOLFSSL_ERROR_WANT_WRITE; + else if (ret == 0) + ret = WOLFSSL_SUCCESS; +#else + ret = SIDE_ERROR; +#endif + + return ret; +} +#endif /* !NO_CERTS && WOLFSSL_POST_HANDSHAKE_AUTH */ + +#if !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) +/* Get the preferred key exchange group. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL or not using TLS v1.3, + * SIDE_ERROR when not a client, NOT_READY_ERROR when handshake not complete + * and group number on success. + */ +int wolfSSL_preferred_group(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + if (ssl->options.handShakeState != HANDSHAKE_DONE) + return NOT_READY_ERROR; + + /* Return supported groups only. */ + return TLSX_SupportedCurve_Preferred(ssl, 1); +#else + return SIDE_ERROR; +#endif +} +#endif + +/* Sets the key exchange groups in rank order on a context. + * + * ctx SSL/TLS context object. + * groups Array of groups. + * count Number of groups in array. + * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3 or + * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + */ +int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) +{ + int i; + + if (ctx == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + + for (i = 0; i < count; i++) + ctx->group[i] = (word16)groups[i]; + ctx->numGroups = (byte)count; + + return WOLFSSL_SUCCESS; +} + +/* Sets the key exchange groups in rank order. + * + * ssl SSL/TLS object. + * groups Array of groups. + * count Number of groups in array. + * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3 or + * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + */ +int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) +{ + int i; + + if (ssl == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + for (i = 0; i < count; i++) + ssl->group[i] = (word16)groups[i]; + ssl->numGroups = (byte)count; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_PSK +void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx, + wc_psk_client_tls13_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_client_tls13_callback"); + + if (ctx == NULL) + return; + + ctx->havePSK = 1; + ctx->client_psk_tls13_cb = cb; +} + + +void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl, + wc_psk_client_tls13_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_client_tls13_callback"); + + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.client_psk_tls13_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); +} + + +void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx, + wc_psk_server_tls13_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_server_tls13_callback"); + if (ctx == NULL) + return; + ctx->havePSK = 1; + ctx->server_psk_tls13_cb = cb; +} + + +void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl, + wc_psk_server_tls13_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_server_tls13_callback"); + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.server_psk_tls13_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.side); +} +#endif + + +#ifndef NO_WOLFSSL_SERVER +/* The server accepting a connection from a client. + * The protocol version is expecting to be TLS v1.3. + * If the client downgrades, and older versions of the protocol are compiled + * in, the server will fallback to wolfSSL_accept(). + * Please see note at top of README if you get an error from accept. + * + * ssl The SSL/TLS object. + * returns WOLFSSL_SUCCESS on successful handshake, WOLFSSL_FATAL_ERROR when + * unrecoverable error occurs and 0 otherwise. + * For more error information use wolfSSL_get_error(). + */ +int wolfSSL_accept_TLSv13(WOLFSSL* ssl) +{ + word16 havePSK = 0; + WOLFSSL_ENTER("SSL_accept_TLSv13()"); + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + havePSK = ssl->options.havePSK; +#endif + (void)havePSK; + + if (ssl->options.side != WOLFSSL_SERVER_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return WOLFSSL_FATAL_ERROR; + } + +#ifndef NO_CERTS + /* allow no private key if using PK callbacks and CB is set */ + if (!havePSK) { + if (!ssl->buffers.certificate || + !ssl->buffers.certificate->buffer) { + + WOLFSSL_MSG("accept error: server cert required"); + WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY); + return WOLFSSL_FATAL_ERROR; + } + + #ifdef HAVE_PK_CALLBACKS + if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) { + WOLFSSL_MSG("Using PK for server private key"); + } + else + #endif + if (!ssl->buffers.key || !ssl->buffers.key->buffer) { + WOLFSSL_MSG("accept error: server key required"); + WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { + if ((ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.acceptState++; + WOLFSSL_MSG("accept state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("accept state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + switch (ssl->options.acceptState) { + +#ifdef HAVE_SECURE_RENEGOTIATION + case TLS13_ACCEPT_BEGIN_RENEG: +#endif + case TLS13_ACCEPT_BEGIN : + /* get client_hello */ + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE; + WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + if (!IsAtLeastTLSv1_3(ssl->version)) + return wolfSSL_accept(ssl); + FALL_THROUGH; + + case TLS13_ACCEPT_CLIENT_HELLO_DONE : +#ifdef WOLFSSL_TLS13_DRAFT_18 + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE : +#else + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = SendTls13ServerHello(ssl, + hello_retry_request)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + + ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE; + WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE : + #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + } + #endif + ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + FALL_THROUGH; +#endif + + case TLS13_ACCEPT_FIRST_REPLY_DONE : + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + ssl->options.clientState = CLIENT_HELLO_RETRY; + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + + ssl->options.acceptState = TLS13_ACCEPT_SECOND_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_SECOND_REPLY_DONE : + if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = TLS13_SERVER_HELLO_SENT; + WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); + FALL_THROUGH; + + case TLS13_SERVER_HELLO_SENT : + #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ + defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) + if (!ssl->options.sentChangeCipher) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; + } + #endif + + ssl->options.acceptState = TLS13_ACCEPT_THIRD_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_THIRD_REPLY_DONE : + if (!ssl->options.noPskDheKe) { + ssl->error = TLSX_KeyShare_DeriveSecret(ssl); + if (ssl->error != 0) + return WOLFSSL_FATAL_ERROR; + } + + if ((ssl->error = SendTls13EncryptedExtensions(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = TLS13_SERVER_EXTENSIONS_SENT; + WOLFSSL_MSG("accept state SERVER_EXTENSIONS_SENT"); + FALL_THROUGH; + + case TLS13_SERVER_EXTENSIONS_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming) { + if (ssl->options.verifyPeer) { + ssl->error = SendTls13CertificateRequest(ssl, NULL, 0); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } +#endif + ssl->options.acceptState = TLS13_CERT_REQ_SENT; + WOLFSSL_MSG("accept state CERT_REQ_SENT"); + FALL_THROUGH; + + case TLS13_CERT_REQ_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + if ((ssl->error = SendTls13Certificate(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + ssl->options.acceptState = TLS13_CERT_SENT; + WOLFSSL_MSG("accept state CERT_SENT"); + FALL_THROUGH; + + case TLS13_CERT_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + if ((ssl->error = SendTls13CertificateVerify(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + ssl->options.acceptState = TLS13_CERT_VERIFY_SENT; + WOLFSSL_MSG("accept state CERT_VERIFY_SENT"); + FALL_THROUGH; + + case TLS13_CERT_VERIFY_SENT : + if ((ssl->error = SendTls13Finished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = TLS13_ACCEPT_FINISHED_SENT; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_SENT"); +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData != no_early_data) { + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + return WOLFSSL_SUCCESS; + } +#endif + FALL_THROUGH; + + case TLS13_ACCEPT_FINISHED_SENT : +#ifdef HAVE_SESSION_TICKET + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->options.verifyPeer && !ssl->options.noTicketTls13 && + ssl->ctx->ticketEncCb != NULL) { + if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + #endif +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TLS13_PRE_TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + FALL_THROUGH; + + case TLS13_PRE_TICKET_SENT : + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = TLS13_ACCEPT_FINISHED_DONE; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); + FALL_THROUGH; + + case TLS13_ACCEPT_FINISHED_DONE : +#ifdef HAVE_SESSION_TICKET + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + if (!ssl->options.verifyPeer) { + } + else + #endif + if (!ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { + if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TLS13_TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + FALL_THROUGH; + + case TLS13_TICKET_SENT : +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + + WOLFSSL_LEAVE("SSL_accept()", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default : + WOLFSSL_MSG("Unknown accept state ERROR"); + return WOLFSSL_FATAL_ERROR; + } +} +#endif + +#ifdef WOLFSSL_EARLY_DATA +/* Sets the maximum amount of early data that can be seen by server when using + * session tickets for resumption. + * A value of zero indicates no early data is to be sent by client using session + * tickets. + * + * ctx The SSL/TLS CTX object. + * sz Maximum size of the early data. + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and + * 0 on success. + */ +int wolfSSL_CTX_set_max_early_data(WOLFSSL_CTX* ctx, unsigned int sz) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + ctx->maxEarlyDataSz = sz; + + return 0; +} + +/* Sets the maximum amount of early data that can be seen by server when using + * session tickets for resumption. + * A value of zero indicates no early data is to be sent by client using session + * tickets. + * + * ssl The SSL/TLS object. + * sz Maximum size of the early data. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SIDE_ERROR when not a server and 0 on success. + */ +int wolfSSL_set_max_early_data(WOLFSSL* ssl, unsigned int sz) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + ssl->options.maxEarlyDataSz = sz; + + return 0; +} + +/* Write early data to the server. + * + * ssl The SSL/TLS object. + * data Early data to write + * sz The size of the eary data in bytes. + * outSz The number of early data bytes written. + * returns BAD_FUNC_ARG when: ssl, data or outSz is NULL; sz is negative; + * or not using TLS v1.3. SIDE ERROR when not a server. Otherwise the number of + * early data bytes written. + */ +int wolfSSL_write_early_data(WOLFSSL* ssl, const void* data, int sz, int* outSz) +{ + int ret = 0; + + WOLFSSL_ENTER("SSL_write_early_data()"); + + if (ssl == NULL || data == NULL || sz < 0 || outSz == NULL) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + if (ssl->options.handShakeState == NULL_STATE) { + ssl->earlyData = expecting_early_data; + ret = wolfSSL_connect_TLSv13(ssl); + if (ret != WOLFSSL_SUCCESS) + return WOLFSSL_FATAL_ERROR; + } + if (ssl->options.handShakeState == CLIENT_HELLO_COMPLETE) { + ret = SendData(ssl, data, sz); + if (ret > 0) + *outSz = ret; + } +#else + return SIDE_ERROR; +#endif + + WOLFSSL_LEAVE("SSL_write_early_data()", ret); + + if (ret < 0) + ret = WOLFSSL_FATAL_ERROR; + return ret; +} + +/* Read the any early data from the client. + * + * ssl The SSL/TLS object. + * data Buffer to put the early data into. + * sz The size of the buffer in bytes. + * outSz The number of early data bytes read. + * returns BAD_FUNC_ARG when: ssl, data or outSz is NULL; sz is negative; + * or not using TLS v1.3. SIDE ERROR when not a server. Otherwise the number of + * early data bytes read. + */ +int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_read_early_data()"); + + + if (ssl == NULL || data == NULL || sz < 0 || outSz == NULL) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + + if (ssl->options.handShakeState == NULL_STATE) { + ssl->earlyData = expecting_early_data; + ret = wolfSSL_accept_TLSv13(ssl); + if (ret <= 0) + return WOLFSSL_FATAL_ERROR; + } + if (ssl->options.handShakeState == SERVER_FINISHED_COMPLETE) { + ret = ReceiveData(ssl, (byte*)data, sz, FALSE); + if (ret > 0) + *outSz = ret; + if (ssl->error == ZERO_RETURN) + ssl->error = WOLFSSL_ERROR_NONE; + } + else + ret = 0; +#else + return SIDE_ERROR; +#endif + + WOLFSSL_LEAVE("wolfSSL_read_early_data()", ret); + + if (ret < 0) + ret = WOLFSSL_FATAL_ERROR; + return ret; +} +#endif + +#ifdef HAVE_SECRET_CALLBACK +int wolfSSL_set_tls13_secret_cb(WOLFSSL* ssl, Tls13SecretCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_set_tls13_secret_cb"); + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + ssl->tls13SecretCb = cb; + ssl->tls13SecretCtx = ctx; + + return WOLFSSL_SUCCESS; +} +#endif + +#undef ERROR_OUT + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* WOLFSSL_TLS13 */ diff --git a/client/wolfssl/src/wolfio.c b/client/wolfssl/src/wolfio.c new file mode 100644 index 0000000..b7032ca --- /dev/null +++ b/client/wolfssl/src/wolfio.c @@ -0,0 +1,2375 @@ +/* wolfio.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY + +#ifdef _WIN32_WCE + /* On WinCE winsock2.h must be included before windows.h for socket stuff */ + #include +#endif + +#include +#include +#include + +#if defined(HAVE_HTTP_CLIENT) + #include /* strtol() */ +#endif + +/* +Possible IO enable options: + * WOLFSSL_USER_IO: Disables default Embed* callbacks and default: off + allows user to define their own using + wolfSSL_CTX_SetIORecv and wolfSSL_CTX_SetIOSend + * USE_WOLFSSL_IO: Enables the wolfSSL IO functions default: off + * HAVE_HTTP_CLIENT: Enables HTTP client API's default: off + (unless HAVE_OCSP or HAVE_CRL_IO defined) + * HAVE_IO_TIMEOUT: Enables support for connect timeout default: off + */ + + +/* if user writes own I/O callbacks they can define WOLFSSL_USER_IO to remove + automatic setting of default I/O functions EmbedSend() and EmbedReceive() + but they'll still need SetCallback xxx() at end of file +*/ + +#if defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT) + +/* Translates return codes returned from + * send() and recv() if need be. + */ +static WC_INLINE int TranslateReturnCode(int old, int sd) +{ + (void)sd; + +#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + if (old == 0) { + errno = SOCKET_EWOULDBLOCK; + return -1; /* convert to BSD style wouldblock as error */ + } + + if (old < 0) { + errno = RTCS_geterror(sd); + if (errno == RTCSERR_TCP_CONN_CLOSING) + return 0; /* convert to BSD style closing */ + if (errno == RTCSERR_TCP_CONN_RLSD) + errno = SOCKET_ECONNRESET; + if (errno == RTCSERR_TCP_TIMED_OUT) + errno = SOCKET_EAGAIN; + } +#endif + + return old; +} + +static WC_INLINE int wolfSSL_LastError(void) +{ +#ifdef USE_WINDOWS_API + return WSAGetLastError(); +#elif defined(EBSNET) + return xn_getlasterror(); +#else + return errno; +#endif +} + +#endif /* USE_WOLFSSL_IO || HAVE_HTTP_CLIENT */ + + +#ifdef OPENSSL_EXTRA +/* Use the WOLFSSL read BIO for receiving data. This is set by the function + * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIORecv. + * + * ssl WOLFSSL struct passed in that has this function set as the receive + * callback. + * buf buffer to fill with data read + * sz size of buf buffer + * ctx a user set context + * + * returns the amount of data read or want read. See WOLFSSL_CBIO_ERR_* values. + */ +int BioReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + int recvd = WOLFSSL_CBIO_ERR_GENERAL; + + WOLFSSL_ENTER("BioReceive"); + + if (ssl->biord == NULL) { + WOLFSSL_MSG("WOLFSSL biord not set"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + if (ssl->biord->method && ssl->biord->method->readCb) { + WOLFSSL_MSG("Calling custom biord"); + recvd = ssl->biord->method->readCb(ssl->biord, buf, sz); + if (recvd < 0 && recvd != WOLFSSL_CBIO_ERR_WANT_READ) + return WOLFSSL_CBIO_ERR_GENERAL; + return recvd; + } + + switch (ssl->biord->type) { + case WOLFSSL_BIO_MEMORY: + case WOLFSSL_BIO_BIO: + if (wolfSSL_BIO_ctrl_pending(ssl->biord) == 0) { + WOLFSSL_MSG("BIO want read"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + recvd = wolfSSL_BIO_read(ssl->biord, buf, sz); + if (recvd <= 0) { + WOLFSSL_MSG("BIO general error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + break; + + default: + WOLFSSL_MSG("This BIO type is unknown / unsupported"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + (void)ctx; + return recvd; +} + + +/* Use the WOLFSSL write BIO for sending data. This is set by the function + * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIOSend. + * + * ssl WOLFSSL struct passed in that has this function set as the send callback. + * buf buffer with data to write out + * sz size of buf buffer + * ctx a user set context + * + * returns the amount of data sent or want send. See WOLFSSL_CBIO_ERR_* values. + */ +int BioSend(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + int sent = WOLFSSL_CBIO_ERR_GENERAL; + + WOLFSSL_ENTER("BioSend"); + + if (ssl->biowr == NULL) { + WOLFSSL_MSG("WOLFSSL biowr not set"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + if (ssl->biowr->method && ssl->biowr->method->writeCb) { + WOLFSSL_MSG("Calling custom biowr"); + sent = ssl->biowr->method->writeCb(ssl->biowr, buf, sz); + if (sent < 0) { + return WOLFSSL_CBIO_ERR_GENERAL; + } + return sent; + } + + switch (ssl->biowr->type) { + case WOLFSSL_BIO_MEMORY: + case WOLFSSL_BIO_BIO: + sent = wolfSSL_BIO_write(ssl->biowr, buf, sz); + if (sent < 0) { + return WOLFSSL_CBIO_ERR_GENERAL; + } + break; + + default: + WOLFSSL_MSG("This BIO type is unknown / unsupported"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + (void)ctx; + + return sent; +} +#endif + + +#ifdef USE_WOLFSSL_IO + +/* The receive embedded callback + * return : nb bytes read, or error + */ +int EmbedReceive(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + int sd = *(int*)ctx; + int recvd; + + recvd = wolfIO_Recv(sd, buf, sz, ssl->rflags); + if (recvd < 0) { + int err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Receive error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_ECONNABORTED) { + WOLFSSL_MSG("\tConnection aborted"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else if (recvd == 0) { + WOLFSSL_MSG("Embed receive connection closed"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + + return recvd; +} + +/* The send embedded callback + * return : nb bytes sent, or error + */ +int EmbedSend(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + int sd = *(int*)ctx; + int sent; + +#ifdef WOLFSSL_MAX_SEND_SZ + if (sz > WOLFSSL_MAX_SEND_SZ) + sz = WOLFSSL_MAX_SEND_SZ; +#endif + + sent = wolfIO_Send(sd, buf, sz, ssl->wflags); + if (sent < 0) { + int err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Send error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + WOLFSSL_MSG("\tWould Block"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_EPIPE) { + WOLFSSL_MSG("\tSocket EPIPE"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return sent; +} + + +#ifdef WOLFSSL_DTLS + +#include + +#define SENDTO_FUNCTION sendto +#define RECVFROM_FUNCTION recvfrom + + +/* The receive embedded callback + * return : nb bytes read, or error + */ +int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx; + int recvd; + int err; + int sd = dtlsCtx->rfd; + int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl); + SOCKADDR_S peer; + XSOCKLENT peerSz = sizeof(peer); + + WOLFSSL_ENTER("EmbedReceiveFrom()"); + + if (ssl->options.handShakeDone) + dtls_timeout = 0; + + if (!wolfSSL_get_using_nonblock(ssl)) { + #ifdef USE_WINDOWS_API + DWORD timeout = dtls_timeout * 1000; + #else + struct timeval timeout; + XMEMSET(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = dtls_timeout; + #endif + if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, + sizeof(timeout)) != 0) { + WOLFSSL_MSG("setsockopt rcvtimeo failed"); + } + } + + recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags, + (SOCKADDR*)&peer, &peerSz); + + recvd = TranslateReturnCode(recvd, sd); + + if (recvd < 0) { + err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Receive From error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + if (wolfSSL_dtls_get_using_nonblock(ssl)) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tSocket timeout"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_ECONNREFUSED) { + WOLFSSL_MSG("\tConnection refused"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else { + if (dtlsCtx->peer.sz > 0 + && peerSz != (XSOCKLENT)dtlsCtx->peer.sz + && XMEMCMP(&peer, dtlsCtx->peer.sa, peerSz) != 0) { + WOLFSSL_MSG(" Ignored packet from invalid peer"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + } + + return recvd; +} + + +/* The send embedded callback + * return : nb bytes sent, or error + */ +int EmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx; + int sd = dtlsCtx->wfd; + int sent; + int err; + + WOLFSSL_ENTER("EmbedSendTo()"); + + sent = (int)SENDTO_FUNCTION(sd, buf, sz, ssl->wflags, + (const SOCKADDR*)dtlsCtx->peer.sa, + dtlsCtx->peer.sz); + + sent = TranslateReturnCode(sent, sd); + + if (sent < 0) { + err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Send To error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + WOLFSSL_MSG("\tWould Block"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_EPIPE) { + WOLFSSL_MSG("\tSocket EPIPE"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return sent; +} + + +#ifdef WOLFSSL_MULTICAST + +/* The alternate receive embedded callback for Multicast + * return : nb bytes read, or error + */ +int EmbedReceiveFromMcast(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx; + int recvd; + int err; + int sd = dtlsCtx->rfd; + + WOLFSSL_ENTER("EmbedReceiveFromMcast()"); + + recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags, NULL, NULL); + + recvd = TranslateReturnCode(recvd, sd); + + if (recvd < 0) { + err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Receive From error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + if (wolfSSL_dtls_get_using_nonblock(ssl)) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tSocket timeout"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_ECONNREFUSED) { + WOLFSSL_MSG("\tConnection refused"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return recvd; +} +#endif /* WOLFSSL_MULTICAST */ + + +/* The DTLS Generate Cookie callback + * return : number of bytes copied into buf, or error + */ +int EmbedGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx) +{ + int sd = ssl->wfd; + SOCKADDR_S peer; + XSOCKLENT peerSz = sizeof(peer); + byte digest[WC_SHA256_DIGEST_SIZE]; + int ret = 0; + + (void)ctx; + + XMEMSET(&peer, 0, sizeof(peer)); + if (getpeername(sd, (SOCKADDR*)&peer, &peerSz) != 0) { + WOLFSSL_MSG("getpeername failed in EmbedGenerateCookie"); + return GEN_COOKIE_E; + } + + ret = wc_Sha256Hash((byte*)&peer, peerSz, digest); + if (ret != 0) + return ret; + + if (sz > WC_SHA256_DIGEST_SIZE) + sz = WC_SHA256_DIGEST_SIZE; + XMEMCPY(buf, digest, sz); + + return sz; +} + +#ifdef WOLFSSL_SESSION_EXPORT + + /* get the peer information in human readable form (ip, port, family) + * default function assumes BSD sockets + * can be overridden with wolfSSL_CTX_SetIOGetPeer + */ + int EmbedGetPeer(WOLFSSL* ssl, char* ip, int* ipSz, + unsigned short* port, int* fam) + { + SOCKADDR_S peer; + word32 peerSz; + int ret; + + if (ssl == NULL || ip == NULL || ipSz == NULL || + port == NULL || fam == NULL) { + return BAD_FUNC_ARG; + } + + /* get peer information stored in ssl struct */ + peerSz = sizeof(SOCKADDR_S); + if ((ret = wolfSSL_dtls_get_peer(ssl, (void*)&peer, &peerSz)) + != WOLFSSL_SUCCESS) { + return ret; + } + + /* extract family, ip, and port */ + *fam = ((SOCKADDR_S*)&peer)->ss_family; + switch (*fam) { + case WOLFSSL_IP4: + if (XINET_NTOP(*fam, &(((SOCKADDR_IN*)&peer)->sin_addr), + ip, *ipSz) == NULL) { + WOLFSSL_MSG("XINET_NTOP error"); + return SOCKET_ERROR_E; + } + *port = XNTOHS(((SOCKADDR_IN*)&peer)->sin_port); + break; + + case WOLFSSL_IP6: + #ifdef WOLFSSL_IPV6 + if (XINET_NTOP(*fam, &(((SOCKADDR_IN6*)&peer)->sin6_addr), + ip, *ipSz) == NULL) { + WOLFSSL_MSG("XINET_NTOP error"); + return SOCKET_ERROR_E; + } + *port = XNTOHS(((SOCKADDR_IN6*)&peer)->sin6_port); + #endif /* WOLFSSL_IPV6 */ + break; + + default: + WOLFSSL_MSG("Unknown family type"); + return SOCKET_ERROR_E; + } + ip[*ipSz - 1] = '\0'; /* make sure has terminator */ + *ipSz = (word16)XSTRLEN(ip); + + return WOLFSSL_SUCCESS; + } + + /* set the peer information in human readable form (ip, port, family) + * default function assumes BSD sockets + * can be overridden with wolfSSL_CTX_SetIOSetPeer + */ + int EmbedSetPeer(WOLFSSL* ssl, char* ip, int ipSz, + unsigned short port, int fam) + { + int ret; + SOCKADDR_S addr; + + /* sanity checks on arguments */ + if (ssl == NULL || ip == NULL || ipSz < 0 || ipSz > DTLS_EXPORT_IP) { + return BAD_FUNC_ARG; + } + + addr.ss_family = fam; + switch (addr.ss_family) { + case WOLFSSL_IP4: + if (XINET_PTON(addr.ss_family, ip, + &(((SOCKADDR_IN*)&addr)->sin_addr)) <= 0) { + WOLFSSL_MSG("XINET_PTON error"); + return SOCKET_ERROR_E; + } + ((SOCKADDR_IN*)&addr)->sin_port = XHTONS(port); + + /* peer sa is free'd in SSL_ResourceFree */ + if ((ret = wolfSSL_dtls_set_peer(ssl, (SOCKADDR_IN*)&addr, + sizeof(SOCKADDR_IN)))!= WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Import DTLS peer info error"); + return ret; + } + break; + + case WOLFSSL_IP6: + #ifdef WOLFSSL_IPV6 + if (XINET_PTON(addr.ss_family, ip, + &(((SOCKADDR_IN6*)&addr)->sin6_addr)) <= 0) { + WOLFSSL_MSG("XINET_PTON error"); + return SOCKET_ERROR_E; + } + ((SOCKADDR_IN6*)&addr)->sin6_port = XHTONS(port); + + /* peer sa is free'd in SSL_ResourceFree */ + if ((ret = wolfSSL_dtls_set_peer(ssl, (SOCKADDR_IN6*)&addr, + sizeof(SOCKADDR_IN6)))!= WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Import DTLS peer info error"); + return ret; + } + #endif /* WOLFSSL_IPV6 */ + break; + + default: + WOLFSSL_MSG("Unknown address family"); + return BUFFER_E; + } + + return WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_SESSION_EXPORT */ +#endif /* WOLFSSL_DTLS */ + + +int wolfIO_Recv(SOCKET_T sd, char *buf, int sz, int rdFlags) +{ + int recvd; + + recvd = (int)RECV_FUNCTION(sd, buf, sz, rdFlags); + recvd = TranslateReturnCode(recvd, sd); + + return recvd; +} + +int wolfIO_Send(SOCKET_T sd, char *buf, int sz, int wrFlags) +{ + int sent; + + sent = (int)SEND_FUNCTION(sd, buf, sz, wrFlags); + sent = TranslateReturnCode(sent, sd); + + return sent; +} + +#endif /* USE_WOLFSSL_IO */ + + +#ifdef HAVE_HTTP_CLIENT + +#ifndef HAVE_IO_TIMEOUT + #define io_timeout_sec 0 +#else + + #ifndef DEFAULT_TIMEOUT_SEC + #define DEFAULT_TIMEOUT_SEC 0 /* no timeout */ + #endif + + static int io_timeout_sec = DEFAULT_TIMEOUT_SEC; + + void wolfIO_SetTimeout(int to_sec) + { + io_timeout_sec = to_sec; + } + + int wolfIO_SetBlockingMode(SOCKET_T sockfd, int non_blocking) + { + int ret = 0; + + #ifdef USE_WINDOWS_API + unsigned long blocking = non_blocking; + ret = ioctlsocket(sockfd, FIONBIO, &blocking); + if (ret == SOCKET_ERROR) + ret = -1; + #else + ret = fcntl(sockfd, F_GETFL, 0); + if (ret >= 0) { + if (non_blocking) + ret |= O_NONBLOCK; + else + ret &= ~O_NONBLOCK; + ret = fcntl(sockfd, F_SETFL, ret); + } + #endif + if (ret < 0) { + WOLFSSL_MSG("wolfIO_SetBlockingMode failed"); + } + + return ret; + } + + int wolfIO_Select(SOCKET_T sockfd, int to_sec) + { + fd_set rfds, wfds; + int nfds = 0; + struct timeval timeout = { (to_sec > 0) ? to_sec : 0, 0}; + int ret; + + #ifndef USE_WINDOWS_API + nfds = (int)sockfd + 1; + #endif + + FD_ZERO(&rfds); + FD_SET(sockfd, &rfds); + wfds = rfds; + + ret = select(nfds, &rfds, &wfds, NULL, &timeout); + if (ret == 0) { + #ifdef DEBUG_HTTP + printf("Timeout: %d\n", ret); + #endif + return HTTP_TIMEOUT; + } + else if (ret > 0) { + if (FD_ISSET(sockfd, &wfds)) { + if (!FD_ISSET(sockfd, &rfds)) { + return 0; + } + } + } + return SOCKET_ERROR_E; + } +#endif /* HAVE_IO_TIMEOUT */ + +static int wolfIO_Word16ToString(char* d, word16 number) +{ + int i = 0; + word16 order = 10000; + word16 digit; + + if (d == NULL) + return i; + + if (number == 0) + d[i++] = '0'; + else { + while (order) { + digit = number / order; + if (i > 0 || digit != 0) + d[i++] = (char)digit + '0'; + if (digit != 0) + number %= digit * order; + + order = (order > 1) ? order / 10 : 0; + } + } + d[i] = 0; /* null terminate */ + + return i; +} + +int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec) +{ +#ifdef HAVE_SOCKADDR + int ret = 0; + SOCKADDR_S addr; + int sockaddr_len = sizeof(SOCKADDR_IN); + /* use gethostbyname for c99 */ +#if defined(HAVE_GETADDRINFO) && !defined(WOLF_C99) + ADDRINFO hints; + ADDRINFO* answer = NULL; + char strPort[6]; +#else + HOSTENT* entry; + SOCKADDR_IN *sin; +#endif + + XMEMSET(&addr, 0, sizeof(addr)); + +#ifdef WOLFIO_DEBUG + printf("TCP Connect: %s:%d\n", ip, port); +#endif + + /* use gethostbyname for c99 */ +#if defined(HAVE_GETADDRINFO) && !defined(WOLF_C99) + XMEMSET(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (wolfIO_Word16ToString(strPort, port) == 0) { + WOLFSSL_MSG("invalid port number for responder"); + return -1; + } + + if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) { + WOLFSSL_MSG("no addr info for responder"); + return -1; + } + + sockaddr_len = answer->ai_addrlen; + XMEMCPY(&addr, answer->ai_addr, sockaddr_len); + freeaddrinfo(answer); +#else + entry = gethostbyname(ip); + sin = (SOCKADDR_IN *)&addr; + + if (entry) { + sin->sin_family = AF_INET; + sin->sin_port = XHTONS(port); + XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0], entry->h_length); + } + else { + WOLFSSL_MSG("no addr info for responder"); + return -1; + } +#endif + + *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM, 0); + +#ifdef USE_WINDOWS_API + if (*sockfd == INVALID_SOCKET) { + WOLFSSL_MSG("bad socket fd, out of fds?"); + return -1; + } +#else + if (*sockfd < 0) { + WOLFSSL_MSG("bad socket fd, out of fds?"); + return -1; + } +#endif + +#ifdef HAVE_IO_TIMEOUT + /* if timeout value provided then set socket non-blocking */ + if (to_sec > 0) { + wolfIO_SetBlockingMode(*sockfd, 1); + } +#else + (void)to_sec; +#endif + + ret = connect(*sockfd, (SOCKADDR *)&addr, sockaddr_len); +#ifdef HAVE_IO_TIMEOUT + if (ret != 0) { + if ((errno == EINPROGRESS) && (to_sec > 0)) { + /* wait for connect to complete */ + ret = wolfIO_Select(*sockfd, to_sec); + + /* restore blocking mode */ + wolfIO_SetBlockingMode(*sockfd, 0); + } + } +#endif + if (ret != 0) { + WOLFSSL_MSG("Responder tcp connect failed"); + return -1; + } + return ret; +#else + (void)sockfd; + (void)ip; + (void)port; + (void)to_sec; + return -1; +#endif /* HAVE_SOCKADDR */ +} + +#ifndef HTTP_SCRATCH_BUFFER_SIZE + #define HTTP_SCRATCH_BUFFER_SIZE 512 +#endif +#ifndef MAX_URL_ITEM_SIZE + #define MAX_URL_ITEM_SIZE 80 +#endif + +int wolfIO_DecodeUrl(const char* url, int urlSz, char* outName, char* outPath, + word16* outPort) +{ + int result = -1; + + if (url == NULL || urlSz == 0) { + if (outName) + *outName = 0; + if (outPath) + *outPath = 0; + if (outPort) + *outPort = 0; + } + else { + int i, cur; + + /* need to break the url down into scheme, address, and port */ + /* "http://example.com:8080/" */ + /* "http://[::1]:443/" */ + if (XSTRNCMP(url, "http://", 7) == 0) { + cur = 7; + } else cur = 0; + + i = 0; + if (url[cur] == '[') { + cur++; + /* copy until ']' */ + while (i < MAX_URL_ITEM_SIZE-1 && cur < urlSz && url[cur] != 0 && + url[cur] != ']') { + if (outName) + outName[i] = url[cur]; + i++; cur++; + } + cur++; /* skip ']' */ + } + else { + while (i < MAX_URL_ITEM_SIZE-1 && cur < urlSz && url[cur] != 0 && + url[cur] != ':' && url[cur] != '/') { + if (outName) + outName[i] = url[cur]; + i++; cur++; + } + } + if (outName) + outName[i] = 0; + /* Need to pick out the path after the domain name */ + + if (cur < urlSz && url[cur] == ':') { + char port[6]; + int j; + word32 bigPort = 0; + i = 0; + cur++; + while (i < 6 && cur < urlSz && url[cur] != 0 && url[cur] != '/') { + port[i] = url[cur]; + i++; cur++; + } + + for (j = 0; j < i; j++) { + if (port[j] < '0' || port[j] > '9') return -1; + bigPort = (bigPort * 10) + (port[j] - '0'); + } + if (outPort) + *outPort = (word16)bigPort; + } + else if (outPort) + *outPort = 80; + + + if (cur < urlSz && url[cur] == '/') { + i = 0; + while (i < MAX_URL_ITEM_SIZE-1 && cur < urlSz && url[cur] != 0) { + if (outPath) + outPath[i] = url[cur]; + i++; cur++; + } + if (outPath) + outPath[i] = 0; + } + else if (outPath) { + outPath[0] = '/'; + outPath[1] = 0; + } + + result = 0; + } + + return result; +} + +static int wolfIO_HttpProcessResponseBuf(int sfd, byte **recvBuf, + int* recvBufSz, int chunkSz, char* start, int len, int dynType, void* heap) +{ + byte* newRecvBuf = NULL; + int newRecvSz = *recvBufSz + chunkSz; + int pos = 0; + + WOLFSSL_MSG("Processing HTTP response"); +#ifdef WOLFIO_DEBUG + printf("HTTP Chunk %d->%d\n", *recvBufSz, chunkSz); +#endif + + (void)heap; + (void)dynType; + + if (chunkSz < 0 || len < 0) { + WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf invalid chunk or length size"); + return MEMORY_E; + } + + if (newRecvSz <= 0) { + WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf new receive size overflow"); + return MEMORY_E; + } + + newRecvBuf = (byte*)XMALLOC(newRecvSz, heap, dynType); + if (newRecvBuf == NULL) { + WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf malloc failed"); + return MEMORY_E; + } + + /* if buffer already exists, then we are growing it */ + if (*recvBuf) { + XMEMCPY(&newRecvBuf[pos], *recvBuf, *recvBufSz); + XFREE(*recvBuf, heap, dynType); + pos += *recvBufSz; + *recvBuf = NULL; + } + + /* copy the remainder of the httpBuf into the respBuf */ + if (len != 0) { + if (pos + len <= newRecvSz) { + XMEMCPY(&newRecvBuf[pos], start, len); + pos += len; + } + else { + WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf bad size"); + XFREE(newRecvBuf, heap, dynType); + return -1; + } + } + + /* receive the remainder of chunk */ + while (len < chunkSz) { + int rxSz = wolfIO_Recv(sfd, (char*)&newRecvBuf[pos], chunkSz-len, 0); + if (rxSz > 0) { + len += rxSz; + pos += rxSz; + } + else { + WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf recv failed"); + XFREE(newRecvBuf, heap, dynType); + return -1; + } + } + + *recvBuf = newRecvBuf; + *recvBufSz = newRecvSz; + + return 0; +} + +int wolfIO_HttpProcessResponse(int sfd, const char** appStrList, + byte** respBuf, byte* httpBuf, int httpBufSz, int dynType, void* heap) +{ + int result = 0; + int len = 0; + char *start, *end; + int respBufSz = 0; + int isChunked = 0, chunkSz = 0; + enum phr_state { phr_init, phr_http_start, phr_have_length, phr_have_type, + phr_wait_end, phr_get_chunk_len, phr_get_chunk_data, + phr_http_end + } state = phr_init; + + *respBuf = NULL; + start = end = NULL; + do { + if (state == phr_get_chunk_data) { + /* get chunk of data */ + result = wolfIO_HttpProcessResponseBuf(sfd, respBuf, &respBufSz, + chunkSz, start, len, dynType, heap); + + state = (result != 0) ? phr_http_end : phr_get_chunk_len; + end = NULL; + len = 0; + } + + /* read data if no \r\n or first time */ + if (end == NULL) { + result = wolfIO_Recv(sfd, (char*)httpBuf+len, httpBufSz-len-1, 0); + if (result > 0) { + len += result; + start = (char*)httpBuf; + start[len] = 0; + } + else { + WOLFSSL_MSG("wolfIO_HttpProcessResponse recv http from peer failed"); + return -1; + } + } + end = XSTRSTR(start, "\r\n"); /* locate end */ + + /* handle incomplete rx */ + if (end == NULL) { + if (len != 0) + XMEMMOVE(httpBuf, start, len); + start = end = NULL; + } + /* when start is "\r\n" */ + else if (end == start) { + /* if waiting for end or need chunk len */ + if (state == phr_wait_end || state == phr_get_chunk_len) { + state = (isChunked) ? phr_get_chunk_len : phr_http_end; + len -= 2; start += 2; /* skip \r\n */ + } + else { + WOLFSSL_MSG("wolfIO_HttpProcessResponse header ended early"); + return -1; + } + } + else { + *end = 0; /* null terminate */ + len -= (int)(end - start) + 2; + /* adjust len to remove the first line including the /r/n */ + + #ifdef WOLFIO_DEBUG + printf("HTTP Resp: %s\n", start); + #endif + + switch (state) { + case phr_init: + if (XSTRLEN(start) < 15) { /* 15 is the length of the two + constant strings we're about to + compare against. */ + WOLFSSL_MSG("wolfIO_HttpProcessResponse HTTP header too short."); + return -1; + } + if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) { + start += 9; + if (XSTRNCASECMP(start, "200 OK", 6) != 0) { + WOLFSSL_MSG("wolfIO_HttpProcessResponse not OK"); + return -1; + } + state = phr_http_start; + } + break; + case phr_http_start: + case phr_have_length: + case phr_have_type: + if (XSTRLEN(start) < 13) { /* 13 is the shortest of the following + next lines we're checking for. */ + WOLFSSL_MSG("wolfIO_HttpProcessResponse content type is too short."); + return -1; + } + + if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) { + int i; + + start += 13; + while (*start == ' ') start++; + + /* try and match against appStrList */ + i = 0; + while (appStrList[i] != NULL) { + if (XSTRNCASECMP(start, appStrList[i], + XSTRLEN(appStrList[i])) == 0) { + break; + } + i++; + } + if (appStrList[i] == NULL) { + WOLFSSL_MSG("wolfIO_HttpProcessResponse appstr mismatch"); + return -1; + } + state = (state == phr_http_start) ? phr_have_type : phr_wait_end; + } + else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) { + start += 15; + while (*start == ' ') start++; + chunkSz = XATOI(start); + state = (state == phr_http_start) ? phr_have_length : phr_wait_end; + } + else if (XSTRNCASECMP(start, "Transfer-Encoding:", 18) == 0) { + start += 18; + while (*start == ' ') start++; + if (XSTRNCASECMP(start, "chunked", 7) == 0) { + isChunked = 1; + state = (state == phr_http_start) ? phr_have_length : phr_wait_end; + } + } + break; + case phr_get_chunk_len: + chunkSz = (int)strtol(start, NULL, 16); /* hex format */ + state = (chunkSz == 0) ? phr_http_end : phr_get_chunk_data; + break; + case phr_get_chunk_data: + /* processing for chunk data done above, since \r\n isn't required */ + case phr_wait_end: + case phr_http_end: + /* do nothing */ + break; + } /* switch (state) */ + + /* skip to end plus \r\n */ + start = end + 2; + } + } while (state != phr_http_end); + + if (!isChunked) { + result = wolfIO_HttpProcessResponseBuf(sfd, respBuf, &respBufSz, chunkSz, + start, len, dynType, heap); + } + + if (result >= 0) { + result = respBufSz; + } + else { + WOLFSSL_ERROR(result); + } + + return result; +} +int wolfIO_HttpBuildRequest(const char *reqType, const char *domainName, + const char *path, int pathLen, int reqSz, const char *contentType, + byte *buf, int bufSize) +{ + return wolfIO_HttpBuildRequest_ex(reqType, domainName, path, pathLen, reqSz, contentType, "", buf, bufSize); +} + + int wolfIO_HttpBuildRequest_ex(const char *reqType, const char *domainName, + const char *path, int pathLen, int reqSz, const char *contentType, + const char *exHdrs, byte *buf, int bufSize) + { + word32 reqTypeLen, domainNameLen, reqSzStrLen, contentTypeLen, exHdrsLen, maxLen; + char reqSzStr[6]; + char* req = (char*)buf; + const char* blankStr = " "; + const char* http11Str = " HTTP/1.1"; + const char* hostStr = "\r\nHost: "; + const char* contentLenStr = "\r\nContent-Length: "; + const char* contentTypeStr = "\r\nContent-Type: "; + const char* singleCrLfStr = "\r\n"; + const char* doubleCrLfStr = "\r\n\r\n"; + word32 blankStrLen, http11StrLen, hostStrLen, contentLenStrLen, + contentTypeStrLen, singleCrLfStrLen, doubleCrLfStrLen; + + reqTypeLen = (word32)XSTRLEN(reqType); + domainNameLen = (word32)XSTRLEN(domainName); + reqSzStrLen = wolfIO_Word16ToString(reqSzStr, (word16)reqSz); + contentTypeLen = (word32)XSTRLEN(contentType); + + blankStrLen = (word32)XSTRLEN(blankStr); + http11StrLen = (word32)XSTRLEN(http11Str); + hostStrLen = (word32)XSTRLEN(hostStr); + contentLenStrLen = (word32)XSTRLEN(contentLenStr); + contentTypeStrLen = (word32)XSTRLEN(contentTypeStr); + + if(exHdrs){ + singleCrLfStrLen = (word32)XSTRLEN(singleCrLfStr); + exHdrsLen = (word32)XSTRLEN(exHdrs); + } else { + singleCrLfStrLen = 0; + exHdrsLen = 0; + } + + doubleCrLfStrLen = (word32)XSTRLEN(doubleCrLfStr); + + /* determine max length and check it */ + maxLen = + reqTypeLen + + blankStrLen + + pathLen + + http11StrLen + + hostStrLen + + domainNameLen + + contentLenStrLen + + reqSzStrLen + + contentTypeStrLen + + contentTypeLen + + singleCrLfStrLen + + exHdrsLen + + doubleCrLfStrLen + + 1 /* null term */; + if (maxLen > (word32)bufSize) + return 0; + + XSTRNCPY((char*)buf, reqType, bufSize); + buf += reqTypeLen; bufSize -= reqTypeLen; + XSTRNCPY((char*)buf, blankStr, bufSize); + buf += blankStrLen; bufSize -= blankStrLen; + XSTRNCPY((char*)buf, path, bufSize); + buf += pathLen; bufSize -= pathLen; + XSTRNCPY((char*)buf, http11Str, bufSize); + buf += http11StrLen; bufSize -= http11StrLen; + if (domainNameLen > 0) { + XSTRNCPY((char*)buf, hostStr, bufSize); + buf += hostStrLen; bufSize -= hostStrLen; + XSTRNCPY((char*)buf, domainName, bufSize); + buf += domainNameLen; bufSize -= domainNameLen; + } + if (reqSz > 0 && reqSzStrLen > 0) { + XSTRNCPY((char*)buf, contentLenStr, bufSize); + buf += contentLenStrLen; bufSize -= contentLenStrLen; + XSTRNCPY((char*)buf, reqSzStr, bufSize); + buf += reqSzStrLen; bufSize -= reqSzStrLen; + } + if (contentTypeLen > 0) { + XSTRNCPY((char*)buf, contentTypeStr, bufSize); + buf += contentTypeStrLen; bufSize -= contentTypeStrLen; + XSTRNCPY((char*)buf, contentType, bufSize); + buf += contentTypeLen; bufSize -= contentTypeLen; + } + if (exHdrsLen > 0) + { + XSTRNCPY((char *)buf, singleCrLfStr, bufSize); + buf += singleCrLfStrLen; + bufSize -= singleCrLfStrLen; + XSTRNCPY((char *)buf, exHdrs, bufSize); + buf += exHdrsLen; + bufSize -= exHdrsLen; + } + XSTRNCPY((char*)buf, doubleCrLfStr, bufSize); + buf += doubleCrLfStrLen; + +#ifdef WOLFIO_DEBUG + printf("HTTP %s: %s", reqType, req); +#endif + + /* calculate actual length based on original and new pointer */ + return (int)((char*)buf - req); +} + + +#ifdef HAVE_OCSP + +int wolfIO_HttpBuildRequestOcsp(const char* domainName, const char* path, + int ocspReqSz, byte* buf, int bufSize) +{ + const char *cacheCtl = "Cache-Control: no-cache"; + return wolfIO_HttpBuildRequest_ex("POST", domainName, path, (int)XSTRLEN(path), + ocspReqSz, "application/ocsp-request", cacheCtl, buf, bufSize); +} + +/* return: >0 OCSP Response Size + * -1 error */ +int wolfIO_HttpProcessResponseOcsp(int sfd, byte** respBuf, + byte* httpBuf, int httpBufSz, void* heap) +{ + const char* appStrList[] = { + "application/ocsp-response", + NULL + }; + + return wolfIO_HttpProcessResponse(sfd, appStrList, + respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_OCSP, heap); +} + +/* in default wolfSSL callback ctx is the heap pointer */ +int EmbedOcspLookup(void* ctx, const char* url, int urlSz, + byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf) +{ + SOCKET_T sfd = 0; + word16 port; + int ret = -1; +#ifdef WOLFSSL_SMALL_STACK + char* path; + char* domainName; +#else + char path[MAX_URL_ITEM_SIZE]; + char domainName[MAX_URL_ITEM_SIZE]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + path = (char*)XMALLOC(MAX_URL_ITEM_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (path == NULL) + return MEMORY_E; + + domainName = (char*)XMALLOC(MAX_URL_ITEM_SIZE, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (domainName == NULL) { + XFREE(path, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + if (ocspReqBuf == NULL || ocspReqSz == 0) { + WOLFSSL_MSG("OCSP request is required for lookup"); + } + else if (ocspRespBuf == NULL) { + WOLFSSL_MSG("Cannot save OCSP response"); + } + else if (wolfIO_DecodeUrl(url, urlSz, domainName, path, &port) < 0) { + WOLFSSL_MSG("Unable to decode OCSP URL"); + } + else { + /* Note, the library uses the EmbedOcspRespFree() callback to + * free this buffer. */ + int httpBufSz = HTTP_SCRATCH_BUFFER_SIZE; + byte* httpBuf = (byte*)XMALLOC(httpBufSz, ctx, DYNAMIC_TYPE_OCSP); + + if (httpBuf == NULL) { + WOLFSSL_MSG("Unable to create OCSP response buffer"); + } + else { + httpBufSz = wolfIO_HttpBuildRequestOcsp(domainName, path, ocspReqSz, + httpBuf, httpBufSz); + + ret = wolfIO_TcpConnect(&sfd, domainName, port, io_timeout_sec); + if ((ret != 0) || ((int)sfd < 0)) { + WOLFSSL_MSG("OCSP Responder connection failed"); + } + else if (wolfIO_Send(sfd, (char*)httpBuf, httpBufSz, 0) != + httpBufSz) { + WOLFSSL_MSG("OCSP http request failed"); + } + else if (wolfIO_Send(sfd, (char*)ocspReqBuf, ocspReqSz, 0) != + ocspReqSz) { + WOLFSSL_MSG("OCSP ocsp request failed"); + } + else { + ret = wolfIO_HttpProcessResponseOcsp(sfd, ocspRespBuf, httpBuf, + HTTP_SCRATCH_BUFFER_SIZE, ctx); + } + + CloseSocket(sfd); + XFREE(httpBuf, ctx, DYNAMIC_TYPE_OCSP); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(path, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(domainName, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +/* in default callback ctx is heap hint */ +void EmbedOcspRespFree(void* ctx, byte *resp) +{ + if (resp) + XFREE(resp, ctx, DYNAMIC_TYPE_OCSP); + + (void)ctx; +} +#endif /* HAVE_OCSP */ + + +#if defined(HAVE_CRL) && defined(HAVE_CRL_IO) + +int wolfIO_HttpBuildRequestCrl(const char* url, int urlSz, + const char* domainName, byte* buf, int bufSize) +{ + const char *cacheCtl = "Cache-Control: no-cache"; + return wolfIO_HttpBuildRequest_ex("GET", domainName, url, urlSz, 0, "", + cacheCtl, buf, bufSize); +} + +int wolfIO_HttpProcessResponseCrl(WOLFSSL_CRL* crl, int sfd, byte* httpBuf, + int httpBufSz) +{ + int result; + byte *respBuf = NULL; + + const char* appStrList[] = { + "application/pkix-crl", + "application/x-pkcs7-crl", + NULL + }; + + result = wolfIO_HttpProcessResponse(sfd, appStrList, + &respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_CRL, crl->heap); + if (result >= 0) { + result = BufferLoadCRL(crl, respBuf, result, WOLFSSL_FILETYPE_ASN1, 0); + } + XFREE(respBuf, crl->heap, DYNAMIC_TYPE_CRL); + + return result; +} + +int EmbedCrlLookup(WOLFSSL_CRL* crl, const char* url, int urlSz) +{ + SOCKET_T sfd = 0; + word16 port; + int ret = -1; +#ifdef WOLFSSL_SMALL_STACK + char* domainName; +#else + char domainName[MAX_URL_ITEM_SIZE]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + domainName = (char*)XMALLOC(MAX_URL_ITEM_SIZE, crl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (domainName == NULL) { + return MEMORY_E; + } +#endif + + if (wolfIO_DecodeUrl(url, urlSz, domainName, NULL, &port) < 0) { + WOLFSSL_MSG("Unable to decode CRL URL"); + } + else { + int httpBufSz = HTTP_SCRATCH_BUFFER_SIZE; + byte* httpBuf = (byte*)XMALLOC(httpBufSz, crl->heap, + DYNAMIC_TYPE_CRL); + if (httpBuf == NULL) { + WOLFSSL_MSG("Unable to create CRL response buffer"); + } + else { + httpBufSz = wolfIO_HttpBuildRequestCrl(url, urlSz, domainName, + httpBuf, httpBufSz); + + ret = wolfIO_TcpConnect(&sfd, domainName, port, io_timeout_sec); + if ((ret != 0) || (sfd < 0)) { + WOLFSSL_MSG("CRL connection failed"); + } + else if (wolfIO_Send(sfd, (char*)httpBuf, httpBufSz, 0) + != httpBufSz) { + WOLFSSL_MSG("CRL http get failed"); + } + else { + ret = wolfIO_HttpProcessResponseCrl(crl, sfd, httpBuf, + HTTP_SCRATCH_BUFFER_SIZE); + } + + CloseSocket(sfd); + XFREE(httpBuf, crl->heap, DYNAMIC_TYPE_CRL); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(domainName, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} +#endif /* HAVE_CRL && HAVE_CRL_IO */ + +#endif /* HAVE_HTTP_CLIENT */ + + + +void wolfSSL_CTX_SetIORecv(WOLFSSL_CTX *ctx, CallbackIORecv CBIORecv) +{ + if (ctx) { + ctx->CBIORecv = CBIORecv; + #ifdef OPENSSL_EXTRA + ctx->cbioFlag |= WOLFSSL_CBIO_RECV; + #endif + } +} + + +void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend) +{ + if (ctx) { + ctx->CBIOSend = CBIOSend; + #ifdef OPENSSL_EXTRA + ctx->cbioFlag |= WOLFSSL_CBIO_SEND; + #endif + } +} + + +/* sets the IO callback to use for receives at WOLFSSL level */ +void wolfSSL_SSLSetIORecv(WOLFSSL *ssl, CallbackIORecv CBIORecv) +{ + if (ssl) { + ssl->CBIORecv = CBIORecv; + #ifdef OPENSSL_EXTRA + ssl->cbioFlag |= WOLFSSL_CBIO_RECV; + #endif + } +} + + +/* sets the IO callback to use for sends at WOLFSSL level */ +void wolfSSL_SSLSetIOSend(WOLFSSL *ssl, CallbackIOSend CBIOSend) +{ + if (ssl) { + ssl->CBIOSend = CBIOSend; + #ifdef OPENSSL_EXTRA + ssl->cbioFlag |= WOLFSSL_CBIO_SEND; + #endif + } +} + + +void wolfSSL_SetIOReadCtx(WOLFSSL* ssl, void *rctx) +{ + if (ssl) + ssl->IOCB_ReadCtx = rctx; +} + + +void wolfSSL_SetIOWriteCtx(WOLFSSL* ssl, void *wctx) +{ + if (ssl) + ssl->IOCB_WriteCtx = wctx; +} + + +void* wolfSSL_GetIOReadCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->IOCB_ReadCtx; + + return NULL; +} + + +void* wolfSSL_GetIOWriteCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->IOCB_WriteCtx; + + return NULL; +} + + +void wolfSSL_SetIOReadFlags(WOLFSSL* ssl, int flags) +{ + if (ssl) + ssl->rflags = flags; +} + + +void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags) +{ + if (ssl) + ssl->wflags = flags; +} + + +#ifdef WOLFSSL_DTLS + +void wolfSSL_CTX_SetGenCookie(WOLFSSL_CTX* ctx, CallbackGenCookie cb) +{ + if (ctx) + ctx->CBIOCookie = cb; +} + + +void wolfSSL_SetCookieCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->IOCB_CookieCtx = ctx; +} + + +void* wolfSSL_GetCookieCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->IOCB_CookieCtx; + + return NULL; +} + +#ifdef WOLFSSL_SESSION_EXPORT + +void wolfSSL_CTX_SetIOGetPeer(WOLFSSL_CTX* ctx, CallbackGetPeer cb) +{ + if (ctx) + ctx->CBGetPeer = cb; +} + + +void wolfSSL_CTX_SetIOSetPeer(WOLFSSL_CTX* ctx, CallbackSetPeer cb) +{ + if (ctx) + ctx->CBSetPeer = cb; +} + +#endif /* WOLFSSL_SESSION_EXPORT */ +#endif /* WOLFSSL_DTLS */ + + +#ifdef HAVE_NETX + +/* The NetX receive callback + * return : bytes read, or error + */ +int NetX_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + NetX_Ctx* nxCtx = (NetX_Ctx*)ctx; + ULONG left; + ULONG total; + ULONG copied = 0; + UINT status; + + (void)ssl; + + if (nxCtx == NULL || nxCtx->nxSocket == NULL) { + WOLFSSL_MSG("NetX Recv NULL parameters"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + if (nxCtx->nxPacket == NULL) { + status = nx_tcp_socket_receive(nxCtx->nxSocket, &nxCtx->nxPacket, + nxCtx->nxWait); + if (status != NX_SUCCESS) { + WOLFSSL_MSG("NetX Recv receive error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + if (nxCtx->nxPacket) { + status = nx_packet_length_get(nxCtx->nxPacket, &total); + if (status != NX_SUCCESS) { + WOLFSSL_MSG("NetX Recv length get error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + left = total - nxCtx->nxOffset; + status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset, + buf, sz, &copied); + if (status != NX_SUCCESS) { + WOLFSSL_MSG("NetX Recv data extract offset error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + nxCtx->nxOffset += copied; + + if (copied == left) { + WOLFSSL_MSG("NetX Recv Drained packet"); + nx_packet_release(nxCtx->nxPacket); + nxCtx->nxPacket = NULL; + nxCtx->nxOffset = 0; + } + } + + return copied; +} + + +/* The NetX send callback + * return : bytes sent, or error + */ +int NetX_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + NetX_Ctx* nxCtx = (NetX_Ctx*)ctx; + NX_PACKET* packet; + NX_PACKET_POOL* pool; /* shorthand */ + UINT status; + + (void)ssl; + + if (nxCtx == NULL || nxCtx->nxSocket == NULL) { + WOLFSSL_MSG("NetX Send NULL parameters"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + pool = nxCtx->nxSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool; + status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET, + nxCtx->nxWait); + if (status != NX_SUCCESS) { + WOLFSSL_MSG("NetX Send packet alloc error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait); + if (status != NX_SUCCESS) { + nx_packet_release(packet); + WOLFSSL_MSG("NetX Send data append error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + status = nx_tcp_socket_send(nxCtx->nxSocket, packet, nxCtx->nxWait); + if (status != NX_SUCCESS) { + nx_packet_release(packet); + WOLFSSL_MSG("NetX Send socket send error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + return sz; +} + + +/* like set_fd, but for default NetX context */ +void wolfSSL_SetIO_NetX(WOLFSSL* ssl, NX_TCP_SOCKET* nxSocket, ULONG waitOption) +{ + if (ssl) { + ssl->nxCtx.nxSocket = nxSocket; + ssl->nxCtx.nxWait = waitOption; + } +} + +#endif /* HAVE_NETX */ + + +#ifdef MICRIUM + +/* Micrium uTCP/IP port, using the NetSock API + * TCP and UDP are currently supported with the callbacks below. + * + * WOLFSSL_SESSION_EXPORT is not yet supported, would need EmbedGetPeer() + * and EmbedSetPeer() callbacks implemented. + * + * HAVE_CRL is not yet supported, would need an EmbedCrlLookup() + * callback implemented. + * + * HAVE_OCSP is not yet supported, would need an EmbedOCSPLookup() + * callback implemented. + */ + +/* The Micrium uTCP/IP send callback + * return : bytes sent, or error + */ +int MicriumSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + NET_SOCK_ID sd = *(int*)ctx; + NET_SOCK_RTN_CODE ret; + NET_ERR err; + + ret = NetSock_TxData(sd, buf, sz, ssl->wflags, &err); + if (ret < 0) { + WOLFSSL_MSG("Embed Send error"); + + if (err == NET_ERR_TX) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + + } else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return ret; +} + +/* The Micrium uTCP/IP receive callback + * return : nb bytes read, or error + */ +int MicriumReceive(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + NET_SOCK_ID sd = *(int*)ctx; + NET_SOCK_RTN_CODE ret; + NET_ERR err; + +#ifdef WOLFSSL_DTLS + { + int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl); + if (wolfSSL_dtls(ssl) + && !wolfSSL_dtls_get_using_nonblock(ssl) + && dtls_timeout != 0) { + /* needs timeout in milliseconds */ + NetSock_CfgTimeoutRxQ_Set(sd, dtls_timeout * 1000, &err); + if (err != NET_SOCK_ERR_NONE) { + WOLFSSL_MSG("NetSock_CfgTimeoutRxQ_Set failed"); + } + } + } +#endif + + ret = NetSock_RxData(sd, buf, sz, ssl->rflags, &err); + if (ret < 0) { + WOLFSSL_MSG("Embed Receive error"); + + if (err == NET_ERR_RX || err == NET_SOCK_ERR_RX_Q_EMPTY || + err == NET_ERR_FAULT_LOCK_ACQUIRE) { + if (!wolfSSL_dtls(ssl) || wolfSSL_dtls_get_using_nonblock(ssl)) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tSocket timeout"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + + } else if (err == NET_SOCK_ERR_CLOSED) { + WOLFSSL_MSG("Embed receive connection closed"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + + } else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return ret; +} + +/* The Micrium uTCP/IP receivefrom callback + * return : nb bytes read, or error + */ +int MicriumReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx; + NET_SOCK_ID sd = dtlsCtx->rfd; + NET_SOCK_ADDR peer; + NET_SOCK_ADDR_LEN peerSz = sizeof(peer); + NET_SOCK_RTN_CODE ret; + NET_ERR err; + int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl); + + WOLFSSL_ENTER("MicriumReceiveFrom()"); + + if (ssl->options.handShakeDone) + dtls_timeout = 0; + + if (!wolfSSL_dtls_get_using_nonblock(ssl)) { + /* needs timeout in milliseconds */ + NetSock_CfgTimeoutRxQ_Set(sd, dtls_timeout * 1000, &err); + if (err != NET_SOCK_ERR_NONE) { + WOLFSSL_MSG("NetSock_CfgTimeoutRxQ_Set failed"); + } + } + + ret = NetSock_RxDataFrom(sd, buf, sz, ssl->rflags, &peer, &peerSz, + 0, 0, 0, &err); + if (ret < 0) { + WOLFSSL_MSG("Embed Receive From error"); + + if (err == NET_ERR_RX || err == NET_SOCK_ERR_RX_Q_EMPTY || + err == NET_ERR_FAULT_LOCK_ACQUIRE) { + if (wolfSSL_dtls_get_using_nonblock(ssl)) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tSocket timeout"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + } else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else { + if (dtlsCtx->peer.sz > 0 + && peerSz != (NET_SOCK_ADDR_LEN)dtlsCtx->peer.sz + && XMEMCMP(&peer, dtlsCtx->peer.sa, peerSz) != 0) { + WOLFSSL_MSG("\tIgnored packet from invalid peer"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + } + + return ret; +} + +/* The Micrium uTCP/IP sendto callback + * return : nb bytes sent, or error + */ +int MicriumSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx; + NET_SOCK_ID sd = dtlsCtx->wfd; + NET_SOCK_RTN_CODE ret; + NET_ERR err; + + WOLFSSL_ENTER("MicriumSendTo()"); + + ret = NetSock_TxDataTo(sd, buf, sz, ssl->wflags, + (NET_SOCK_ADDR*)dtlsCtx->peer.sa, + (NET_SOCK_ADDR_LEN)dtlsCtx->peer.sz, + &err); + if (err < 0) { + WOLFSSL_MSG("Embed Send To error"); + + if (err == NET_ERR_TX) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + + } else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return ret; +} + +/* Micrium DTLS Generate Cookie callback + * return : number of bytes copied into buf, or error + */ +int MicriumGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx) +{ + NET_SOCK_ADDR peer; + NET_SOCK_ADDR_LEN peerSz = sizeof(peer); + byte digest[WC_SHA_DIGEST_SIZE]; + int ret = 0; + + (void)ctx; + + XMEMSET(&peer, 0, sizeof(peer)); + if (wolfSSL_dtls_get_peer(ssl, (void*)&peer, + (unsigned int*)&peerSz) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("getpeername failed in MicriumGenerateCookie"); + return GEN_COOKIE_E; + } + + ret = wc_ShaHash((byte*)&peer, peerSz, digest); + if (ret != 0) + return ret; + + if (sz > WC_SHA_DIGEST_SIZE) + sz = WC_SHA_DIGEST_SIZE; + XMEMCPY(buf, digest, sz); + + return sz; +} + +#endif /* MICRIUM */ + +#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) + +#include +#include +#include + +#define MB_NAME "wolfssl_mb" + +typedef struct Mynewt_Ctx { + struct mn_socket *mnSocket; /* send/recv socket handler */ + struct mn_sockaddr_in mnSockAddrIn; /* socket address */ + struct os_mbuf *mnPacket; /* incoming packet handle + for short reads */ + int reading; /* reading flag */ + + /* private */ + void *mnMemBuffer; /* memory buffer for mempool */ + struct os_mempool mnMempool; /* mempool */ + struct os_mbuf_pool mnMbufpool; /* mbuf pool */ +} Mynewt_Ctx; + +void mynewt_ctx_clear(void *ctx) { + Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx; + if(!mynewt_ctx) return; + + if(mynewt_ctx->mnPacket) { + os_mbuf_free_chain(mynewt_ctx->mnPacket); + mynewt_ctx->mnPacket = NULL; + } + os_mempool_clear(&mynewt_ctx->mnMempool); + XFREE(mynewt_ctx->mnMemBuffer, 0, 0); + XFREE(mynewt_ctx, 0, 0); +} + +/* return Mynewt_Ctx instance */ +void* mynewt_ctx_new() { + int rc = 0; + Mynewt_Ctx *mynewt_ctx; + int mem_buf_count = MYNEWT_VAL(WOLFSSL_MNSOCK_MEM_BUF_COUNT); + int mem_buf_size = MYNEWT_VAL(WOLFSSL_MNSOCK_MEM_BUF_SIZE); + int mempool_bytes = OS_MEMPOOL_BYTES(mem_buf_count, mem_buf_size); + + mynewt_ctx = (Mynewt_Ctx *)XMALLOC(sizeof(struct Mynewt_Ctx), + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if(!mynewt_ctx) return NULL; + + XMEMSET(mynewt_ctx, 0, sizeof(Mynewt_Ctx)); + mynewt_ctx->mnMemBuffer = XMALLOC(mempool_bytes, 0, 0); + if(!mynewt_ctx->mnMemBuffer) { + mynewt_ctx_clear((void*)mynewt_ctx); + return NULL; + } + + rc = os_mempool_init(&mynewt_ctx->mnMempool, + mem_buf_count, mem_buf_size, + mynewt_ctx->mnMemBuffer, MB_NAME); + if(rc != 0) { + mynewt_ctx_clear((void*)mynewt_ctx); + return NULL; + } + rc = os_mbuf_pool_init(&mynewt_ctx->mnMbufpool, &mynewt_ctx->mnMempool, + mem_buf_count, mem_buf_size); + if(rc != 0) { + mynewt_ctx_clear((void*)mynewt_ctx); + return NULL; + } + + return mynewt_ctx; +} + +static void mynewt_sock_writable(void *arg, int err); +static void mynewt_sock_readable(void *arg, int err); +static const union mn_socket_cb mynewt_sock_cbs = { + .socket.writable = mynewt_sock_writable, + .socket.readable = mynewt_sock_readable, +}; +static void mynewt_sock_writable(void *arg, int err) +{ + /* do nothing */ +} +static void mynewt_sock_readable(void *arg, int err) +{ + Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx *)arg; + if (err && mynewt_ctx->reading) { + mynewt_ctx->reading = 0; + } +} + +/* The Mynewt receive callback + * return : bytes read, or error + */ +int Mynewt_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx; + int rc = 0; + struct mn_sockaddr_in from; + struct os_mbuf *m; + int read_sz = 0; + uint16_t total; + + if (mynewt_ctx == NULL || mynewt_ctx->mnSocket == NULL) { + WOLFSSL_MSG("Mynewt Recv NULL parameters"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + + if(mynewt_ctx->mnPacket == NULL) { + mynewt_ctx->mnPacket = os_mbuf_get_pkthdr(&mynewt_ctx->mnMbufpool, 0); + if(mynewt_ctx->mnPacket == NULL) { + return MEMORY_E; + } + + mynewt_ctx->reading = 1; + while(mynewt_ctx->reading && rc == 0) { + rc = mn_recvfrom(mynewt_ctx->mnSocket, &m, (struct mn_sockaddr *) &from); + if(rc == MN_ECONNABORTED) { + rc = 0; + mynewt_ctx->reading = 0; + break; + } + if (!(rc == 0 || rc == MN_EAGAIN)) { + WOLFSSL_MSG("Mynewt Recv receive error"); + mynewt_ctx->reading = 0; + break; + } + if(rc == 0) { + int len = OS_MBUF_PKTLEN(m); + if(len == 0) { + break; + } + rc = os_mbuf_appendfrom(mynewt_ctx->mnPacket, m, 0, len); + if(rc != 0) { + WOLFSSL_MSG("Mynewt Recv os_mbuf_appendfrom error"); + break; + } + os_mbuf_free_chain(m); + m = NULL; + } else if(rc == MN_EAGAIN) { + /* continue to until reading all of packet data. */ + rc = 0; + break; + } + } + if(rc != 0) { + mynewt_ctx->reading = 0; + os_mbuf_free_chain(mynewt_ctx->mnPacket); + mynewt_ctx->mnPacket = NULL; + return rc; + } + } + + if(mynewt_ctx->mnPacket) { + total = OS_MBUF_PKTLEN(mynewt_ctx->mnPacket); + read_sz = (total >= sz)? sz : total; + + os_mbuf_copydata(mynewt_ctx->mnPacket, 0, read_sz, (void*)buf); + os_mbuf_adj(mynewt_ctx->mnPacket, read_sz); + + if (read_sz == total) { + WOLFSSL_MSG("Mynewt Recv Drained packet"); + os_mbuf_free_chain(mynewt_ctx->mnPacket); + mynewt_ctx->mnPacket = NULL; + } + } + + return read_sz; +} + +/* The Mynewt send callback + * return : bytes sent, or error + */ +int Mynewt_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx; + int rc = 0; + struct os_mbuf *m; + int write_sz = 0; + m = os_msys_get_pkthdr(sz, 0); + if (!m) { + WOLFSSL_MSG("Mynewt Send os_msys_get_pkthdr error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + rc = os_mbuf_copyinto(m, 0, buf, sz); + if (rc != 0) { + WOLFSSL_MSG("Mynewt Send os_mbuf_copyinto error"); + os_mbuf_free_chain(m); + return rc; + } + rc = mn_sendto(mynewt_ctx->mnSocket, m, (struct mn_sockaddr *)&mynewt_ctx->mnSockAddrIn); + if(rc != 0) { + WOLFSSL_MSG("Mynewt Send mn_sendto error"); + os_mbuf_free_chain(m); + return rc; + } + write_sz = sz; + return write_sz; +} + +/* like set_fd, but for default NetX context */ +void wolfSSL_SetIO_Mynewt(WOLFSSL* ssl, struct mn_socket* mnSocket, struct mn_sockaddr_in* mnSockAddrIn) +{ + if (ssl && ssl->mnCtx) { + Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx *)ssl->mnCtx; + mynewt_ctx->mnSocket = mnSocket; + memcpy(&mynewt_ctx->mnSockAddrIn, mnSockAddrIn, sizeof(struct mn_sockaddr_in)); + mn_socket_set_cbs(mynewt_ctx->mnSocket, mnSocket, &mynewt_sock_cbs); + } +} + +#endif /* defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) */ + +#ifdef WOLFSSL_UIP +#include +#include + +/* uIP TCP/IP port, using the native tcp/udp socket api. + * TCP and UDP are currently supported with the callbacks below. + * + */ +/* The uIP tcp send callback + * return : bytes sent, or error + */ +int uIPSend(WOLFSSL* ssl, char* buf, int sz, void* _ctx) +{ + uip_wolfssl_ctx *ctx = (struct uip_wolfssl_ctx *)_ctx; + int ret; + unsigned int max_sendlen; + int total_written = 0; + (void)ssl; + do { + unsigned int bytes_left = sz - total_written; + max_sendlen = tcp_socket_max_sendlen(&ctx->conn.tcp); + if (bytes_left > max_sendlen) { + printf("Send limited by buffer\r\n"); + bytes_left = max_sendlen; + } + if (bytes_left == 0) { + printf("Buffer full!\r\n"); + break; + } + ret = tcp_socket_send(&ctx->conn.tcp, (unsigned char *)buf + total_written, bytes_left); + if (ret <= 0) + break; + total_written += ret; + } while(total_written < sz); + if (total_written == 0) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + return total_written; +} + +int uIPSendTo(WOLFSSL* ssl, char* buf, int sz, void* _ctx) +{ + uip_wolfssl_ctx *ctx = (struct uip_wolfssl_ctx *)_ctx; + int ret = 0; + (void)ssl; + ret = udp_socket_sendto(&ctx->conn.udp, (unsigned char *)buf, sz, &ctx->peer_addr, ctx->peer_port ); + if (ret == 0) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + return ret; +} + +/* The uIP uTCP/IP receive callback + * return : nb bytes read, or error + */ +int uIPReceive(WOLFSSL *ssl, char *buf, int sz, void *_ctx) +{ + uip_wolfssl_ctx *ctx = (uip_wolfssl_ctx *)_ctx; + if (!ctx || !ctx->ssl_rx_databuf) + return -1; + (void)ssl; + if (ctx->ssl_rb_len > 0) { + if (sz > ctx->ssl_rb_len - ctx->ssl_rb_off) + sz = ctx->ssl_rb_len - ctx->ssl_rb_off; + XMEMCPY(buf, ctx->ssl_rx_databuf + ctx->ssl_rb_off, sz); + ctx->ssl_rb_off += sz; + if (ctx->ssl_rb_off >= ctx->ssl_rb_len) { + ctx->ssl_rb_len = 0; + ctx->ssl_rb_off = 0; + } + return sz; + } else { + return WOLFSSL_CBIO_ERR_WANT_READ; + } +} + +/* uIP DTLS Generate Cookie callback + * return : number of bytes copied into buf, or error + */ +int uIPGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *_ctx) +{ + uip_wolfssl_ctx *ctx = (uip_wolfssl_ctx *)_ctx; + byte token[32]; + byte digest[WC_SHA_DIGEST_SIZE]; + int ret = 0; + XMEMSET(token, 0, sizeof(token)); + XMEMCPY(token, &ctx->peer_addr, sizeof(uip_ipaddr_t)); + XMEMCPY(token + sizeof(uip_ipaddr_t), &ctx->peer_port, sizeof(word16)); + ret = wc_ShaHash(token, sizeof(uip_ipaddr_t) + sizeof(word16), digest); + if (ret != 0) + return ret; + if (sz > WC_SHA_DIGEST_SIZE) + sz = WC_SHA_DIGEST_SIZE; + XMEMCPY(buf, digest, sz); + return sz; +} + +#endif /* WOLFSSL_UIP */ + +#ifdef WOLFSSL_GNRC + +#include +#include +#include + +/* GNRC TCP/IP port, using the native tcp/udp socket api. + * TCP and UDP are currently supported with the callbacks below. + * + */ +/* The GNRC tcp send callback + * return : bytes sent, or error + */ + +int GNRC_SendTo(WOLFSSL* ssl, char* buf, int sz, void* _ctx) +{ + sock_tls_t *ctx = (sock_tls_t *)_ctx; + int ret = 0; + (void)ssl; + if (!ctx) + return WOLFSSL_CBIO_ERR_GENERAL; + ret = sock_udp_send(&ctx->conn.udp, (unsigned char *)buf, sz, &ctx->peer_addr); + if (ret == 0) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + return ret; +} + +/* The GNRC TCP/IP receive callback + * return : nb bytes read, or error + */ +int GNRC_ReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *_ctx) +{ + sock_udp_ep_t ep; + int ret; + uint32_t timeout = wolfSSL_dtls_get_current_timeout(ssl) * 1000000; + sock_tls_t *ctx = (sock_tls_t *)_ctx; + if (!ctx) + return WOLFSSL_CBIO_ERR_GENERAL; + (void)ssl; + if (wolfSSL_get_using_nonblock(ctx->ssl)) { + timeout = 0; + } + ret = sock_udp_recv(&ctx->conn.udp, buf, sz, timeout, &ep); + if (ret > 0) { + if (ctx->peer_addr.port == 0) + XMEMCPY(&ctx->peer_addr, &ep, sizeof(sock_udp_ep_t)); + } + if (ret == -ETIMEDOUT) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + return ret; +} + +/* GNRC DTLS Generate Cookie callback + * return : number of bytes copied into buf, or error + */ +#define GNRC_MAX_TOKEN_SIZE (32) +int GNRC_GenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *_ctx) +{ + sock_tls_t *ctx = (sock_tls_t *)_ctx; + if (!ctx) + return WOLFSSL_CBIO_ERR_GENERAL; + byte token[GNRC_MAX_TOKEN_SIZE]; + byte digest[WC_SHA_DIGEST_SIZE]; + int ret = 0; + size_t token_size = sizeof(sock_udp_ep_t); + (void)ssl; + if (token_size > GNRC_MAX_TOKEN_SIZE) + token_size = GNRC_MAX_TOKEN_SIZE; + XMEMSET(token, 0, GNRC_MAX_TOKEN_SIZE); + XMEMCPY(token, &ctx->peer_addr, token_size); + ret = wc_ShaHash(token, token_size, digest); + if (ret != 0) + return ret; + if (sz > WC_SHA_DIGEST_SIZE) + sz = WC_SHA_DIGEST_SIZE; + XMEMCPY(buf, digest, sz); + return sz; +} + +#endif /* WOLFSSL_GNRC */ + +#endif /* WOLFCRYPT_ONLY */ -- cgit v1.2.3