blob: 139e343f9a8e2eabab311d19d16e53c4c1b4b599 [file] [log] [blame]
/* 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;