| /* ssl.c |
| * |
| * Copyright (C) 2006-2015 wolfSSL Inc. |
| * |
| * This file is part of wolfSSL. (formerly known as CyaSSL) |
| * |
| * 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-1301, USA |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <wolfssl/wolfcrypt/settings.h> |
| |
| #ifdef HAVE_ERRNO_H |
| #include <errno.h> |
| #endif |
| |
| #include <wolfssl/internal.h> |
| #include <wolfssl/error-ssl.h> |
| #include <wolfssl/wolfcrypt/coding.h> |
| |
| #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) |
| #include <wolfssl/openssl/evp.h> |
| #endif |
| |
| #ifdef OPENSSL_EXTRA |
| /* openssl headers begin */ |
| #include <wolfssl/openssl/hmac.h> |
| #include <wolfssl/openssl/crypto.h> |
| #include <wolfssl/openssl/des.h> |
| #include <wolfssl/openssl/bn.h> |
| #include <wolfssl/openssl/dh.h> |
| #include <wolfssl/openssl/rsa.h> |
| #include <wolfssl/openssl/pem.h> |
| /* openssl headers end, wolfssl internal headers next */ |
| #include <wolfssl/wolfcrypt/hmac.h> |
| #include <wolfssl/wolfcrypt/random.h> |
| #include <wolfssl/wolfcrypt/des3.h> |
| #include <wolfssl/wolfcrypt/md4.h> |
| #include <wolfssl/wolfcrypt/md5.h> |
| #include <wolfssl/wolfcrypt/arc4.h> |
| #ifdef WOLFSSL_SHA512 |
| #include <wolfssl/wolfcrypt/sha512.h> |
| #endif |
| #endif |
| |
| #ifndef NO_FILESYSTEM |
| #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR) \ |
| && !defined(EBSNET) |
| #include <dirent.h> |
| #include <sys/stat.h> |
| #endif |
| #ifdef EBSNET |
| #include "vfapi.h" |
| #include "vfile.h" |
| #endif |
| #endif /* NO_FILESYSTEM */ |
| |
| #ifndef TRUE |
| #define TRUE 1 |
| #endif |
| #ifndef FALSE |
| #define FALSE 0 |
| #endif |
| |
| #ifndef WOLFSSL_HAVE_MIN |
| #define WOLFSSL_HAVE_MIN |
| |
| static INLINE word32 min(word32 a, word32 b) |
| { |
| return a > b ? b : a; |
| } |
| |
| #endif /* WOLFSSSL_HAVE_MIN */ |
| |
| #ifndef WOLFSSL_HAVE_MAX |
| #define WOLFSSL_HAVE_MAX |
| |
| #ifdef WOLFSSL_DTLS |
| static INLINE word32 max(word32 a, word32 b) |
| { |
| return a > b ? a : b; |
| } |
| #endif /* WOLFSSL_DTLS */ |
| |
| #endif /* WOLFSSL_HAVE_MAX */ |
| |
| |
| #ifndef WOLFSSL_LEANPSK |
| char* mystrnstr(const char* s1, const char* s2, unsigned int n) |
| { |
| unsigned int s2_len = (unsigned int)XSTRLEN(s2); |
| |
| if (s2_len == 0) |
| return (char*)s1; |
| |
| while (n >= s2_len && s1[0]) { |
| if (s1[0] == s2[0]) |
| if (XMEMCMP(s1, s2, s2_len) == 0) |
| return (char*)s1; |
| s1++; |
| n--; |
| } |
| |
| return NULL; |
| } |
| #endif |
| |
| |
| /* prevent multiple mutex initializations */ |
| static volatile int initRefCount = 0; |
| static wolfSSL_Mutex count_mutex; /* init ref count mutex */ |
| |
| |
| WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD* method) |
| { |
| WOLFSSL_CTX* ctx = NULL; |
| |
| WOLFSSL_ENTER("WOLFSSL_CTX_new"); |
| |
| if (initRefCount == 0) |
| wolfSSL_Init(); /* user no longer forced to call Init themselves */ |
| |
| if (method == NULL) |
| return ctx; |
| |
| ctx = (WOLFSSL_CTX*) XMALLOC(sizeof(WOLFSSL_CTX), 0, DYNAMIC_TYPE_CTX); |
| if (ctx) { |
| if (InitSSL_Ctx(ctx, method) < 0) { |
| WOLFSSL_MSG("Init CTX failed"); |
| wolfSSL_CTX_free(ctx); |
| ctx = NULL; |
| } |
| } |
| else { |
| WOLFSSL_MSG("Alloc CTX failed, method freed"); |
| XFREE(method, NULL, DYNAMIC_TYPE_METHOD); |
| } |
| |
| WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0); |
| return ctx; |
| } |
| |
| |
| void wolfSSL_CTX_free(WOLFSSL_CTX* ctx) |
| { |
| WOLFSSL_ENTER("SSL_CTX_free"); |
| if (ctx) |
| FreeSSL_Ctx(ctx); |
| WOLFSSL_LEAVE("SSL_CTX_free", 0); |
| } |
| |
| |
| 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) { |
| FreeSSL(ssl); |
| ssl = 0; |
| } |
| |
| WOLFSSL_LEAVE("SSL_new", ret); |
| return ssl; |
| } |
| |
| |
| void wolfSSL_free(WOLFSSL* ssl) |
| { |
| WOLFSSL_ENTER("SSL_free"); |
| if (ssl) |
| FreeSSL(ssl); |
| WOLFSSL_LEAVE("SSL_free", 0); |
| } |
| |
| #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) |
| { |
| WOLFSSL_ENTER("SSL_use_old_poly"); |
| ssl->options.oldPoly = value; |
| WOLFSSL_LEAVE("SSL_use_old_poly", 0); |
| return 0; |
| } |
| #endif |
| |
| int wolfSSL_set_fd(WOLFSSL* ssl, int fd) |
| { |
| WOLFSSL_ENTER("SSL_set_fd"); |
| ssl->rfd = fd; /* not used directly to allow IO callbacks */ |
| ssl->wfd = fd; |
| |
| ssl->IOCB_ReadCtx = &ssl->rfd; |
| ssl->IOCB_WriteCtx = &ssl->wfd; |
| |
| #ifdef WOLFSSL_DTLS |
| if (ssl->options.dtls) { |
| ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx; |
| ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx; |
| ssl->buffers.dtlsCtx.fd = fd; |
| } |
| #endif |
| |
| WOLFSSL_LEAVE("SSL_set_fd", SSL_SUCCESS); |
| return SSL_SUCCESS; |
| } |
| |
| |
| /** |
| * Get the name of cipher at priotity level passed in. |
| */ |
| char* wolfSSL_get_cipher_list(int priority) |
| { |
| const char* const* ciphers = GetCipherNames(); |
| |
| if (priority >= GetCipherNamesSize() || priority < 0) { |
| return 0; |
| } |
| |
| return (char*)ciphers[priority]; |
| } |
| |
| |
| int wolfSSL_get_ciphers(char* buf, int len) |
| { |
| const char* const* ciphers = GetCipherNames(); |
| int totalInc = 0; |
| int step = 0; |
| char delim = ':'; |
| int size = GetCipherNamesSize(); |
| int i; |
| |
| if (buf == NULL || len <= 0) |
| return BAD_FUNC_ARG; |
| |
| /* Add each member to the buffer delimitted by a : */ |
| for (i = 0; i < size; i++) { |
| step = (int)(XSTRLEN(ciphers[i]) + 1); /* delimiter */ |
| totalInc += step; |
| |
| /* Check to make sure buf is large enough and will not overflow */ |
| if (totalInc < len) { |
| XSTRNCPY(buf, ciphers[i], XSTRLEN(ciphers[i])); |
| buf += XSTRLEN(ciphers[i]); |
| |
| if (i < size - 1) |
| *buf++ = delim; |
| } |
| else |
| return BUFFER_E; |
| } |
| return SSL_SUCCESS; |
| } |
| |
| |
| int wolfSSL_get_fd(const WOLFSSL* ssl) |
| { |
| WOLFSSL_ENTER("SSL_get_fd"); |
| WOLFSSL_LEAVE("SSL_get_fd", ssl->rfd); |
| return ssl->rfd; |
| } |
| |
| |
| int wolfSSL_get_using_nonblock(WOLFSSL* ssl) |
| { |
| WOLFSSL_ENTER("wolfSSL_get_using_nonblock"); |
| WOLFSSL_LEAVE("wolfSSL_get_using_nonblock", ssl->options.usingNonblock); |
| return ssl->options.usingNonblock; |
| } |
| |
| |
| int wolfSSL_dtls(WOLFSSL* ssl) |
| { |
| return ssl->options.dtls; |
| } |
| |
| |
| #ifndef WOLFSSL_LEANPSK |
| void wolfSSL_set_using_nonblock(WOLFSSL* ssl, int nonblock) |
| { |
| WOLFSSL_ENTER("wolfSSL_set_using_nonblock"); |
| ssl->options.usingNonblock = (nonblock != 0); |
| } |
| |
| |
| int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) |
| { |
| #ifdef WOLFSSL_DTLS |
| void* 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); |
| XMEMCPY(sa, peer, peerSz); |
| ssl->buffers.dtlsCtx.peer.sa = sa; |
| ssl->buffers.dtlsCtx.peer.sz = peerSz; |
| return SSL_SUCCESS; |
| } |
| return SSL_FAILURE; |
| #else |
| (void)ssl; |
| (void)peer; |
| (void)peerSz; |
| return SSL_NOT_IMPLEMENTED; |
| #endif |
| } |
| |
| int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) |
| { |
| #ifdef WOLFSSL_DTLS |
| if (peer != NULL && peerSz != NULL |
| && *peerSz >= ssl->buffers.dtlsCtx.peer.sz) { |
| *peerSz = ssl->buffers.dtlsCtx.peer.sz; |
| XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); |
| return SSL_SUCCESS; |
| } |
| return SSL_FAILURE; |
| #else |
| (void)ssl; |
| (void)peer; |
| (void)peerSz; |
| return SSL_NOT_IMPLEMENTED; |
| #endif |
| } |
| #endif /* WOLFSSL_LEANPSK */ |
| |
| |
| /* return underlyig connect or accept, SSL_SUCCESS on ok */ |
| int wolfSSL_negotiate(WOLFSSL* ssl) |
| { |
| int err = SSL_FATAL_ERROR; |
| |
| WOLFSSL_ENTER("wolfSSL_negotiate"); |
| #ifndef NO_WOLFSSL_SERVER |
| if (ssl->options.side == WOLFSSL_SERVER_END) |
| err = wolfSSL_accept(ssl); |
| #endif |
| |
| #ifndef NO_WOLFSSL_CLIENT |
| if (ssl->options.side == WOLFSSL_CLIENT_END) |
| err = wolfSSL_connect(ssl); |
| #endif |
| |
| WOLFSSL_LEAVE("wolfSSL_negotiate", err); |
| |
| return err; |
| } |
| |
| |
| #ifndef WOLFSSL_LEANPSK |
| /* object size based on build */ |
| int wolfSSL_GetObjectSize(void) |
| { |
| #ifdef SHOW_SIZES |
| printf("sizeof suites = %lu\n", sizeof(Suites)); |
| printf("sizeof ciphers(2) = %lu\n", sizeof(Ciphers)); |
| #ifndef NO_RC4 |
| printf(" sizeof arc4 = %lu\n", sizeof(Arc4)); |
| #endif |
| printf(" sizeof aes = %lu\n", sizeof(Aes)); |
| #ifndef NO_DES3 |
| printf(" sizeof des3 = %lu\n", sizeof(Des3)); |
| #endif |
| #ifndef NO_RABBIT |
| printf(" sizeof rabbit = %lu\n", sizeof(Rabbit)); |
| #endif |
| #ifdef HAVE_CHACHA |
| printf(" sizeof chacha = %lu\n", sizeof(Chacha)); |
| #endif |
| printf("sizeof cipher specs = %lu\n", sizeof(CipherSpecs)); |
| printf("sizeof keys = %lu\n", sizeof(Keys)); |
| printf("sizeof Hashes(2) = %lu\n", sizeof(Hashes)); |
| #ifndef NO_MD5 |
| printf(" sizeof MD5 = %lu\n", sizeof(Md5)); |
| #endif |
| #ifndef NO_SHA |
| printf(" sizeof SHA = %lu\n", sizeof(Sha)); |
| #endif |
| #ifndef NO_SHA256 |
| printf(" sizeof SHA256 = %lu\n", sizeof(Sha256)); |
| #endif |
| #ifdef WOLFSSL_SHA384 |
| printf(" sizeof SHA384 = %lu\n", sizeof(Sha384)); |
| #endif |
| #ifdef WOLFSSL_SHA384 |
| printf(" sizeof SHA512 = %lu\n", sizeof(Sha512)); |
| #endif |
| printf("sizeof Buffers = %lu\n", sizeof(Buffers)); |
| printf("sizeof Options = %lu\n", sizeof(Options)); |
| printf("sizeof Arrays = %lu\n", sizeof(Arrays)); |
| #ifndef NO_RSA |
| printf("sizeof RsaKey = %lu\n", sizeof(RsaKey)); |
| #endif |
| #ifdef HAVE_ECC |
| printf("sizeof ecc_key = %lu\n", sizeof(ecc_key)); |
| #endif |
| printf("sizeof WOLFSSL_CIPHER = %lu\n", sizeof(WOLFSSL_CIPHER)); |
| printf("sizeof WOLFSSL_SESSION = %lu\n", sizeof(WOLFSSL_SESSION)); |
| printf("sizeof WOLFSSL = %lu\n", sizeof(WOLFSSL)); |
| printf("sizeof WOLFSSL_CTX = %lu\n", sizeof(WOLFSSL_CTX)); |
| #endif |
| |
| return sizeof(WOLFSSL); |
| } |
| #endif |
| |
| |
| #ifndef NO_DH |
| /* server Diffie-Hellman parameters, SSL_SUCCESS on ok */ |
| int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, |
| const unsigned char* g, int gSz) |
| { |
| byte havePSK = 0; |
| byte haveRSA = 1; |
| |
| WOLFSSL_ENTER("wolfSSL_SetTmpDH"); |
| if (ssl == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; |
| |
| if (pSz < ssl->options.minDhKeySz) |
| return DH_KEY_SIZE_E; |
| |
| if (ssl->options.side != WOLFSSL_SERVER_END) |
| return SIDE_ERROR; |
| |
| if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) |
| XFREE(ssl->buffers.serverDH_P.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH); |
| if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) |
| XFREE(ssl->buffers.serverDH_G.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH); |
| |
| ssl->buffers.weOwnDH = 1; /* SSL owns now */ |
| ssl->buffers.serverDH_P.buffer = (byte*)XMALLOC(pSz, ssl->ctx->heap, |
| DYNAMIC_TYPE_DH); |
| if (ssl->buffers.serverDH_P.buffer == NULL) |
| return MEMORY_E; |
| |
| ssl->buffers.serverDH_G.buffer = (byte*)XMALLOC(gSz, ssl->ctx->heap, |
| DYNAMIC_TYPE_DH); |
| if (ssl->buffers.serverDH_G.buffer == NULL) { |
| XFREE(ssl->buffers.serverDH_P.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH); |
| 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; |
| #ifndef NO_PSK |
| havePSK = ssl->options.havePSK; |
| #endif |
| #ifdef NO_RSA |
| haveRSA = 0; |
| #endif |
| InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, ssl->options.haveDH, |
| ssl->options.haveNTRU, ssl->options.haveECDSAsig, |
| ssl->options.haveStaticECC, ssl->options.side); |
| |
| WOLFSSL_LEAVE("wolfSSL_SetTmpDH", 0); |
| return SSL_SUCCESS; |
| } |
| |
| /* server ctx Diffie-Hellman parameters, SSL_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 (pSz < ctx->minDhKeySz) |
| return DH_KEY_SIZE_E; |
| |
| XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH); |
| XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH); |
| |
| ctx->serverDH_P.buffer = (byte*)XMALLOC(pSz, ctx->heap,DYNAMIC_TYPE_DH); |
| if (ctx->serverDH_P.buffer == NULL) |
| return MEMORY_E; |
| |
| ctx->serverDH_G.buffer = (byte*)XMALLOC(gSz, ctx->heap,DYNAMIC_TYPE_DH); |
| if (ctx->serverDH_G.buffer == NULL) { |
| XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH); |
| 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 SSL_SUCCESS; |
| } |
| |
| #endif /* !NO_DH */ |
| |
| |
| 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 HAVE_ERRNO_H |
| errno = 0; |
| #endif |
| |
| ret = SendData(ssl, data, sz); |
| |
| WOLFSSL_LEAVE("SSL_write()", ret); |
| |
| if (ret < 0) |
| return SSL_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_ERRNO_H |
| errno = 0; |
| #endif |
| #ifdef WOLFSSL_DTLS |
| if (ssl->options.dtls) |
| ssl->dtls_expected_rx = max(sz + 100, MAX_MTU); |
| #endif |
| |
| #ifdef HAVE_MAX_FRAGMENT |
| ret = ReceiveData(ssl, (byte*)data, |
| min(sz, min(ssl->max_fragment, OUTPUT_RECORD_SIZE)), peek); |
| #else |
| ret = ReceiveData(ssl, (byte*)data, min(sz, OUTPUT_RECORD_SIZE), peek); |
| #endif |
| |
| WOLFSSL_LEAVE("wolfSSL_read_internal()", ret); |
| |
| if (ret < 0) |
| return SSL_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); |
| } |
| |
| |
| int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) |
| { |
| WOLFSSL_ENTER("wolfSSL_read()"); |
| |
| return wolfSSL_read_internal(ssl, data, sz, FALSE); |
| } |
| |
| |
| #ifdef HAVE_CAVIUM |
| |
| /* let's use cavium, SSL_SUCCESS on ok */ |
| int wolfSSL_UseCavium(WOLFSSL* ssl, int devId) |
| { |
| if (ssl == NULL) |
| return BAD_FUNC_ARG; |
| |
| ssl->devId = devId; |
| |
| return SSL_SUCCESS; |
| } |
| |
| |
| /* let's use cavium, SSL_SUCCESS on ok */ |
| int wolfSSL_CTX_UseCavium(WOLFSSL_CTX* ctx, int devId) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| ctx->devId = devId; |
| |
| return SSL_SUCCESS; |
| } |
| |
| |
| #endif /* HAVE_CAVIUM */ |
| |
| #ifdef HAVE_SNI |
| |
| 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); |
| } |
| |
| 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); |
| } |
| |
| #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_MAX_FRAGMENT |
| #ifndef NO_WOLFSSL_CLIENT |
| int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) |
| { |
| if (ssl == NULL) |
| return BAD_FUNC_ARG; |
| |
| return TLSX_UseMaxFragment(&ssl->extensions, mfl); |
| } |
| |
| int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| return TLSX_UseMaxFragment(&ctx->extensions, mfl); |
| } |
| #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); |
| } |
| |
| int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| return TLSX_UseTruncatedHMAC(&ctx->extensions); |
| } |
| #endif /* NO_WOLFSSL_CLIENT */ |
| #endif /* HAVE_TRUNCATED_HMAC */ |
| |
| /* Elliptic Curves */ |
| #ifdef HAVE_SUPPORTED_CURVES |
| #ifndef NO_WOLFSSL_CLIENT |
| |
| int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) |
| { |
| if (ssl == NULL) |
| return BAD_FUNC_ARG; |
| |
| switch (name) { |
| case WOLFSSL_ECC_SECP160R1: |
| case WOLFSSL_ECC_SECP192R1: |
| case WOLFSSL_ECC_SECP224R1: |
| case WOLFSSL_ECC_SECP256R1: |
| case WOLFSSL_ECC_SECP384R1: |
| case WOLFSSL_ECC_SECP521R1: |
| break; |
| |
| default: |
| return BAD_FUNC_ARG; |
| } |
| |
| return TLSX_UseSupportedCurve(&ssl->extensions, name); |
| } |
| |
| int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| switch (name) { |
| case WOLFSSL_ECC_SECP160R1: |
| case WOLFSSL_ECC_SECP192R1: |
| case WOLFSSL_ECC_SECP224R1: |
| case WOLFSSL_ECC_SECP256R1: |
| case WOLFSSL_ECC_SECP384R1: |
| case WOLFSSL_ECC_SECP521R1: |
| break; |
| |
| default: |
| return BAD_FUNC_ARG; |
| } |
| |
| return TLSX_UseSupportedCurve(&ctx->extensions, name); |
| } |
| |
| #endif /* NO_WOLFSSL_CLIENT */ |
| #endif /* HAVE_SUPPORTED_CURVES */ |
| |
| /* 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); |
| |
| if (ret == SSL_SUCCESS) { |
| TLSX* extension = TLSX_Find(ssl->extensions, SECURE_RENEGOTIATION); |
| |
| if (extension) |
| ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; |
| } |
| |
| return ret; |
| } |
| |
| |
| /* do a secure renegotiation handshake, user forced, we discourage */ |
| int wolfSSL_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 (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.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 = 0; /* TODO, move states in internal.h */ |
| |
| XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); |
| |
| ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; |
| |
| #ifndef NO_OLD_TLS |
| #ifndef NO_MD5 |
| wc_InitMd5(&ssl->hsHashes->hashMd5); |
| #endif |
| #ifndef NO_SHA |
| ret = wc_InitSha(&ssl->hsHashes->hashSha); |
| if (ret !=0) |
| return ret; |
| #endif |
| #endif /* NO_OLD_TLS */ |
| #ifndef NO_SHA256 |
| ret = wc_InitSha256(&ssl->hsHashes->hashSha256); |
| if (ret !=0) |
| return ret; |
| #endif |
| #ifdef WOLFSSL_SHA384 |
| ret = wc_InitSha384(&ssl->hsHashes->hashSha384); |
| if (ret !=0) |
| return ret; |
| #endif |
| #ifdef WOLFSSL_SHA512 |
| ret = wc_InitSha512(&ssl->hsHashes->hashSha512); |
| if (ret !=0) |
| return ret; |
| #endif |
| |
| ret = wolfSSL_negotiate(ssl); |
| return ret; |
| } |
| |
| #endif /* HAVE_SECURE_RENEGOTIATION */ |
| |
| /* Session Ticket */ |
| #if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SESSION_TICKET) |
| /* SSL_SUCCESS on ok */ |
| int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| ctx->ticketEncCb = cb; |
| |
| return SSL_SUCCESS; |
| } |
| |
| /* set hint interval, SSL_SUCCESS on ok */ |
| int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| ctx->ticketHint = hint; |
| |
| return SSL_SUCCESS; |
| } |
| |
| /* set user context, SSL_SUCCESS on ok */ |
| int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| ctx->ticketEncCtx = userCtx; |
| |
| return SSL_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); |
| } |
| |
| int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) |
| { |
| if (ctx == NULL) |
| return BAD_FUNC_ARG; |
| |
| return TLSX_UseSessionTicket(&ctx->extensions, NULL); |
| } |
| |
| 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 SSL_SUCCESS; |
| } |
| |
| WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL* ssl, byte* buf, word32 bufSz) |
| { |
| if (ssl == NULL || (buf == NULL && bufSz > 0)) |
| return BAD_FUNC_ARG; |
| |
| if (bufSz > 0) |
| XMEMCPY(ssl->session.ticket, buf, bufSz); |
| ssl->session.ticketLen = (word16)bufSz; |
| |
| return SSL_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 SSL_SUCCESS; |
| } |
| #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 |
| |
| |
| /* SSL_SUCCESS on ok */ |
| int wolfSSL_shutdown(WOLFSSL* ssl) |
| { |
| int ret = SSL_FATAL_ERROR; |
| byte tmp; |
| WOLFSSL_ENTER("SSL_shutdown()"); |
| |
| if (ssl == NULL) |
| return SSL_FATAL_ERROR; |
| |
| if (ssl->options.quietShutdown) { |
| WOLFSSL_MSG("quiet shutdown, no close notify sent"); |
| return SSL_SUCCESS; |
| } |
| |
| /* 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 SSL_FATAL_ERROR; |
| } |
| ssl->options.sentNotify = 1; /* don't send close_notify twice */ |
| if (ssl->options.closeNotify) |
| ret = SSL_SUCCESS; |
| else |
| ret = SSL_SHUTDOWN_NOT_DONE; |
| |
| WOLFSSL_LEAVE("SSL_shutdown()", ret); |
| return ret; |
| } |
| |
| /* call wolfSSL_shutdown again for bidirectional shudown */ |
| if (ssl->options.sentNotify && !ssl->options.closeNotify) { |
| ret = wolfSSL_read(ssl, &tmp, 0); |
| if (ret < 0) { |
| WOLFSSL_ERROR(ssl->error); |
| ret = SSL_FATAL_ERROR; |
| } else if (ssl->options.closeNotify) { |
| ssl->error = SSL_ERROR_SYSCALL; /* simulate OpenSSL behavior */ |
| ret = SSL_SUCCESS; |
| } |
| } |
| |
| WOLFSSL_LEAVE("SSL_shutdown()", ret); |
| |
| return ret; |
| } |
| |
| |
| int wolfSSL_get_error(WOLFSSL* ssl, int ret) |
| { |
| WOLFSSL_ENTER("SSL_get_error"); |
| |
| if (ret > 0) |
| return SSL_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 SSL_ERROR_WANT_READ; /* convert to OpenSSL type */ |
| else if (ssl->error == WANT_WRITE) |
| return SSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ |
| else if (ssl->error == ZERO_RETURN) |
| return SSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ |
| return ssl->error; |
| } |
| |
| |
| /* retrive alert history, SSL_SUCCESS on ok */ |
| int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) |
| { |
| if (ssl && h) { |
| *h = ssl->alert_history; |
| } |
| return SSL_SUCCESS; |
| } |
| |
| |
| /* 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 const char* 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); |
| } |
| } |
| |
| |
| const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) |
| { |
| 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; |
| } |
| |
| |
| #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; |
| } |
| |
| |
| 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; |
| |
| if (ssl->specs.cipher_type == block) |
| return WOLFSSL_BLOCK_TYPE; |
| if (ssl->specs.cipher_type == stream) |
| return WOLFSSL_STREAM_TYPE; |
| 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_CertManagerNew(void) |
| { |
| WOLFSSL_CERT_MANAGER* cm = NULL; |
| |
| WOLFSSL_ENTER("wolfSSL_CertManagerNew"); |
| |
| cm = (WOLFSSL_CERT_MANAGER*) XMALLOC(sizeof(WOLFSSL_CERT_MANAGER), 0, |
| DYNAMIC_TYPE_CERT_MANAGER); |
| if (cm) { |
| XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER)); |
| |
| if (InitMutex(&cm->caLock) != 0) { |
| WOLFSSL_MSG("Bad mutex init"); |
| wolfSSL_CertManagerFree(cm); |
| return NULL; |
| } |
| } |
| |
| return cm; |
| } |
| |
| |
| 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); |
| #endif |
| FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL); |
| FreeMutex(&cm->caLock); |
| XFREE(cm, NULL, DYNAMIC_TYPE_CERT_MANAGER); |
| } |
| |
| } |
| |
| |
| /* Unload the CA signer list */ |
| int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) |
| { |
| WOLFSSL_ENTER("wolfSSL_CertManagerUnloadCAs"); |
| |
| if (cm == NULL) |
| return BAD_FUNC_ARG; |
| |
| if (LockMutex(&cm->caLock) != 0) |
| return BAD_MUTEX_E; |
| |
| FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL); |
| |
| UnLockMutex(&cm->caLock); |
| |
| |
| return SSL_SUCCESS; |
| } |
| |
| |
| /* Return bytes written to buff or < 0 for error */ |
| int wolfSSL_CertPemToDer(const unsigned char* pem, int pemSz, |
| unsigned char* buff, int buffSz, |
| int type) |
| { |
| int eccKey = 0; |
| int ret; |
| buffer der; |
| #ifdef WOLFSSL_SMALL_STACK |
| EncryptedInfo* info = NULL; |
| #else |
| EncryptedInfo info[1]; |
| #endif |
| |
| WOLFSSL_ENTER("wolfSSL_CertPemToDer"); |
| |
| if (pem == NULL || buff == NULL || buffSz <= 0) { |
| WOLFSSL_MSG("Bad pem der args"); |
| return BAD_FUNC_ARG; |
| } |
| |
| if (type != CERT_TYPE && type != CA_TYPE && type != CERTREQ_TYPE) { |
| WOLFSSL_MSG("Bad cert type"); |
| return BAD_FUNC_ARG; |
| } |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (info == NULL) |
| return MEMORY_E; |
| #endif |
| |
| info->set = 0; |
| info->ctx = NULL; |
| info->consumed = 0; |
| der.buffer = NULL; |
| |
| ret = PemToDer(pem, pemSz, type, &der, NULL, info, &eccKey); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| if (ret < 0) { |
| WOLFSSL_MSG("Bad Pem To Der"); |
| } |
| else { |
| if (der.length <= (word32)buffSz) { |
| XMEMCPY(buff, der.buffer, der.length); |
| ret = der.length; |
| } |
| else { |
| WOLFSSL_MSG("Bad der length"); |
| ret = BAD_FUNC_ARG; |
| } |
| } |
| |
| XFREE(der.buffer, NULL, DYNAMIC_TYPE_KEY); |
| |
| return ret; |
| } |
| |
| |
| #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) |
| |
| /* our KeyPemToDer password callback, password in userData */ |
| static INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata) |
| { |
| (void)rw; |
| |
| if (userdata == NULL) |
| return 0; |
| |
| XSTRNCPY(passwd, (char*)userdata, sz); |
| return min((word32)sz, (word32)XSTRLEN((char*)userdata)); |
| } |
| |
| #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ |
| |
| |
| /* Return bytes written to buff or < 0 for error */ |
| int wolfSSL_KeyPemToDer(const unsigned char* pem, int pemSz, unsigned char* buff, |
| int buffSz, const char* pass) |
| { |
| int eccKey = 0; |
| int ret; |
| buffer der; |
| #ifdef WOLFSSL_SMALL_STACK |
| EncryptedInfo* info = NULL; |
| #else |
| EncryptedInfo info[1]; |
| #endif |
| |
| (void)pass; |
| |
| WOLFSSL_ENTER("wolfSSL_KeyPemToDer"); |
| |
| if (pem == NULL || buff == NULL || buffSz <= 0) { |
| WOLFSSL_MSG("Bad pem der args"); |
| return BAD_FUNC_ARG; |
| } |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (info == NULL) |
| return MEMORY_E; |
| #endif |
| |
| info->set = 0; |
| info->ctx = NULL; |
| info->consumed = 0; |
| der.buffer = NULL; |
| |
| #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) |
| if (pass) { |
| info->ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); |
| if (info->ctx == NULL) { |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| return MEMORY_E; |
| } |
| |
| wolfSSL_CTX_set_default_passwd_cb(info->ctx, OurPasswordCb); |
| wolfSSL_CTX_set_default_passwd_cb_userdata(info->ctx, (void*)pass); |
| } |
| #endif |
| |
| ret = PemToDer(pem, pemSz, PRIVATEKEY_TYPE, &der, NULL, info, &eccKey); |
| |
| if (info->ctx) |
| wolfSSL_CTX_free(info->ctx); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| if (ret < 0) { |
| WOLFSSL_MSG("Bad Pem To Der"); |
| } |
| else { |
| if (der.length <= (word32)buffSz) { |
| XMEMCPY(buff, der.buffer, der.length); |
| ret = der.length; |
| } |
| else { |
| WOLFSSL_MSG("Bad der length"); |
| ret = BAD_FUNC_ARG; |
| } |
| } |
| |
| XFREE(der.buffer, NULL, DYNAMIC_TYPE_KEY); |
| |
| return ret; |
| } |
| |
| |
| #endif /* !NO_CERTS */ |
| |
| |
| |
| #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) |
| |
| void wolfSSL_ERR_print_errors_fp(FILE* fp, int err) |
| { |
| char data[WOLFSSL_MAX_ERROR_SZ + 1]; |
| |
| WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); |
| SetErrorString(err, data); |
| fprintf(fp, "%s", data); |
| } |
| |
| #endif |
| |
| |
| int wolfSSL_pending(WOLFSSL* ssl) |
| { |
| WOLFSSL_ENTER("SSL_pending"); |
| return ssl->buffers.clearOutputBuffer.length; |
| } |
| |
| |
| #ifndef WOLFSSL_LEANPSK |
| /* trun 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 SSL_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 SSL_FAILURE; |
| |
| ssl->options.certOnly = 1; |
| ret = wolfSSL_connect(ssl); |
| ssl->options.certOnly = 0; |
| |
| return ret; |
| } |
| #endif |
| |
| |
| #ifndef WOLFSSL_LEANPSK |
| /* trun 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 SSL_SUCCESS; |
| } |
| |
| |
| /* make minVersion the internal equivilant SSL version */ |
| static int SetMinVersionHelper(byte* minVersion, int version) |
| { |
| switch (version) { |
| #ifndef NO_OLD_TLS |
| case WOLFSSL_SSLV3: |
| *minVersion = SSLv3_MINOR; |
| break; |
| #endif |
| |
| #ifndef NO_TLS |
| #ifndef NO_OLD_TLS |
| case WOLFSSL_TLSV1: |
| *minVersion = TLSv1_MINOR; |
| break; |
| |
| case WOLFSSL_TLSV1_1: |
| *minVersion = TLSv1_1_MINOR; |
| break; |
| #endif |
| case WOLFSSL_TLSV1_2: |
| *minVersion = TLSv1_2_MINOR; |
| break; |
| #endif |
| |
| default: |
| WOLFSSL_MSG("Bad function argument"); |
| return BAD_FUNC_ARG; |
| } |
| |
| return SSL_SUCCESS; |
| } |
| |
| |
| /* Set minimum downgrade version allowed, SSL_SUCCESS on ok */ |
| 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, SSL_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); |
| } |
| |
| |
| int wolfSSL_SetVersion(WOLFSSL* ssl, int version) |
| { |
| byte haveRSA = 1; |
| byte havePSK = 0; |
| |
| WOLFSSL_ENTER("wolfSSL_SetVersion"); |
| |
| if (ssl == NULL) { |
| WOLFSSL_MSG("Bad function argument"); |
| return BAD_FUNC_ARG; |
| } |
| |
| switch (version) { |
| #ifndef NO_OLD_TLS |
| case WOLFSSL_SSLV3: |
| ssl->version = MakeSSLv3(); |
| break; |
| #endif |
| |
| #ifndef NO_TLS |
| #ifndef NO_OLD_TLS |
| case WOLFSSL_TLSV1: |
| ssl->version = MakeTLSv1(); |
| break; |
| |
| case WOLFSSL_TLSV1_1: |
| ssl->version = MakeTLSv1_1(); |
| break; |
| #endif |
| case WOLFSSL_TLSV1_2: |
| ssl->version = MakeTLSv1_2(); |
| 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 |
| |
| InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, ssl->options.haveDH, |
| ssl->options.haveNTRU, ssl->options.haveECDSAsig, |
| ssl->options.haveStaticECC, ssl->options.side); |
| |
| return SSL_SUCCESS; |
| } |
| #endif /* !leanpsk */ |
| |
| |
| #if !defined(NO_CERTS) || !defined(NO_SESSION_CACHE) |
| |
| /* Make a work from the front of random hash */ |
| static INLINE word32 MakeWordFromHash(const byte* hashID) |
| { |
| return (hashID[0] << 24) | (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 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 = HashSigner(hash); |
| |
| if (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; |
| break; |
| } |
| signers = signers->next; |
| } |
| UnLockMutex(&cm->caLock); |
| |
| return ret; |
| } |
| |
| |
| /* 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 (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; |
| } |
| 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 (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; |
| } |
| } |
| UnLockMutex(&cm->caLock); |
| |
| return ret; |
| } |
| #endif |
| |
| |
| /* 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, buffer der, int type, int verify) |
| { |
| int ret; |
| Signer* signer = 0; |
| word32 row; |
| byte* subjectHash; |
| #ifdef WOLFSSL_SMALL_STACK |
| DecodedCert* cert = NULL; |
| #else |
| DecodedCert cert[1]; |
| #endif |
| |
| WOLFSSL_MSG("Adding a CA"); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (cert == NULL) |
| return MEMORY_E; |
| #endif |
| |
| InitDecodedCert(cert, der.buffer, der.length, cm->heap); |
| ret = ParseCert(cert, CA_TYPE, verify, cm); |
| WOLFSSL_MSG(" Parsed new CA"); |
| |
| #ifndef NO_SKID |
| subjectHash = cert->extSubjKeyId; |
| #else |
| subjectHash = cert->subjectHash; |
| #endif |
| |
| if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA) { |
| WOLFSSL_MSG(" Can'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->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(" Doesn't have key usage certificate signing"); |
| ret = NOT_CA_ERROR; |
| } |
| #endif |
| else if (ret == 0 && AlreadySigner(cm, subjectHash)) { |
| WOLFSSL_MSG(" Already 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; |
| else { |
| signer->keyOID = cert->keyOID; |
| signer->publicKey = cert->publicKey; |
| signer->pubKeySize = cert->pubKeySize; |
| signer->nameLen = cert->subjectCNLen; |
| signer->name = cert->subjectCN; |
| #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); |
| 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 (LockMutex(&cm->caLock) == 0) { |
| signer->next = cm->caTable[row]; |
| cm->caTable[row] = signer; /* takes ownership */ |
| UnLockMutex(&cm->caLock); |
| if (cm->caCacheCallback) |
| cm->caCacheCallback(der.buffer, (int)der.length, type); |
| } |
| else { |
| WOLFSSL_MSG(" CA Mutex Lock failed"); |
| ret = BAD_MUTEX_E; |
| FreeSigner(signer, cm->heap); |
| } |
| } |
| } |
| |
| WOLFSSL_MSG(" Freeing Parsed CA"); |
| FreeDecodedCert(cert); |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| WOLFSSL_MSG(" Freeing der CA"); |
| XFREE(der.buffer, cm->heap, DYNAMIC_TYPE_CA); |
| WOLFSSL_MSG(" OK Freeing der CA"); |
| |
| WOLFSSL_LEAVE("AddCA", ret); |
| |
| return ret == 0 ? SSL_SUCCESS : ret; |
| } |
| |
| #endif /* !NO_CERTS */ |
| |
| |
| #ifndef NO_SESSION_CACHE |
| |
| /* basic config gives a cache with 33 sessions, adequate for clients and |
| embedded servers |
| |
| MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that |
| aren't under heavy load, basically allows 200 new sessions per minute |
| |
| BIG_SESSION_CACHE yields 20,027 sessions |
| |
| 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 |
| |
| 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) |
| */ |
| #ifdef 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 SessionRow SessionCache[SESSION_ROWS]; |
| |
| #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) |
| static word32 PeakSessions; |
| #endif |
| |
| static 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 ClientRow ClientCache[SESSION_ROWS]; /* Client Cache */ |
| /* uses session mutex */ |
| #endif /* NO_CLIENT_CACHE */ |
| |
| #endif /* NO_SESSION_CACHE */ |
| |
| |
| int wolfSSL_Init(void) |
| { |
| int ret = SSL_SUCCESS; |
| |
| WOLFSSL_ENTER("wolfSSL_Init"); |
| |
| if (initRefCount == 0) { |
| #ifndef NO_SESSION_CACHE |
| if (InitMutex(&session_mutex) != 0) |
| ret = BAD_MUTEX_E; |
| #endif |
| if (InitMutex(&count_mutex) != 0) |
| ret = BAD_MUTEX_E; |
| } |
| if (ret == SSL_SUCCESS) { |
| if (LockMutex(&count_mutex) != 0) { |
| WOLFSSL_MSG("Bad Lock Mutex count"); |
| return BAD_MUTEX_E; |
| } |
| initRefCount++; |
| UnLockMutex(&count_mutex); |
| } |
| |
| return ret; |
| } |
| |
| |
| #ifndef NO_CERTS |
| |
| static const char* BEGIN_CERT = "-----BEGIN CERTIFICATE-----"; |
| static const char* END_CERT = "-----END CERTIFICATE-----"; |
| static const char* BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----"; |
| static const char* END_CERT_REQ = "-----END CERTIFICATE REQUEST-----"; |
| static const char* BEGIN_DH_PARAM = "-----BEGIN DH PARAMETERS-----"; |
| static const char* END_DH_PARAM = "-----END DH PARAMETERS-----"; |
| static const char* BEGIN_X509_CRL = "-----BEGIN X509 CRL-----"; |
| static const char* END_X509_CRL = "-----END X509 CRL-----"; |
| static const char* BEGIN_RSA_PRIV = "-----BEGIN RSA PRIVATE KEY-----"; |
| static const char* END_RSA_PRIV = "-----END RSA PRIVATE KEY-----"; |
| static const char* BEGIN_PRIV_KEY = "-----BEGIN PRIVATE KEY-----"; |
| static const char* END_PRIV_KEY = "-----END PRIVATE KEY-----"; |
| static const char* BEGIN_ENC_PRIV_KEY = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; |
| static const char* END_ENC_PRIV_KEY = "-----END ENCRYPTED PRIVATE KEY-----"; |
| static const char* BEGIN_EC_PRIV = "-----BEGIN EC PRIVATE KEY-----"; |
| static const char* END_EC_PRIV = "-----END EC PRIVATE KEY-----"; |
| static const char* BEGIN_DSA_PRIV = "-----BEGIN DSA PRIVATE KEY-----"; |
| static const char* END_DSA_PRIV = "-----END DSA PRIVATE KEY-----"; |
| |
| /* Remove PEM header/footer, convert to ASN1, store any encrypted data |
| info->consumed tracks of PEM bytes consumed in case multiple parts */ |
| int PemToDer(const unsigned char* buff, long longSz, int type, |
| buffer* der, void* heap, EncryptedInfo* info, int* eccKey) |
| { |
| const char* header = NULL; |
| const char* footer = NULL; |
| char* headerEnd; |
| char* footerEnd; |
| char* consumedEnd; |
| char* bufferEnd = (char*)(buff + longSz); |
| long neededSz; |
| int ret = 0; |
| int dynamicType = 0; |
| int sz = (int)longSz; |
| |
| switch (type) { |
| case CA_TYPE: /* same as below */ |
| case CERT_TYPE: header= BEGIN_CERT; footer= END_CERT; break; |
| case CRL_TYPE: header= BEGIN_X509_CRL; footer= END_X509_CRL; break; |
| case DH_PARAM_TYPE: header= BEGIN_DH_PARAM; footer= END_DH_PARAM; break; |
| case CERTREQ_TYPE: header= BEGIN_CERT_REQ; footer= END_CERT_REQ; break; |
| default: header= BEGIN_RSA_PRIV; footer= END_RSA_PRIV; break; |
| } |
| |
| switch (type) { |
| case CA_TYPE: dynamicType = DYNAMIC_TYPE_CA; break; |
| case CERT_TYPE: dynamicType = DYNAMIC_TYPE_CERT; break; |
| case CRL_TYPE: dynamicType = DYNAMIC_TYPE_CRL; break; |
| default: dynamicType = DYNAMIC_TYPE_KEY; break; |
| } |
| |
| /* find header */ |
| for (;;) { |
| headerEnd = XSTRNSTR((char*)buff, header, sz); |
| |
| if (headerEnd || type != PRIVATEKEY_TYPE) { |
| break; |
| } else if (header == BEGIN_RSA_PRIV) { |
| header = BEGIN_PRIV_KEY; footer = END_PRIV_KEY; |
| } else if (header == BEGIN_PRIV_KEY) { |
| header = BEGIN_ENC_PRIV_KEY; footer = END_ENC_PRIV_KEY; |
| } else if (header == BEGIN_ENC_PRIV_KEY) { |
| header = BEGIN_EC_PRIV; footer = END_EC_PRIV; |
| } else if (header == BEGIN_EC_PRIV) { |
| header = BEGIN_DSA_PRIV; footer = END_DSA_PRIV; |
| } else |
| break; |
| } |
| |
| if (!headerEnd) { |
| WOLFSSL_MSG("Couldn't find PEM header"); |
| return SSL_NO_PEM_HEADER; |
| } |
| |
| headerEnd += XSTRLEN(header); |
| |
| /* eat end of line */ |
| if (headerEnd[0] == '\n') |
| headerEnd++; |
| else if (headerEnd[1] == '\n') |
| headerEnd += 2; |
| else |
| return SSL_BAD_FILE; |
| |
| if (type == PRIVATEKEY_TYPE) { |
| if (eccKey) |
| *eccKey = header == BEGIN_EC_PRIV; |
| } |
| |
| #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) |
| { |
| /* remove encrypted header if there */ |
| char encHeader[] = "Proc-Type"; |
| char* line = XSTRNSTR(headerEnd, encHeader, PEM_LINE_LEN); |
| if (line) { |
| char* newline; |
| char* finish; |
| char* start = XSTRNSTR(line, "DES", PEM_LINE_LEN); |
| |
| if (!start) |
| start = XSTRNSTR(line, "AES", PEM_LINE_LEN); |
| |
| if (!start) return SSL_BAD_FILE; |
| if (!info) return SSL_BAD_FILE; |
| |
| finish = XSTRNSTR(start, ",", PEM_LINE_LEN); |
| |
| if (start && finish && (start < finish)) { |
| newline = XSTRNSTR(finish, "\r", PEM_LINE_LEN); |
| |
| XMEMCPY(info->name, start, finish - start); |
| info->name[finish - start] = 0; |
| XMEMCPY(info->iv, finish + 1, sizeof(info->iv)); |
| |
| if (!newline) newline = XSTRNSTR(finish, "\n", PEM_LINE_LEN); |
| if (newline && (newline > finish)) { |
| info->ivSz = (word32)(newline - (finish + 1)); |
| info->set = 1; |
| } |
| else |
| return SSL_BAD_FILE; |
| } |
| else |
| return SSL_BAD_FILE; |
| |
| /* eat blank line */ |
| while (*newline == '\r' || *newline == '\n') |
| newline++; |
| headerEnd = newline; |
| } |
| } |
| #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ |
| |
| /* find footer */ |
| footerEnd = XSTRNSTR((char*)buff, footer, sz); |
| if (!footerEnd) |
| return SSL_BAD_FILE; |
| |
| consumedEnd = footerEnd + XSTRLEN(footer); |
| |
| if (consumedEnd < bufferEnd) { /* handle no end of line on last line */ |
| /* eat end of line */ |
| if (consumedEnd[0] == '\n') |
| consumedEnd++; |
| else if (consumedEnd[1] == '\n') |
| consumedEnd += 2; |
| else |
| return SSL_BAD_FILE; |
| } |
| |
| if (info) |
| info->consumed = (long)(consumedEnd - (char*)buff); |
| |
| /* set up der buffer */ |
| neededSz = (long)(footerEnd - headerEnd); |
| if (neededSz > sz || neededSz < 0) |
| return SSL_BAD_FILE; |
| |
| der->buffer = (byte*)XMALLOC(neededSz, heap, dynamicType); |
| if (!der->buffer) |
| return MEMORY_ERROR; |
| |
| der->length = (word32)neededSz; |
| |
| if (Base64_Decode((byte*)headerEnd, (word32)neededSz, der->buffer, |
| &der->length) < 0) |
| return SSL_BAD_FILE; |
| |
| if (header == BEGIN_PRIV_KEY) { |
| /* pkcs8 key, convert and adjust length */ |
| if ((ret = ToTraditional(der->buffer, der->length)) < 0) |
| return ret; |
| |
| der->length = ret; |
| return 0; |
| } |
| |
| #if (defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)) && !defined(NO_PWDBASED) |
| if (header == BEGIN_ENC_PRIV_KEY) { |
| int passwordSz; |
| #ifdef WOLFSSL_SMALL_STACK |
| char* password = NULL; |
| #else |
| char password[80]; |
| #endif |
| |
| if (!info || !info->ctx || !info->ctx->passwd_cb) |
| return SSL_BAD_FILE; /* no callback error */ |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| password = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| if (password == NULL) |
| return MEMORY_E; |
| #endif |
| passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0, |
| info->ctx->userdata); |
| /* convert and adjust length */ |
| ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| if (ret < 0) |
| return ret; |
| |
| der->length = ret; |
| return 0; |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| |
| /* process the buffer buff, legnth sz, into ctx of format and type |
| used tracks bytes consumed, userChain specifies a user cert chain |
| to pass during the handshake */ |
| static int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, |
| long sz, int format, int type, WOLFSSL* ssl, |
| long* used, int userChain) |
| { |
| buffer der; /* holds DER or RAW (for NTRU) */ |
| int ret; |
| int dynamicType = 0; |
| int eccKey = 0; |
| int rsaKey = 0; |
| void* heap = ctx ? ctx->heap : NULL; |
| #ifdef WOLFSSL_SMALL_STACK |
| EncryptedInfo* info = NULL; |
| #else |
| EncryptedInfo info[1]; |
| #endif |
| |
| (void)dynamicType; |
| (void)rsaKey; |
| |
| if (used) |
| *used = sz; /* used bytes default to sz, PEM chain may shorten*/ |
| |
| if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM |
| && format != SSL_FILETYPE_RAW) |
| return SSL_BAD_FILETYPE; |
| |
| if (ctx == NULL && ssl == NULL) |
| return BAD_FUNC_ARG; |
| |
| if (type == CA_TYPE) |
| dynamicType = DYNAMIC_TYPE_CA; |
| else if (type == CERT_TYPE) |
| dynamicType = DYNAMIC_TYPE_CERT; |
| else |
| dynamicType = DYNAMIC_TYPE_KEY; |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (info == NULL) |
| return MEMORY_E; |
| #endif |
| |
| info->set = 0; |
| info->ctx = ctx; |
| info->consumed = 0; |
| der.buffer = 0; |
| |
| if (format == SSL_FILETYPE_PEM) { |
| ret = PemToDer(buff, sz, type, &der, heap, info, &eccKey); |
| if (ret < 0) { |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| XFREE(der.buffer, heap, dynamicType); |
| return ret; |
| } |
| |
| if (used) |
| *used = info->consumed; |
| |
| /* we may have a user cert chain, try to consume */ |
| if (userChain && type == CERT_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; |
| byte* shrinked = NULL; /* shrinked to size chainBuffer |
| * or staticBuffer */ |
| int dynamicBuffer = 0; |
| word32 bufferSz = sizeof(staticBuffer); |
| long consumed = info->consumed; |
| word32 idx = 0; |
| int gotOne = 0; |
| |
| if ( (sz - consumed) > (int)bufferSz) { |
| WOLFSSL_MSG("Growing Tmp Chain Buffer"); |
| bufferSz = (word32)(sz - consumed); |
| /* will shrink to actual size */ |
| chainBuffer = (byte*)XMALLOC(bufferSz, heap, DYNAMIC_TYPE_FILE); |
| if (chainBuffer == NULL) { |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| XFREE(der.buffer, heap, dynamicType); |
| return MEMORY_E; |
| } |
| dynamicBuffer = 1; |
| } |
| |
| WOLFSSL_MSG("Processing Cert Chain"); |
| while (consumed < sz) { |
| buffer part; |
| info->consumed = 0; |
| part.buffer = 0; |
| |
| ret = PemToDer(buff + consumed, sz - consumed, type, &part, |
| heap, info, &eccKey); |
| if (ret == 0) { |
| gotOne = 1; |
| if ( (idx + part.length) > 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; |
| } |
| } |
| |
| XFREE(part.buffer, heap, dynamicType); |
| |
| if (ret == SSL_NO_PEM_HEADER && gotOne) { |
| WOLFSSL_MSG("We got one good PEM so stuff at end ok"); |
| break; |
| } |
| |
| if (ret < 0) { |
| WOLFSSL_MSG(" Error in Cert in Chain"); |
| if (dynamicBuffer) |
| XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| XFREE(der.buffer, heap, dynamicType); |
| return ret; |
| } |
| WOLFSSL_MSG(" Consumed another Cert in Chain"); |
| } |
| WOLFSSL_MSG("Finished Processing Cert Chain"); |
| |
| /* only retain actual size used */ |
| shrinked = (byte*)XMALLOC(idx, heap, dynamicType); |
| if (shrinked) { |
| if (ssl) { |
| if (ssl->buffers.certChain.buffer && |
| ssl->buffers.weOwnCertChain) { |
| XFREE(ssl->buffers.certChain.buffer, heap, |
| dynamicType); |
| } |
| ssl->buffers.certChain.buffer = shrinked; |
| ssl->buffers.certChain.length = idx; |
| XMEMCPY(ssl->buffers.certChain.buffer, chainBuffer,idx); |
| ssl->buffers.weOwnCertChain = 1; |
| } else if (ctx) { |
| if (ctx->certChain.buffer) |
| XFREE(ctx->certChain.buffer, heap, dynamicType); |
| ctx->certChain.buffer = shrinked; |
| ctx->certChain.length = idx; |
| XMEMCPY(ctx->certChain.buffer, chainBuffer, idx); |
| } |
| } |
| |
| if (dynamicBuffer) |
| XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); |
| |
| if (shrinked == NULL) { |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| XFREE(der.buffer, heap, dynamicType); |
| return MEMORY_E; |
| } |
| } |
| } |
| else { /* ASN1 (DER) or RAW (NTRU) */ |
| der.buffer = (byte*) XMALLOC(sz, heap, dynamicType); |
| if (!der.buffer) { |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| return MEMORY_ERROR; |
| } |
| |
| XMEMCPY(der.buffer, buff, sz); |
| der.length = (word32)sz; |
| } |
| |
| #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) |
| if (info->set) { |
| /* decrypt */ |
| int passwordSz; |
| #ifdef WOLFSSL_SMALL_STACK |
| char* password = NULL; |
| byte* key = NULL; |
| byte* iv = NULL; |
| #else |
| char password[80]; |
| byte key[AES_256_KEY_SIZE]; |
| #ifndef NO_MD5 |
| byte iv[AES_IV_SIZE]; |
| #endif |
| #endif |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| password = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| key = (byte*)XMALLOC(AES_256_KEY_SIZE, NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| iv = (byte*)XMALLOC(AES_IV_SIZE, NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| |
| if (password == NULL || key == NULL || iv == NULL) { |
| XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| ret = MEMORY_E; |
| } |
| else |
| #endif |
| if (!ctx || !ctx->passwd_cb) { |
| ret = NO_PASSWORD; |
| } |
| else { |
| passwordSz = ctx->passwd_cb(password, sizeof(password), 0, |
| ctx->userdata); |
| |
| /* use file's salt for key derivation, hex decode first */ |
| if (Base16_Decode(info->iv, info->ivSz, info->iv, &info->ivSz) |
| != 0) { |
| ret = ASN_INPUT_E; |
| } |
| #ifndef NO_MD5 |
| else if ((ret = EVP_BytesToKey(info->name, "MD5", info->iv, |
| (byte*)password, passwordSz, 1, key, iv)) <= 0) { |
| /* empty */ |
| } |
| #endif |
| #ifndef NO_DES3 |
| else if (XSTRNCMP(info->name, "DES-CBC", 7) == 0) { |
| ret = wc_Des_CbcDecryptWithKey(der.buffer, der.buffer, der.length, |
| key, info->iv); |
| } |
| else if (XSTRNCMP(info->name, "DES-EDE3-CBC", 13) == 0) { |
| ret = wc_Des3_CbcDecryptWithKey(der.buffer, der.buffer, der.length, |
| key, info->iv); |
| } |
| #endif |
| #ifndef NO_AES |
| else if (XSTRNCMP(info->name, "AES-128-CBC", 13) == 0) { |
| ret = wc_AesCbcDecryptWithKey(der.buffer, der.buffer, der.length, |
| key, AES_128_KEY_SIZE, info->iv); |
| } |
| else if (XSTRNCMP(info->name, "AES-192-CBC", 13) == 0) { |
| ret = wc_AesCbcDecryptWithKey(der.buffer, der.buffer, der.length, |
| key, AES_192_KEY_SIZE, info->iv); |
| } |
| else if (XSTRNCMP(info->name, "AES-256-CBC", 13) == 0) { |
| ret = wc_AesCbcDecryptWithKey(der.buffer, der.buffer, der.length, |
| key, AES_256_KEY_SIZE, info->iv); |
| } |
| #endif |
| else { |
| ret = SSL_BAD_FILE; |
| } |
| } |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| if (ret != 0) { |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| XFREE(der.buffer, heap, dynamicType); |
| return ret; |
| } |
| } |
| #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| if (type == CA_TYPE) { |
| if (ctx == NULL) { |
| WOLFSSL_MSG("Need context for CA load"); |
| XFREE(der.buffer, heap, dynamicType); |
| return BAD_FUNC_ARG; |
| } |
| return AddCA(ctx->cm, der, WOLFSSL_USER_CA, ctx->verifyPeer); |
| /* takes der over */ |
| } |
| else if (type == CERT_TYPE) { |
| if (ssl) { |
| if (ssl->buffers.weOwnCert && ssl->buffers.certificate.buffer) |
| XFREE(ssl->buffers.certificate.buffer, heap, dynamicType); |
| ssl->buffers.certificate = der; |
| ssl->buffers.weOwnCert = 1; |
| } |
| else if (ctx) { |
| if (ctx->certificate.buffer) |
| XFREE(ctx->certificate.buffer, heap, dynamicType); |
| ctx->certificate = der; /* takes der over */ |
| } |
| } |
| else if (type == PRIVATEKEY_TYPE) { |
| if (ssl) { |
| if (ssl->buffers.weOwnKey && ssl->buffers.key.buffer) |
| XFREE(ssl->buffers.key.buffer, heap, dynamicType); |
| ssl->buffers.key = der; |
| ssl->buffers.weOwnKey = 1; |
| } |
| else if (ctx) { |
| if (ctx->privateKey.buffer) |
| XFREE(ctx->privateKey.buffer, heap, dynamicType); |
| ctx->privateKey = der; /* takes der over */ |
| } |
| } |
| else { |
| XFREE(der.buffer, heap, dynamicType); |
| return SSL_BAD_CERTTYPE; |
| } |
| |
| if (type == PRIVATEKEY_TYPE && format != SSL_FILETYPE_RAW) { |
| #ifndef NO_RSA |
| if (!eccKey) { |
| /* make sure RSA key can be used */ |
| word32 idx = 0; |
| #ifdef WOLFSSL_SMALL_STACK |
| RsaKey* key = NULL; |
| #else |
| RsaKey key[1]; |
| #endif |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| key = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (key == NULL) |
| return MEMORY_E; |
| #endif |
| |
| ret = wc_InitRsaKey(key, 0); |
| if (ret == 0) { |
| if (wc_RsaPrivateKeyDecode(der.buffer, &idx, key, der.length) != |
| 0) { |
| #ifdef HAVE_ECC |
| /* could have DER ECC (or pkcs8 ecc), no easy way to tell */ |
| eccKey = 1; /* so try it out */ |
| #endif |
| if (!eccKey) |
| ret = SSL_BAD_FILE; |
| } else { |
| rsaKey = 1; |
| (void)rsaKey; /* for no ecc builds */ |
| } |
| } |
| |
| wc_FreeRsaKey(key); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| if (ret != 0) |
| return ret; |
| } |
| #endif |
| #ifdef HAVE_ECC |
| if (!rsaKey) { |
| /* make sure ECC key can be used */ |
| word32 idx = 0; |
| ecc_key key; |
| |
| wc_ecc_init(&key); |
| if (wc_EccPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) { |
| wc_ecc_free(&key); |
| return SSL_BAD_FILE; |
| } |
| wc_ecc_free(&key); |
| eccKey = 1; |
| if (ctx) |
| ctx->haveStaticECC = 1; |
| if (ssl) |
| ssl->options.haveStaticECC = 1; |
| } |
| #endif /* HAVE_ECC */ |
| } |
| else if (type == CERT_TYPE) { |
| #ifdef WOLFSSL_SMALL_STACK |
| DecodedCert* cert = NULL; |
| #else |
| DecodedCert cert[1]; |
| #endif |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| 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"); |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| return SSL_BAD_FILE; |
| } |
| switch (cert->signatureOID) { |
| case CTC_SHAwECDSA: |
| case CTC_SHA256wECDSA: |
| case CTC_SHA384wECDSA: |
| case CTC_SHA512wECDSA: |
| WOLFSSL_MSG("ECDSA cert signature"); |
| if (ctx) |
| ctx->haveECDSAsig = 1; |
| if (ssl) |
| ssl->options.haveECDSAsig = 1; |
| break; |
| default: |
| WOLFSSL_MSG("Not ECDSA cert signature"); |
| break; |
| } |
| |
| #ifdef HAVE_ECC |
| if (ctx) |
| ctx->pkCurveOID = cert->pkCurveOID; |
| if (ssl) |
| ssl->pkCurveOID = cert->pkCurveOID; |
| #endif |
| |
| FreeDecodedCert(cert); |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| } |
| |
| return SSL_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) |
| { |
| 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); |
| |
| if (ret == SSL_NO_PEM_HEADER && gotOne) { |
| WOLFSSL_MSG("We got one good PEM file so stuff at end ok"); |
| ret = SSL_SUCCESS; |
| break; |
| } |
| |
| if (ret < 0) |
| break; |
| |
| WOLFSSL_MSG(" Processed a CA"); |
| gotOne = 1; |
| used += consumed; |
| } |
| |
| return ret; |
| } |
| |
| |
| /* Verify the ceritficate, SSL_SUCCESS for ok, < 0 for error */ |
| int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm, const byte* buff, |
| long sz, int format) |
| { |
| int ret = 0; |
| buffer der; |
| #ifdef WOLFSSL_SMALL_STACK |
| DecodedCert* cert = NULL; |
| #else |
| DecodedCert cert[1]; |
| #endif |
| |
| WOLFSSL_ENTER("wolfSSL_CertManagerVerifyBuffer"); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (cert == NULL) |
| return MEMORY_E; |
| #endif |
| |
| der.buffer = NULL; |
| der.length = 0; |
| |
| if (format == SSL_FILETYPE_PEM) { |
| int eccKey = 0; /* not used */ |
| #ifdef WOLFSSL_SMALL_STACK |
| EncryptedInfo* info = NULL; |
| #else |
| EncryptedInfo info[1]; |
| #endif |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (info == NULL) { |
| XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| return MEMORY_E; |
| } |
| #endif |
| |
| info->set = 0; |
| info->ctx = NULL; |
| info->consumed = 0; |
| |
| ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, info, &eccKey); |
| |
| if (ret == 0) |
| InitDecodedCert(cert, der.buffer, der.length, cm->heap); |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| } |
| else |
| InitDecodedCert(cert, (byte*)buff, (word32)sz, cm->heap); |
| |
| if (ret == 0) |
| ret = ParseCertRelative(cert, CERT_TYPE, 1, cm); |
| |
| #ifdef HAVE_CRL |
| if (ret == 0 && cm->crlEnabled) |
| ret = CheckCertCRL(cm->crl, cert); |
| #endif |
| |
| FreeDecodedCert(cert); |
| |
| XFREE(der.buffer, cm->heap, DYNAMIC_TYPE_CERT); |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| return ret == 0 ? SSL_SUCCESS : ret; |
| } |
| |
| |
| /* turn on OCSP if off and compiled in, set options */ |
| int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options) |
| { |
| int ret = SSL_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 SSL_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; |
| #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 SSL_SUCCESS; |
| } |
| |
| |
| #ifdef HAVE_OCSP |
| |
| |
| /* check CRL if enabled, SSL_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 SSL_SUCCESS; |
| |
| #ifdef WOLFSSL_SMALL_STACK |
| cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, |
| DYNAMIC_TYPE_TMP_BUFFER); |
| if (cert == NULL) |
| return MEMORY_E; |
| #endif |
| |
| InitDecodedCert(cert, der, sz, NULL); |
| |
| if ((ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY, cm)) != 0) { |
| WOLFSSL_MSG("ParseCert failed"); |
| } |
| else if ((ret = CheckCertOCSP(cm->ocsp, cert)) != 0) { |
| WOLFSSL_MSG("CheckCertOCSP failed"); |
| } |
| |
| FreeDecodedCert(cert); |
| #ifdef WOLFSSL_SMALL_STACK |
| XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| #endif |
| |
| return ret == 0 ? SSL_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, 0); |
| if (url != NULL) { |
| int urlSz = (int)XSTRLEN(url) + 1; |
| cm->ocspOverrideURL = (char*)XMALLOC(urlSz, cm->heap, 0); |
| if (cm->ocspOverrideURL != NULL) { |
| XMEMCPY(cm->ocspOverrideURL, url, urlSz); |
| } |
| else |
| return MEMORY_E; |
| } |
| else |
| cm->ocspOverrideURL = NULL; |
| |
| return SSL_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 SSL_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_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) |
| return wolfSSL_CertManagerSetOCSP_Cb(ssl->ctx->cm, |
| ioCb, respFreeCb, ioCbCtx); |
| 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; |
| } |
| |
| |
| #endif /* HAVE_OCSP */ |
| |
| |
| #ifndef NO_FILESYSTEM |
| |
| #if defined(WOLFSSL_MDK_ARM) |
| extern FILE * wolfSSL_fopen(const char *name, const char *mode) ; |
| #define XFOPEN wolfSSL_fopen |
| #else |
| #define XFOPEN fopen |
| #endif |
| |
| /* 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) |
| { |
| #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 = ctx ? ctx->heap : NULL; |
| |
| (void)crl; |
| (void)heapHint; |
| |
| |