13748 lines
420 KiB
C
13748 lines
420 KiB
C
/* internal.c
|
|
*
|
|
* Copyright (C) 2006-2014 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
|
|
*/
|
|
|
|
/* Name change compatibility layer */
|
|
//#include <cyassl/ssl.h>
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
|
|
#include <wolfssl/internal.h>
|
|
#include <wolfssl/error-ssl.h>
|
|
#include <wolfssl/wolfcrypt/asn.h>
|
|
|
|
#ifdef HAVE_LIBZ
|
|
#include "zlib.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_NTRU
|
|
#include "ntru_crypto.h"
|
|
#endif
|
|
|
|
#if defined(DEBUG_WOLFSSL) || defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST)
|
|
#ifdef FREESCALE_MQX
|
|
#include <fio.h>
|
|
#else
|
|
#include <stdio.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __sun
|
|
#include <sys/filio.h>
|
|
#endif
|
|
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
|
|
#if defined(WOLFSSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS)
|
|
#error \
|
|
WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
|
|
#endif
|
|
|
|
#if defined(HAVE_SECURE_RENEGOTIATION) && defined(HAVE_RENEGOTIATION_INDICATION)
|
|
#error Cannot use both secure-renegotiation and renegotiation-indication
|
|
#endif
|
|
|
|
static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
|
|
const byte* input, int inSz, int type);
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32*,
|
|
word32);
|
|
static int DoServerHello(WOLFSSL* ssl, const byte* input, word32*, word32);
|
|
static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, word32*,
|
|
word32);
|
|
#ifndef NO_CERTS
|
|
static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32*,
|
|
word32);
|
|
#endif
|
|
#ifdef HAVE_SESSION_TICKET
|
|
static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32*,
|
|
word32);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
static int DoClientHello(WOLFSSL* ssl, const byte* input, word32*, word32);
|
|
static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32*, word32);
|
|
#if !defined(NO_RSA) || defined(HAVE_ECC)
|
|
static int DoCertificateVerify(WOLFSSL* ssl, byte*, word32*, word32);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
static INLINE int DtlsCheckWindow(DtlsState* state);
|
|
static INLINE int DtlsUpdateWindow(DtlsState* state);
|
|
#endif
|
|
|
|
|
|
typedef enum {
|
|
doProcessInit = 0,
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
runProcessOldClientHello,
|
|
#endif
|
|
getRecordLayerHeader,
|
|
getData,
|
|
runProcessingOneMessage
|
|
} processReply;
|
|
|
|
#ifndef NO_OLD_TLS
|
|
static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
|
|
int content, int verify);
|
|
|
|
#endif
|
|
|
|
#ifndef NO_CERTS
|
|
static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes);
|
|
#endif
|
|
|
|
static void PickHashSigAlgo(WOLFSSL* ssl,
|
|
const byte* hashSigAlgo, word32 hashSigAlgoSz);
|
|
|
|
#ifndef min
|
|
|
|
static INLINE word32 min(word32 a, word32 b)
|
|
{
|
|
return a > b ? b : a;
|
|
}
|
|
|
|
#endif /* min */
|
|
|
|
|
|
int IsTLS(const WOLFSSL* ssl)
|
|
{
|
|
if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int IsAtLeastTLSv1_2(const WOLFSSL* ssl)
|
|
{
|
|
if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR)
|
|
return 1;
|
|
if (ssl->version.major == DTLS_MAJOR && ssl->version.minor <= DTLSv1_2_MINOR)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef HAVE_NTRU
|
|
|
|
static byte GetEntropy(ENTROPY_CMD cmd, byte* out)
|
|
{
|
|
/* TODO: add locking? */
|
|
static RNG rng;
|
|
|
|
if (cmd == INIT)
|
|
return (InitRng(&rng) == 0) ? 1 : 0;
|
|
|
|
if (out == NULL)
|
|
return 0;
|
|
|
|
if (cmd == GET_BYTE_OF_ENTROPY)
|
|
return (RNG_GenerateBlock(&rng, out, 1) == 0) ? 1 : 0;
|
|
|
|
if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) {
|
|
*out = 1;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* HAVE_NTRU */
|
|
|
|
/* used by ssl.c too */
|
|
void c32to24(word32 in, word24 out)
|
|
{
|
|
out[0] = (in >> 16) & 0xff;
|
|
out[1] = (in >> 8) & 0xff;
|
|
out[2] = in & 0xff;
|
|
}
|
|
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
|
|
static INLINE void c32to48(word32 in, byte out[6])
|
|
{
|
|
out[0] = 0;
|
|
out[1] = 0;
|
|
out[2] = (in >> 24) & 0xff;
|
|
out[3] = (in >> 16) & 0xff;
|
|
out[4] = (in >> 8) & 0xff;
|
|
out[5] = in & 0xff;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DTLS */
|
|
|
|
|
|
/* convert 16 bit integer to opaque */
|
|
static INLINE void c16toa(word16 u16, byte* c)
|
|
{
|
|
c[0] = (u16 >> 8) & 0xff;
|
|
c[1] = u16 & 0xff;
|
|
}
|
|
|
|
|
|
#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \
|
|
|| defined(HAVE_AESGCM)
|
|
/* convert 32 bit integer to opaque */
|
|
static INLINE void c32toa(word32 u32, byte* c)
|
|
{
|
|
c[0] = (u32 >> 24) & 0xff;
|
|
c[1] = (u32 >> 16) & 0xff;
|
|
c[2] = (u32 >> 8) & 0xff;
|
|
c[3] = u32 & 0xff;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* convert a 24 bit integer into a 32 bit one */
|
|
static INLINE void c24to32(const word24 u24, word32* u32)
|
|
{
|
|
*u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
|
|
}
|
|
|
|
|
|
/* convert opaque to 16 bit integer */
|
|
static INLINE void ato16(const byte* c, word16* u16)
|
|
{
|
|
*u16 = (word16) ((c[0] << 8) | (c[1]));
|
|
}
|
|
|
|
|
|
#if defined(WOLFSSL_DTLS) || defined(HAVE_SESSION_TICKET)
|
|
|
|
/* convert opaque to 32 bit integer */
|
|
static INLINE void ato32(const byte* c, word32* u32)
|
|
{
|
|
*u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
|
|
}
|
|
|
|
#endif /* WOLFSSL_DTLS */
|
|
|
|
|
|
#ifdef HAVE_LIBZ
|
|
|
|
/* alloc user allocs to work with zlib */
|
|
static void* myAlloc(void* opaque, unsigned int item, unsigned int size)
|
|
{
|
|
(void)opaque;
|
|
return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
|
|
}
|
|
|
|
|
|
static void myFree(void* opaque, void* memory)
|
|
{
|
|
(void)opaque;
|
|
XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ);
|
|
}
|
|
|
|
|
|
/* init zlib comp/decomp streams, 0 on success */
|
|
static int InitStreams(WOLFSSL* ssl)
|
|
{
|
|
ssl->c_stream.zalloc = (alloc_func)myAlloc;
|
|
ssl->c_stream.zfree = (free_func)myFree;
|
|
ssl->c_stream.opaque = (voidpf)ssl->heap;
|
|
|
|
if (deflateInit(&ssl->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
|
|
return ZLIB_INIT_ERROR;
|
|
|
|
ssl->didStreamInit = 1;
|
|
|
|
ssl->d_stream.zalloc = (alloc_func)myAlloc;
|
|
ssl->d_stream.zfree = (free_func)myFree;
|
|
ssl->d_stream.opaque = (voidpf)ssl->heap;
|
|
|
|
if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void FreeStreams(WOLFSSL* ssl)
|
|
{
|
|
if (ssl->didStreamInit) {
|
|
deflateEnd(&ssl->c_stream);
|
|
inflateEnd(&ssl->d_stream);
|
|
}
|
|
}
|
|
|
|
|
|
/* compress in to out, return out size or error */
|
|
static int myCompress(WOLFSSL* ssl, byte* in, int inSz, byte* out, int outSz)
|
|
{
|
|
int err;
|
|
int currTotal = (int)ssl->c_stream.total_out;
|
|
|
|
ssl->c_stream.next_in = in;
|
|
ssl->c_stream.avail_in = inSz;
|
|
ssl->c_stream.next_out = out;
|
|
ssl->c_stream.avail_out = outSz;
|
|
|
|
err = deflate(&ssl->c_stream, Z_SYNC_FLUSH);
|
|
if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR;
|
|
|
|
return (int)ssl->c_stream.total_out - currTotal;
|
|
}
|
|
|
|
|
|
/* decompress in to out, returnn out size or error */
|
|
static int myDeCompress(WOLFSSL* ssl, byte* in,int inSz, byte* out,int outSz)
|
|
{
|
|
int err;
|
|
int currTotal = (int)ssl->d_stream.total_out;
|
|
|
|
ssl->d_stream.next_in = in;
|
|
ssl->d_stream.avail_in = inSz;
|
|
ssl->d_stream.next_out = out;
|
|
ssl->d_stream.avail_out = outSz;
|
|
|
|
err = inflate(&ssl->d_stream, Z_SYNC_FLUSH);
|
|
if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR;
|
|
|
|
return (int)ssl->d_stream.total_out - currTotal;
|
|
}
|
|
|
|
#endif /* HAVE_LIBZ */
|
|
|
|
|
|
void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv)
|
|
{
|
|
method->version = pv;
|
|
method->side = WOLFSSL_CLIENT_END;
|
|
method->downgrade = 0;
|
|
}
|
|
|
|
|
|
/* Initialze SSL context, return 0 on success */
|
|
int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method)
|
|
{
|
|
ctx->method = method;
|
|
ctx->refCount = 1; /* so either CTX_free or SSL_free can release */
|
|
#ifndef NO_CERTS
|
|
ctx->certificate.buffer = 0;
|
|
ctx->certChain.buffer = 0;
|
|
ctx->privateKey.buffer = 0;
|
|
ctx->serverDH_P.buffer = 0;
|
|
ctx->serverDH_G.buffer = 0;
|
|
#endif
|
|
ctx->haveDH = 0;
|
|
ctx->haveNTRU = 0; /* start off */
|
|
ctx->haveECDSAsig = 0; /* start off */
|
|
ctx->haveStaticECC = 0; /* start off */
|
|
ctx->heap = ctx; /* defaults to self */
|
|
#ifndef NO_PSK
|
|
ctx->havePSK = 0;
|
|
ctx->server_hint[0] = 0;
|
|
ctx->client_psk_cb = 0;
|
|
ctx->server_psk_cb = 0;
|
|
#endif /* NO_PSK */
|
|
#ifdef HAVE_ANON
|
|
ctx->haveAnon = 0;
|
|
#endif /* HAVE_ANON */
|
|
#ifdef HAVE_ECC
|
|
ctx->eccTempKeySz = ECDHE_SIZE;
|
|
#endif
|
|
|
|
#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
|
|
ctx->passwd_cb = 0;
|
|
ctx->userdata = 0;
|
|
#endif /* OPENSSL_EXTRA */
|
|
|
|
ctx->timeout = WOLFSSL_SESSION_TIMEOUT;
|
|
|
|
#ifndef WOLFSSL_USER_IO
|
|
ctx->CBIORecv = EmbedReceive;
|
|
ctx->CBIOSend = EmbedSend;
|
|
#ifdef WOLFSSL_DTLS
|
|
if (method->version.major == DTLS_MAJOR) {
|
|
ctx->CBIORecv = EmbedReceiveFrom;
|
|
ctx->CBIOSend = EmbedSendTo;
|
|
ctx->CBIOCookie = EmbedGenerateCookie;
|
|
}
|
|
#endif
|
|
#else
|
|
/* user will set */
|
|
ctx->CBIORecv = NULL;
|
|
ctx->CBIOSend = NULL;
|
|
#ifdef WOLFSSL_DTLS
|
|
ctx->CBIOCookie = NULL;
|
|
#endif
|
|
#endif /* WOLFSSL_USER_IO */
|
|
#ifdef HAVE_NETX
|
|
ctx->CBIORecv = NetX_Receive;
|
|
ctx->CBIOSend = NetX_Send;
|
|
#endif
|
|
ctx->partialWrite = 0;
|
|
ctx->verifyCallback = 0;
|
|
|
|
#ifndef NO_CERTS
|
|
ctx->cm = wolfSSL_CertManagerNew();
|
|
#endif
|
|
#ifdef HAVE_NTRU
|
|
if (method->side == WOLFSSL_CLIENT_END)
|
|
ctx->haveNTRU = 1; /* always on cliet side */
|
|
/* server can turn on by loading key */
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
if (method->side == WOLFSSL_CLIENT_END) {
|
|
ctx->haveECDSAsig = 1; /* always on cliet side */
|
|
ctx->haveStaticECC = 1; /* server can turn on by loading key */
|
|
}
|
|
#endif
|
|
ctx->suites.setSuites = 0; /* user hasn't set yet */
|
|
/* remove DH later if server didn't set, add psk later */
|
|
InitSuites(&ctx->suites, method->version, TRUE, FALSE, TRUE, ctx->haveNTRU,
|
|
ctx->haveECDSAsig, ctx->haveStaticECC, method->side);
|
|
ctx->verifyPeer = 0;
|
|
ctx->verifyNone = 0;
|
|
ctx->failNoCert = 0;
|
|
ctx->sessionCacheOff = 0; /* initially on */
|
|
ctx->sessionCacheFlushOff = 0; /* initially on */
|
|
ctx->sendVerify = 0;
|
|
ctx->quietShutdown = 0;
|
|
ctx->groupMessages = 0;
|
|
#ifdef HAVE_CAVIUM
|
|
ctx->devId = NO_CAVIUM_DEVICE;
|
|
#endif
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
ctx->extensions = NULL;
|
|
#endif
|
|
#ifdef ATOMIC_USER
|
|
ctx->MacEncryptCb = NULL;
|
|
ctx->DecryptVerifyCb = NULL;
|
|
#endif
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
ctx->EccSignCb = NULL;
|
|
ctx->EccVerifyCb = NULL;
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_RSA
|
|
ctx->RsaSignCb = NULL;
|
|
ctx->RsaVerifyCb = NULL;
|
|
ctx->RsaEncCb = NULL;
|
|
ctx->RsaDecCb = NULL;
|
|
#endif /* NO_RSA */
|
|
#endif /* HAVE_PK_CALLBACKS */
|
|
|
|
if (InitMutex(&ctx->countMutex) < 0) {
|
|
WOLFSSL_MSG("Mutex error on CTX init");
|
|
return BAD_MUTEX_E;
|
|
}
|
|
#ifndef NO_CERTS
|
|
if (ctx->cm == NULL) {
|
|
WOLFSSL_MSG("Bad Cert Manager New");
|
|
return BAD_CERT_MANAGER_ERROR;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* In case contexts are held in array and don't want to free actual ctx */
|
|
void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
|
|
{
|
|
XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD);
|
|
|
|
#ifndef NO_CERTS
|
|
XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH);
|
|
XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH);
|
|
XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
|
|
XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
|
|
XFREE(ctx->certChain.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
|
|
wolfSSL_CertManagerFree(ctx->cm);
|
|
#endif
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
TLSX_FreeAll(ctx->extensions);
|
|
#endif
|
|
}
|
|
|
|
|
|
void FreeSSL_Ctx(WOLFSSL_CTX* ctx)
|
|
{
|
|
int doFree = 0;
|
|
|
|
if (LockMutex(&ctx->countMutex) != 0) {
|
|
WOLFSSL_MSG("Couldn't lock count mutex");
|
|
return;
|
|
}
|
|
ctx->refCount--;
|
|
if (ctx->refCount == 0)
|
|
doFree = 1;
|
|
UnLockMutex(&ctx->countMutex);
|
|
|
|
if (doFree) {
|
|
WOLFSSL_MSG("CTX ref count down to 0, doing full free");
|
|
SSL_CtxResourceFree(ctx);
|
|
FreeMutex(&ctx->countMutex);
|
|
XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX);
|
|
}
|
|
else {
|
|
(void)ctx;
|
|
WOLFSSL_MSG("CTX ref count not 0 yet, no free");
|
|
}
|
|
}
|
|
|
|
|
|
/* Set cipher pointers to null */
|
|
void InitCiphers(WOLFSSL* ssl)
|
|
{
|
|
#ifdef BUILD_ARC4
|
|
ssl->encrypt.arc4 = NULL;
|
|
ssl->decrypt.arc4 = NULL;
|
|
#endif
|
|
#ifdef BUILD_DES3
|
|
ssl->encrypt.des3 = NULL;
|
|
ssl->decrypt.des3 = NULL;
|
|
#endif
|
|
#ifdef BUILD_AES
|
|
ssl->encrypt.aes = NULL;
|
|
ssl->decrypt.aes = NULL;
|
|
#endif
|
|
#ifdef HAVE_CAMELLIA
|
|
ssl->encrypt.cam = NULL;
|
|
ssl->decrypt.cam = NULL;
|
|
#endif
|
|
#ifdef HAVE_HC128
|
|
ssl->encrypt.hc128 = NULL;
|
|
ssl->decrypt.hc128 = NULL;
|
|
#endif
|
|
#ifdef BUILD_RABBIT
|
|
ssl->encrypt.rabbit = NULL;
|
|
ssl->decrypt.rabbit = NULL;
|
|
#endif
|
|
#ifdef HAVE_CHACHA
|
|
ssl->encrypt.chacha = NULL;
|
|
ssl->decrypt.chacha = NULL;
|
|
#endif
|
|
#ifdef HAVE_POLY1305
|
|
ssl->auth.poly1305 = NULL;
|
|
#endif
|
|
ssl->encrypt.setup = 0;
|
|
ssl->decrypt.setup = 0;
|
|
#ifdef HAVE_ONE_TIME_AUTH
|
|
ssl->auth.setup = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Free ciphers */
|
|
void FreeCiphers(WOLFSSL* ssl)
|
|
{
|
|
(void)ssl;
|
|
#ifdef BUILD_ARC4
|
|
#ifdef HAVE_CAVIUM
|
|
if (ssl->devId != NO_CAVIUM_DEVICE) {
|
|
wc_Arc4FreeCavium(ssl->encrypt.arc4);
|
|
wc_Arc4FreeCavium(ssl->decrypt.arc4);
|
|
}
|
|
#endif
|
|
XFREE(ssl->encrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef BUILD_DES3
|
|
#ifdef HAVE_CAVIUM
|
|
if (ssl->devId != NO_CAVIUM_DEVICE) {
|
|
Des3_FreeCavium(ssl->encrypt.des3);
|
|
Des3_FreeCavium(ssl->decrypt.des3);
|
|
}
|
|
#endif
|
|
XFREE(ssl->encrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef BUILD_AES
|
|
#ifdef HAVE_CAVIUM
|
|
if (ssl->devId != NO_CAVIUM_DEVICE) {
|
|
wc_AesFreeCavium(ssl->encrypt.aes);
|
|
wc_AesFreeCavium(ssl->decrypt.aes);
|
|
}
|
|
#endif
|
|
XFREE(ssl->encrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef HAVE_CAMELLIA
|
|
XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef HAVE_HC128
|
|
XFREE(ssl->encrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef BUILD_RABBIT
|
|
XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef HAVE_CHACHA
|
|
XFREE(ssl->encrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
XFREE(ssl->decrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
#ifdef HAVE_POLY1305
|
|
XFREE(ssl->auth.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER);
|
|
#endif
|
|
}
|
|
|
|
|
|
void InitCipherSpecs(CipherSpecs* cs)
|
|
{
|
|
cs->bulk_cipher_algorithm = INVALID_BYTE;
|
|
cs->cipher_type = INVALID_BYTE;
|
|
cs->mac_algorithm = INVALID_BYTE;
|
|
cs->kea = INVALID_BYTE;
|
|
cs->sig_algo = INVALID_BYTE;
|
|
|
|
cs->hash_size = 0;
|
|
cs->static_ecdh = 0;
|
|
cs->key_size = 0;
|
|
cs->iv_size = 0;
|
|
cs->block_size = 0;
|
|
}
|
|
|
|
static void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig,
|
|
int haveRSAsig, int haveAnon)
|
|
{
|
|
int idx = 0;
|
|
|
|
if (haveECDSAsig) {
|
|
#ifdef WOLFSSL_SHA384
|
|
suites->hashSigAlgo[idx++] = sha384_mac;
|
|
suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
suites->hashSigAlgo[idx++] = sha256_mac;
|
|
suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
|
|
#endif
|
|
#ifndef NO_SHA
|
|
suites->hashSigAlgo[idx++] = sha_mac;
|
|
suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
|
|
#endif
|
|
}
|
|
|
|
if (haveRSAsig) {
|
|
#ifdef WOLFSSL_SHA384
|
|
suites->hashSigAlgo[idx++] = sha384_mac;
|
|
suites->hashSigAlgo[idx++] = rsa_sa_algo;
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
suites->hashSigAlgo[idx++] = sha256_mac;
|
|
suites->hashSigAlgo[idx++] = rsa_sa_algo;
|
|
#endif
|
|
#ifndef NO_SHA
|
|
suites->hashSigAlgo[idx++] = sha_mac;
|
|
suites->hashSigAlgo[idx++] = rsa_sa_algo;
|
|
#endif
|
|
}
|
|
|
|
if (haveAnon) {
|
|
#ifdef HAVE_ANON
|
|
suites->hashSigAlgo[idx++] = sha_mac;
|
|
suites->hashSigAlgo[idx++] = anonymous_sa_algo;
|
|
#endif
|
|
}
|
|
|
|
suites->hashSigAlgoSz = (word16)idx;
|
|
}
|
|
|
|
void InitSuites(Suites* suites, ProtocolVersion pv, byte haveRSA, byte havePSK,
|
|
byte haveDH, byte haveNTRU, byte haveECDSAsig,
|
|
byte haveStaticECC, int side)
|
|
{
|
|
word16 idx = 0;
|
|
int tls = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR;
|
|
int tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR;
|
|
int haveRSAsig = 1;
|
|
|
|
(void)tls; /* shut up compiler */
|
|
(void)tls1_2;
|
|
(void)haveDH;
|
|
(void)havePSK;
|
|
(void)haveNTRU;
|
|
(void)haveStaticECC;
|
|
|
|
if (suites == NULL) {
|
|
WOLFSSL_MSG("InitSuites pointer error");
|
|
return;
|
|
}
|
|
|
|
if (suites->setSuites)
|
|
return; /* trust user settings, don't override */
|
|
|
|
if (side == WOLFSSL_SERVER_END && haveStaticECC) {
|
|
haveRSA = 0; /* can't do RSA with ECDSA key */
|
|
(void)haveRSA; /* some builds won't read */
|
|
}
|
|
|
|
if (side == WOLFSSL_SERVER_END && haveECDSAsig) {
|
|
haveRSAsig = 0; /* can't have RSA sig if signed by ECDSA */
|
|
(void)haveRSAsig; /* non ecc builds won't read */
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (pv.major == DTLS_MAJOR) {
|
|
tls = 1;
|
|
tls1_2 = pv.minor <= DTLSv1_2_MINOR;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_RENEGOTIATION_INDICATION
|
|
if (side == WOLFSSL_CLIENT_END) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveNTRU && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveNTRU && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
|
|
if (tls && haveNTRU && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
|
|
if (tls && haveNTRU && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
|
|
if (tls1_2 && haveRSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
|
|
if (tls1_2 && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
|
|
if (tls1_2 && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
|
|
if (tls1_2 && haveRSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
|
|
if (tls1_2 && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
|
|
if (tls1_2 && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
|
|
if (tls && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
|
|
if (tls && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
|
|
if (tls && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
|
|
if (tls && haveECDSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
|
|
if (tls && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_RC4_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = CHACHA_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = CHACHA_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = CHACHA_BYTE;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
|
|
if (tls && haveRSAsig && haveStaticECC) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
|
|
if (tls1_2 && haveECDSAsig) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_128_CCM_8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_256_CCM_8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
|
|
if (tls1_2 && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
|
|
if (tls1_2 && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
|
|
if (tls1_2 && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && haveDH && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
|
|
if (tls1_2 && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_256_GCM_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
|
|
if (tls && haveDH && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && haveDH && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
|
|
if (tls1_2 && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_128_GCM_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
|
|
if (tls && haveDH && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
|
|
if (tls && haveDH && havePSK) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CCM;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
|
|
if (tls && haveDH && havePSK) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CCM;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM_8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = ECC_BYTE;
|
|
suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM_8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
|
|
if (tls && haveDH && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA384;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
|
|
if (tls && haveDH && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA
|
|
if (tls && havePSK) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
|
|
if (haveRSA ) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
|
|
if (haveRSA ) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
|
|
if (haveRSA ) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_HC_128_B2B256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_B2B256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_B2B256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
|
|
if (tls && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_WITH_RSA_CAMELLIA_256_CBC_SHA
|
|
if (tls && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
|
if (tls && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
|
if (tls && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
|
if (tls && haveDH && haveRSA) {
|
|
suites->suites[idx++] = 0;
|
|
suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256;
|
|
}
|
|
#endif
|
|
|
|
suites->suiteSz = idx;
|
|
|
|
InitSuitesHashSigAlgo(suites, haveECDSAsig, haveRSAsig, 0);
|
|
}
|
|
|
|
|
|
#ifndef NO_CERTS
|
|
|
|
|
|
void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag)
|
|
{
|
|
(void)dynamicFlag;
|
|
|
|
if (name != NULL) {
|
|
name->name = name->staticName;
|
|
name->dynamicName = 0;
|
|
#ifdef OPENSSL_EXTRA
|
|
XMEMSET(&name->fullName, 0, sizeof(DecodedName));
|
|
#endif /* OPENSSL_EXTRA */
|
|
}
|
|
}
|
|
|
|
|
|
void FreeX509Name(WOLFSSL_X509_NAME* name)
|
|
{
|
|
if (name != NULL) {
|
|
if (name->dynamicName)
|
|
XFREE(name->name, NULL, DYNAMIC_TYPE_SUBJECT_CN);
|
|
#ifdef OPENSSL_EXTRA
|
|
if (name->fullName.fullName != NULL)
|
|
XFREE(name->fullName.fullName, NULL, DYNAMIC_TYPE_X509);
|
|
#endif /* OPENSSL_EXTRA */
|
|
}
|
|
}
|
|
|
|
|
|
/* Initialize wolfSSL X509 type */
|
|
void InitX509(WOLFSSL_X509* x509, int dynamicFlag)
|
|
{
|
|
InitX509Name(&x509->issuer, 0);
|
|
InitX509Name(&x509->subject, 0);
|
|
x509->version = 0;
|
|
x509->pubKey.buffer = NULL;
|
|
x509->sig.buffer = NULL;
|
|
x509->derCert.buffer = NULL;
|
|
x509->altNames = NULL;
|
|
x509->altNamesNext = NULL;
|
|
x509->dynamicMemory = (byte)dynamicFlag;
|
|
x509->isCa = 0;
|
|
#ifdef HAVE_ECC
|
|
x509->pkCurveOID = 0;
|
|
#endif /* HAVE_ECC */
|
|
#ifdef OPENSSL_EXTRA
|
|
x509->pathLength = 0;
|
|
x509->basicConstSet = 0;
|
|
x509->basicConstCrit = 0;
|
|
x509->basicConstPlSet = 0;
|
|
x509->subjAltNameSet = 0;
|
|
x509->subjAltNameCrit = 0;
|
|
x509->authKeyIdSet = 0;
|
|
x509->authKeyIdCrit = 0;
|
|
x509->authKeyId = NULL;
|
|
x509->authKeyIdSz = 0;
|
|
x509->subjKeyIdSet = 0;
|
|
x509->subjKeyIdCrit = 0;
|
|
x509->subjKeyId = NULL;
|
|
x509->subjKeyIdSz = 0;
|
|
x509->keyUsageSet = 0;
|
|
x509->keyUsageCrit = 0;
|
|
x509->keyUsage = 0;
|
|
#ifdef WOLFSSL_SEP
|
|
x509->certPolicySet = 0;
|
|
x509->certPolicyCrit = 0;
|
|
#endif /* WOLFSSL_SEP */
|
|
#endif /* OPENSSL_EXTRA */
|
|
}
|
|
|
|
|
|
/* Free wolfSSL X509 type */
|
|
void FreeX509(WOLFSSL_X509* x509)
|
|
{
|
|
if (x509 == NULL)
|
|
return;
|
|
|
|
FreeX509Name(&x509->issuer);
|
|
FreeX509Name(&x509->subject);
|
|
if (x509->pubKey.buffer)
|
|
XFREE(x509->pubKey.buffer, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_SUBJECT_CN);
|
|
XFREE(x509->sig.buffer, NULL, DYNAMIC_TYPE_SIGNATURE);
|
|
#ifdef OPENSSL_EXTRA
|
|
XFREE(x509->authKeyId, NULL, 0);
|
|
XFREE(x509->subjKeyId, NULL, 0);
|
|
#endif /* OPENSSL_EXTRA */
|
|
if (x509->altNames)
|
|
FreeAltNames(x509->altNames, NULL);
|
|
if (x509->dynamicMemory)
|
|
XFREE(x509, NULL, DYNAMIC_TYPE_X509);
|
|
}
|
|
|
|
#endif /* NO_CERTS */
|
|
|
|
|
|
/* init everything to 0, NULL, default values before calling anything that may
|
|
fail so that desctructor has a "good" state to cleanup */
|
|
int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
|
|
{
|
|
int ret;
|
|
byte haveRSA = 0;
|
|
byte havePSK = 0;
|
|
byte haveAnon = 0;
|
|
|
|
ssl->ctx = ctx; /* only for passing to calls, options could change */
|
|
ssl->version = ctx->method->version;
|
|
ssl->suites = NULL;
|
|
|
|
#ifdef HAVE_LIBZ
|
|
ssl->didStreamInit = 0;
|
|
#endif
|
|
#ifndef NO_RSA
|
|
haveRSA = 1;
|
|
#endif
|
|
|
|
#ifndef NO_CERTS
|
|
ssl->buffers.certificate.buffer = 0;
|
|
ssl->buffers.key.buffer = 0;
|
|
ssl->buffers.certChain.buffer = 0;
|
|
#endif
|
|
ssl->buffers.inputBuffer.length = 0;
|
|
ssl->buffers.inputBuffer.idx = 0;
|
|
ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
|
|
ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN;
|
|
ssl->buffers.inputBuffer.dynamicFlag = 0;
|
|
ssl->buffers.inputBuffer.offset = 0;
|
|
ssl->buffers.outputBuffer.length = 0;
|
|
ssl->buffers.outputBuffer.idx = 0;
|
|
ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
|
|
ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN;
|
|
ssl->buffers.outputBuffer.dynamicFlag = 0;
|
|
ssl->buffers.outputBuffer.offset = 0;
|
|
ssl->buffers.domainName.buffer = 0;
|
|
#ifndef NO_CERTS
|
|
ssl->buffers.serverDH_P.buffer = 0;
|
|
ssl->buffers.serverDH_G.buffer = 0;
|
|
ssl->buffers.serverDH_Pub.buffer = 0;
|
|
ssl->buffers.serverDH_Priv.buffer = 0;
|
|
#endif
|
|
ssl->buffers.clearOutputBuffer.buffer = 0;
|
|
ssl->buffers.clearOutputBuffer.length = 0;
|
|
ssl->buffers.prevSent = 0;
|
|
ssl->buffers.plainSz = 0;
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
ssl->buffers.peerEccDsaKey.buffer = 0;
|
|
ssl->buffers.peerEccDsaKey.length = 0;
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_RSA
|
|
ssl->buffers.peerRsaKey.buffer = 0;
|
|
ssl->buffers.peerRsaKey.length = 0;
|
|
#endif /* NO_RSA */
|
|
#endif /* HAVE_PK_CALLBACKS */
|
|
|
|
#ifdef KEEP_PEER_CERT
|
|
InitX509(&ssl->peerCert, 0);
|
|
#endif
|
|
|
|
#ifdef HAVE_ECC
|
|
ssl->eccTempKeySz = ctx->eccTempKeySz;
|
|
ssl->pkCurveOID = ctx->pkCurveOID;
|
|
ssl->peerEccKeyPresent = 0;
|
|
ssl->peerEccDsaKeyPresent = 0;
|
|
ssl->eccDsaKeyPresent = 0;
|
|
ssl->eccTempKeyPresent = 0;
|
|
ssl->peerEccKey = NULL;
|
|
ssl->peerEccDsaKey = NULL;
|
|
ssl->eccDsaKey = NULL;
|
|
ssl->eccTempKey = NULL;
|
|
#endif
|
|
|
|
ssl->timeout = ctx->timeout;
|
|
ssl->rfd = -1; /* set to invalid descriptor */
|
|
ssl->wfd = -1;
|
|
ssl->rflags = 0; /* no user flags yet */
|
|
ssl->wflags = 0; /* no user flags yet */
|
|
ssl->biord = 0;
|
|
ssl->biowr = 0;
|
|
|
|
ssl->IOCB_ReadCtx = &ssl->rfd; /* prevent invalid pointer access if not */
|
|
ssl->IOCB_WriteCtx = &ssl->wfd; /* correctly set */
|
|
#ifdef HAVE_NETX
|
|
ssl->nxCtx.nxSocket = NULL;
|
|
ssl->nxCtx.nxPacket = NULL;
|
|
ssl->nxCtx.nxOffset = 0;
|
|
ssl->nxCtx.nxWait = 0;
|
|
ssl->IOCB_ReadCtx = &ssl->nxCtx; /* default NetX IO ctx, same for read */
|
|
ssl->IOCB_WriteCtx = &ssl->nxCtx; /* and write */
|
|
#endif
|
|
#ifdef WOLFSSL_DTLS
|
|
ssl->IOCB_CookieCtx = NULL; /* we don't use for default cb */
|
|
ssl->dtls_expected_rx = MAX_MTU;
|
|
ssl->keys.dtls_state.window = 0;
|
|
ssl->keys.dtls_state.nextEpoch = 0;
|
|
ssl->keys.dtls_state.nextSeq = 0;
|
|
#endif
|
|
|
|
XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived));
|
|
|
|
#ifndef NO_RSA
|
|
ssl->peerRsaKey = NULL;
|
|
ssl->peerRsaKeyPresent = 0;
|
|
#endif
|
|
ssl->verifyCallback = ctx->verifyCallback;
|
|
ssl->verifyCbCtx = NULL;
|
|
ssl->options.side = ctx->method->side;
|
|
ssl->options.downgrade = ctx->method->downgrade;
|
|
ssl->options.minDowngrade = TLSv1_MINOR; /* current default */
|
|
ssl->error = 0;
|
|
ssl->options.connReset = 0;
|
|
ssl->options.isClosed = 0;
|
|
ssl->options.closeNotify = 0;
|
|
ssl->options.sentNotify = 0;
|
|
ssl->options.usingCompression = 0;
|
|
if (ssl->options.side == WOLFSSL_SERVER_END)
|
|
ssl->options.haveDH = ctx->haveDH;
|
|
else
|
|
ssl->options.haveDH = 0;
|
|
ssl->options.haveNTRU = ctx->haveNTRU;
|
|
ssl->options.haveECDSAsig = ctx->haveECDSAsig;
|
|
ssl->options.haveStaticECC = ctx->haveStaticECC;
|
|
ssl->options.havePeerCert = 0;
|
|
ssl->options.havePeerVerify = 0;
|
|
ssl->options.usingPSK_cipher = 0;
|
|
ssl->options.usingAnon_cipher = 0;
|
|
ssl->options.sendAlertState = 0;
|
|
#ifndef NO_PSK
|
|
havePSK = ctx->havePSK;
|
|
ssl->options.havePSK = ctx->havePSK;
|
|
ssl->options.client_psk_cb = ctx->client_psk_cb;
|
|
ssl->options.server_psk_cb = ctx->server_psk_cb;
|
|
#endif /* NO_PSK */
|
|
#ifdef HAVE_ANON
|
|
haveAnon = ctx->haveAnon;
|
|
ssl->options.haveAnon = ctx->haveAnon;
|
|
#endif
|
|
|
|
ssl->options.serverState = NULL_STATE;
|
|
ssl->options.clientState = NULL_STATE;
|
|
ssl->options.connectState = CONNECT_BEGIN;
|
|
ssl->options.acceptState = ACCEPT_BEGIN;
|
|
ssl->options.handShakeState = NULL_STATE;
|
|
ssl->options.handShakeDone = 0;
|
|
ssl->options.processReply = doProcessInit;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
ssl->keys.dtls_sequence_number = 0;
|
|
ssl->keys.dtls_state.curSeq = 0;
|
|
ssl->keys.dtls_state.nextSeq = 0;
|
|
ssl->keys.dtls_handshake_number = 0;
|
|
ssl->keys.dtls_expected_peer_handshake_number = 0;
|
|
ssl->keys.dtls_epoch = 0;
|
|
ssl->keys.dtls_state.curEpoch = 0;
|
|
ssl->keys.dtls_state.nextEpoch = 0;
|
|
ssl->dtls_timeout_init = DTLS_TIMEOUT_INIT;
|
|
ssl->dtls_timeout_max = DTLS_TIMEOUT_MAX;
|
|
ssl->dtls_timeout = ssl->dtls_timeout_init;
|
|
ssl->dtls_pool = NULL;
|
|
ssl->dtls_msg_list = NULL;
|
|
#endif
|
|
ssl->keys.encryptSz = 0;
|
|
ssl->keys.padSz = 0;
|
|
ssl->keys.encryptionOn = 0; /* initially off */
|
|
ssl->keys.decryptedCur = 0; /* initially off */
|
|
ssl->options.sessionCacheOff = ctx->sessionCacheOff;
|
|
ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff;
|
|
|
|
ssl->options.verifyPeer = ctx->verifyPeer;
|
|
ssl->options.verifyNone = ctx->verifyNone;
|
|
ssl->options.failNoCert = ctx->failNoCert;
|
|
ssl->options.sendVerify = ctx->sendVerify;
|
|
|
|
ssl->options.resuming = 0;
|
|
ssl->options.haveSessionId = 0;
|
|
#ifndef NO_OLD_TLS
|
|
ssl->hmac = SSL_hmac; /* default to SSLv3 */
|
|
#else
|
|
ssl->hmac = TLS_hmac;
|
|
#endif
|
|
ssl->heap = ctx->heap; /* defaults to self */
|
|
ssl->options.tls = 0;
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->options.dtls = ssl->version.major == DTLS_MAJOR;
|
|
ssl->options.partialWrite = ctx->partialWrite;
|
|
ssl->options.quietShutdown = ctx->quietShutdown;
|
|
ssl->options.certOnly = 0;
|
|
ssl->options.groupMessages = ctx->groupMessages;
|
|
ssl->options.usingNonblock = 0;
|
|
ssl->options.saveArrays = 0;
|
|
#ifdef HAVE_POLY1305
|
|
ssl->options.oldPoly = 0;
|
|
#endif
|
|
|
|
#ifndef NO_CERTS
|
|
/* ctx still owns certificate, certChain, key, dh, and cm */
|
|
ssl->buffers.certificate = ctx->certificate;
|
|
ssl->buffers.certChain = ctx->certChain;
|
|
ssl->buffers.key = ctx->privateKey;
|
|
if (ssl->options.side == WOLFSSL_SERVER_END) {
|
|
ssl->buffers.serverDH_P = ctx->serverDH_P;
|
|
ssl->buffers.serverDH_G = ctx->serverDH_G;
|
|
}
|
|
#endif
|
|
ssl->buffers.weOwnCert = 0;
|
|
ssl->buffers.weOwnCertChain = 0;
|
|
ssl->buffers.weOwnKey = 0;
|
|
ssl->buffers.weOwnDH = 0;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
ssl->buffers.dtlsCtx.fd = -1;
|
|
ssl->buffers.dtlsCtx.peer.sa = NULL;
|
|
ssl->buffers.dtlsCtx.peer.sz = 0;
|
|
#endif
|
|
|
|
#ifdef KEEP_PEER_CERT
|
|
ssl->peerCert.issuer.sz = 0;
|
|
ssl->peerCert.subject.sz = 0;
|
|
#endif
|
|
|
|
#ifdef SESSION_CERTS
|
|
ssl->session.chain.count = 0;
|
|
#endif
|
|
|
|
#ifndef NO_CLIENT_CACHE
|
|
ssl->session.idLen = 0;
|
|
#endif
|
|
|
|
#ifdef HAVE_SESSION_TICKET
|
|
ssl->session.ticketLen = 0;
|
|
#endif
|
|
|
|
ssl->cipher.ssl = ssl;
|
|
|
|
#ifdef FORTRESS
|
|
ssl->ex_data[0] = 0;
|
|
ssl->ex_data[1] = 0;
|
|
ssl->ex_data[2] = 0;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
ssl->hsInfoOn = 0;
|
|
ssl->toInfoOn = 0;
|
|
#endif
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
ssl->devId = ctx->devId;
|
|
#endif
|
|
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
ssl->extensions = NULL;
|
|
#ifdef HAVE_MAX_FRAGMENT
|
|
ssl->max_fragment = MAX_RECORD_SIZE;
|
|
#endif
|
|
#ifdef HAVE_TRUNCATED_HMAC
|
|
ssl->truncated_hmac = 0;
|
|
#endif
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
ssl->secure_renegotiation = NULL;
|
|
#endif
|
|
#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
|
|
ssl->session_ticket_cb = NULL;
|
|
ssl->session_ticket_ctx = NULL;
|
|
ssl->expect_session_ticket = 0;
|
|
#endif
|
|
#endif
|
|
|
|
ssl->rng = NULL;
|
|
ssl->arrays = NULL;
|
|
|
|
/* default alert state (none) */
|
|
ssl->alert_history.last_rx.code = -1;
|
|
ssl->alert_history.last_rx.level = -1;
|
|
ssl->alert_history.last_tx.code = -1;
|
|
ssl->alert_history.last_tx.level = -1;
|
|
|
|
InitCiphers(ssl);
|
|
InitCipherSpecs(&ssl->specs);
|
|
#ifdef ATOMIC_USER
|
|
ssl->MacEncryptCtx = NULL;
|
|
ssl->DecryptVerifyCtx = NULL;
|
|
#endif
|
|
#ifdef HAVE_FUZZER
|
|
ssl->fuzzerCb = NULL;
|
|
ssl->fuzzerCtx = NULL;
|
|
#endif
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
ssl->EccSignCtx = NULL;
|
|
ssl->EccVerifyCtx = NULL;
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_RSA
|
|
ssl->RsaSignCtx = NULL;
|
|
ssl->RsaVerifyCtx = NULL;
|
|
ssl->RsaEncCtx = NULL;
|
|
ssl->RsaDecCtx = NULL;
|
|
#endif /* NO_RSA */
|
|
#endif /* HAVE_PK_CALLBACKS */
|
|
|
|
/* all done with init, now can return errors, call other stuff */
|
|
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
InitMd5(&ssl->hashMd5);
|
|
#endif
|
|
#ifndef NO_SHA
|
|
ret = InitSha(&ssl->hashSha);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
ret = InitSha256(&ssl->hashSha256);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
ret = InitSha384(&ssl->hashSha384);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* increment CTX reference count */
|
|
if (LockMutex(&ctx->countMutex) != 0) {
|
|
WOLFSSL_MSG("Couldn't lock CTX count mutex");
|
|
return BAD_MUTEX_E;
|
|
}
|
|
ctx->refCount++;
|
|
UnLockMutex(&ctx->countMutex);
|
|
|
|
/* arrays */
|
|
ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap,
|
|
DYNAMIC_TYPE_ARRAYS);
|
|
if (ssl->arrays == NULL) {
|
|
WOLFSSL_MSG("Arrays Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
XMEMSET(ssl->arrays, 0, sizeof(Arrays));
|
|
|
|
#ifndef NO_PSK
|
|
ssl->arrays->client_identity[0] = 0;
|
|
if (ctx->server_hint[0]) { /* set in CTX */
|
|
XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint, MAX_PSK_ID_LEN);
|
|
ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0';
|
|
}
|
|
else
|
|
ssl->arrays->server_hint[0] = 0;
|
|
#endif /* NO_PSK */
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
ssl->arrays->cookieSz = 0;
|
|
#endif
|
|
|
|
/* RNG */
|
|
ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG);
|
|
if (ssl->rng == NULL) {
|
|
WOLFSSL_MSG("RNG Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
|
|
if ( (ret = InitRng(ssl->rng)) != 0) {
|
|
WOLFSSL_MSG("RNG Init error");
|
|
return ret;
|
|
}
|
|
|
|
/* suites */
|
|
ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap,
|
|
DYNAMIC_TYPE_SUITES);
|
|
if (ssl->suites == NULL) {
|
|
WOLFSSL_MSG("Suites Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
*ssl->suites = ctx->suites;
|
|
|
|
/* peer key */
|
|
#ifndef NO_RSA
|
|
ssl->peerRsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey), ssl->heap,
|
|
DYNAMIC_TYPE_RSA);
|
|
if (ssl->peerRsaKey == NULL) {
|
|
WOLFSSL_MSG("PeerRsaKey Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
ret = InitRsaKey(ssl->peerRsaKey, ctx->heap);
|
|
if (ret != 0) return ret;
|
|
#endif
|
|
#ifndef NO_CERTS
|
|
/* make sure server has cert and key unless using PSK or Anon */
|
|
if (ssl->options.side == WOLFSSL_SERVER_END && !havePSK && !haveAnon)
|
|
if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) {
|
|
WOLFSSL_MSG("Server missing certificate and/or private key");
|
|
return NO_PRIVATE_KEY;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
|
|
ctx->heap, DYNAMIC_TYPE_ECC);
|
|
if (ssl->peerEccKey == NULL) {
|
|
WOLFSSL_MSG("PeerEccKey Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
|
|
ctx->heap, DYNAMIC_TYPE_ECC);
|
|
if (ssl->peerEccDsaKey == NULL) {
|
|
WOLFSSL_MSG("PeerEccDsaKey Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
ssl->eccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
|
|
ctx->heap, DYNAMIC_TYPE_ECC);
|
|
if (ssl->eccDsaKey == NULL) {
|
|
WOLFSSL_MSG("EccDsaKey Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
|
|
ctx->heap, DYNAMIC_TYPE_ECC);
|
|
if (ssl->eccTempKey == NULL) {
|
|
WOLFSSL_MSG("EccTempKey Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
ecc_init(ssl->peerEccKey);
|
|
ecc_init(ssl->peerEccDsaKey);
|
|
ecc_init(ssl->eccDsaKey);
|
|
ecc_init(ssl->eccTempKey);
|
|
#endif
|
|
#ifdef HAVE_SECRET_CALLBACK
|
|
ssl->sessionSecretCb = NULL;
|
|
ssl->sessionSecretCtx = NULL;
|
|
#endif
|
|
|
|
/* make sure server has DH parms, and add PSK if there, add NTRU too */
|
|
if (ssl->options.side == WOLFSSL_SERVER_END)
|
|
InitSuites(ssl->suites, ssl->version, haveRSA, havePSK,
|
|
ssl->options.haveDH, ssl->options.haveNTRU,
|
|
ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
|
|
ssl->options.side);
|
|
else
|
|
InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, TRUE,
|
|
ssl->options.haveNTRU, ssl->options.haveECDSAsig,
|
|
ssl->options.haveStaticECC, ssl->options.side);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* free use of temporary arrays */
|
|
void FreeArrays(WOLFSSL* ssl, int keep)
|
|
{
|
|
if (ssl->arrays && keep) {
|
|
/* keeps session id for user retrieval */
|
|
XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN);
|
|
ssl->session.sessionIDSz = ssl->arrays->sessionIDSz;
|
|
}
|
|
XFREE(ssl->arrays, ssl->heap, DYNAMIC_TYPE_ARRAYS);
|
|
ssl->arrays = NULL;
|
|
}
|
|
|
|
|
|
/* In case holding SSL object in array and don't want to free actual ssl */
|
|
void SSL_ResourceFree(WOLFSSL* ssl)
|
|
{
|
|
/* Note: any resources used during the handshake should be released in the
|
|
* function FreeHandshakeResources(). Be careful with the special cases
|
|
* like the RNG which may optionally be kept for the whole session. (For
|
|
* example with the RNG, it isn't used beyond the handshake except when
|
|
* using stream ciphers where it is retained. */
|
|
|
|
FreeCiphers(ssl);
|
|
FreeArrays(ssl, 0);
|
|
#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
|
|
FreeRng(ssl->rng);
|
|
#endif
|
|
XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
|
|
XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
|
|
XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
|
|
|
|
#ifndef NO_CERTS
|
|
XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH);
|
|
XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH);
|
|
/* parameters (p,g) may be owned by ctx */
|
|
if (ssl->buffers.weOwnDH || ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH);
|
|
XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH);
|
|
}
|
|
|
|
if (ssl->buffers.weOwnCert)
|
|
XFREE(ssl->buffers.certificate.buffer, ssl->heap, DYNAMIC_TYPE_CERT);
|
|
if (ssl->buffers.weOwnCertChain)
|
|
XFREE(ssl->buffers.certChain.buffer, ssl->heap, DYNAMIC_TYPE_CERT);
|
|
if (ssl->buffers.weOwnKey)
|
|
XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY);
|
|
#endif
|
|
#ifndef NO_RSA
|
|
if (ssl->peerRsaKey) {
|
|
FreeRsaKey(ssl->peerRsaKey);
|
|
XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA);
|
|
}
|
|
#endif
|
|
if (ssl->buffers.inputBuffer.dynamicFlag)
|
|
ShrinkInputBuffer(ssl, FORCED_FREE);
|
|
if (ssl->buffers.outputBuffer.dynamicFlag)
|
|
ShrinkOutputBuffer(ssl);
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->dtls_pool != NULL) {
|
|
DtlsPoolReset(ssl);
|
|
XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE);
|
|
}
|
|
if (ssl->dtls_msg_list != NULL) {
|
|
DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap);
|
|
ssl->dtls_msg_list = NULL;
|
|
}
|
|
XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
|
|
ssl->buffers.dtlsCtx.peer.sa = NULL;
|
|
#endif
|
|
#if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS)
|
|
FreeX509(&ssl->peerCert);
|
|
#endif
|
|
#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
|
|
wolfSSL_BIO_free(ssl->biord);
|
|
if (ssl->biord != ssl->biowr) /* in case same as write */
|
|
wolfSSL_BIO_free(ssl->biowr);
|
|
#endif
|
|
#ifdef HAVE_LIBZ
|
|
FreeStreams(ssl);
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
if (ssl->peerEccKey) {
|
|
if (ssl->peerEccKeyPresent)
|
|
ecc_free(ssl->peerEccKey);
|
|
XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
}
|
|
if (ssl->peerEccDsaKey) {
|
|
if (ssl->peerEccDsaKeyPresent)
|
|
ecc_free(ssl->peerEccDsaKey);
|
|
XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
}
|
|
if (ssl->eccTempKey) {
|
|
if (ssl->eccTempKeyPresent)
|
|
ecc_free(ssl->eccTempKey);
|
|
XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
}
|
|
if (ssl->eccDsaKey) {
|
|
if (ssl->eccDsaKeyPresent)
|
|
ecc_free(ssl->eccDsaKey);
|
|
XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
}
|
|
#endif
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_RSA
|
|
XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA);
|
|
#endif /* NO_RSA */
|
|
#endif /* HAVE_PK_CALLBACKS */
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
TLSX_FreeAll(ssl->extensions);
|
|
#endif
|
|
#ifdef HAVE_NETX
|
|
if (ssl->nxCtx.nxPacket)
|
|
nx_packet_release(ssl->nxCtx.nxPacket);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Free any handshake resources no longer needed */
|
|
void FreeHandshakeResources(WOLFSSL* ssl)
|
|
{
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
|
|
WOLFSSL_MSG("Secure Renegotiation needs to retain handshake resources");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* input buffer */
|
|
if (ssl->buffers.inputBuffer.dynamicFlag)
|
|
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
|
|
|
|
/* suites */
|
|
XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
|
|
ssl->suites = NULL;
|
|
|
|
/* RNG */
|
|
if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) {
|
|
#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
|
|
FreeRng(ssl->rng);
|
|
#endif
|
|
XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
|
|
ssl->rng = NULL;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
/* DTLS_POOL */
|
|
if (ssl->options.dtls && ssl->dtls_pool != NULL) {
|
|
DtlsPoolReset(ssl);
|
|
XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
|
|
ssl->dtls_pool = NULL;
|
|
}
|
|
#endif
|
|
|
|
/* arrays */
|
|
if (ssl->options.saveArrays)
|
|
FreeArrays(ssl, 1);
|
|
|
|
#ifndef NO_RSA
|
|
/* peerRsaKey */
|
|
if (ssl->peerRsaKey) {
|
|
FreeRsaKey(ssl->peerRsaKey);
|
|
XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA);
|
|
ssl->peerRsaKey = NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_ECC
|
|
if (ssl->peerEccKey)
|
|
{
|
|
if (ssl->peerEccKeyPresent) {
|
|
ecc_free(ssl->peerEccKey);
|
|
ssl->peerEccKeyPresent = 0;
|
|
}
|
|
XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
ssl->peerEccKey = NULL;
|
|
}
|
|
if (ssl->peerEccDsaKey)
|
|
{
|
|
if (ssl->peerEccDsaKeyPresent) {
|
|
ecc_free(ssl->peerEccDsaKey);
|
|
ssl->peerEccDsaKeyPresent = 0;
|
|
}
|
|
XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
ssl->peerEccDsaKey = NULL;
|
|
}
|
|
if (ssl->eccTempKey)
|
|
{
|
|
if (ssl->eccTempKeyPresent) {
|
|
ecc_free(ssl->eccTempKey);
|
|
ssl->eccTempKeyPresent = 0;
|
|
}
|
|
XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
ssl->eccTempKey = NULL;
|
|
}
|
|
if (ssl->eccDsaKey)
|
|
{
|
|
if (ssl->eccDsaKeyPresent) {
|
|
ecc_free(ssl->eccDsaKey);
|
|
ssl->eccDsaKeyPresent = 0;
|
|
}
|
|
XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
ssl->eccDsaKey = NULL;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
|
|
ssl->buffers.peerEccDsaKey.buffer = NULL;
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_RSA
|
|
XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA);
|
|
ssl->buffers.peerRsaKey.buffer = NULL;
|
|
#endif /* NO_RSA */
|
|
#endif /* HAVE_PK_CALLBACKS */
|
|
}
|
|
|
|
|
|
void FreeSSL(WOLFSSL* ssl)
|
|
{
|
|
FreeSSL_Ctx(ssl->ctx); /* will decrement and free underyling CTX if 0 */
|
|
SSL_ResourceFree(ssl);
|
|
XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL);
|
|
}
|
|
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
|
|
int DtlsPoolInit(WOLFSSL* ssl)
|
|
{
|
|
if (ssl->dtls_pool == NULL) {
|
|
DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool),
|
|
ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
|
|
if (pool == NULL) {
|
|
WOLFSSL_MSG("DTLS Buffer Pool Memory error");
|
|
return MEMORY_E;
|
|
}
|
|
else {
|
|
int i;
|
|
|
|
for (i = 0; i < DTLS_POOL_SZ; i++) {
|
|
pool->buf[i].length = 0;
|
|
pool->buf[i].buffer = NULL;
|
|
}
|
|
pool->used = 0;
|
|
ssl->dtls_pool = pool;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DtlsPoolSave(WOLFSSL* ssl, const byte *src, int sz)
|
|
{
|
|
DtlsPool *pool = ssl->dtls_pool;
|
|
if (pool != NULL && pool->used < DTLS_POOL_SZ) {
|
|
buffer *pBuf = &pool->buf[pool->used];
|
|
pBuf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
|
|
if (pBuf->buffer == NULL) {
|
|
WOLFSSL_MSG("DTLS Buffer Memory error");
|
|
return MEMORY_ERROR;
|
|
}
|
|
XMEMCPY(pBuf->buffer, src, sz);
|
|
pBuf->length = (word32)sz;
|
|
pool->used++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void DtlsPoolReset(WOLFSSL* ssl)
|
|
{
|
|
DtlsPool *pool = ssl->dtls_pool;
|
|
if (pool != NULL) {
|
|
buffer *pBuf;
|
|
int i, used;
|
|
|
|
used = pool->used;
|
|
for (i = 0, pBuf = &pool->buf[0]; i < used; i++, pBuf++) {
|
|
XFREE(pBuf->buffer, ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
|
|
pBuf->buffer = NULL;
|
|
pBuf->length = 0;
|
|
}
|
|
pool->used = 0;
|
|
}
|
|
ssl->dtls_timeout = ssl->dtls_timeout_init;
|
|
}
|
|
|
|
|
|
int DtlsPoolTimeout(WOLFSSL* ssl)
|
|
{
|
|
int result = -1;
|
|
if (ssl->dtls_timeout < ssl->dtls_timeout_max) {
|
|
ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER;
|
|
result = 0;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
int DtlsPoolSend(WOLFSSL* ssl)
|
|
{
|
|
int ret;
|
|
DtlsPool *pool = ssl->dtls_pool;
|
|
|
|
if (pool != NULL && pool->used > 0) {
|
|
int i;
|
|
for (i = 0; i < pool->used; i++) {
|
|
int sendResult;
|
|
buffer* buf = &pool->buf[i];
|
|
|
|
DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer;
|
|
|
|
word16 message_epoch;
|
|
ato16(dtls->epoch, &message_epoch);
|
|
if (message_epoch == ssl->keys.dtls_epoch) {
|
|
/* Increment record sequence number on retransmitted handshake
|
|
* messages */
|
|
c32to48(ssl->keys.dtls_sequence_number, dtls->sequence_number);
|
|
ssl->keys.dtls_sequence_number++;
|
|
}
|
|
else {
|
|
/* The Finished message is sent with the next epoch, keep its
|
|
* sequence number */
|
|
}
|
|
|
|
if ((ret = CheckAvailableSize(ssl, buf->length)) != 0)
|
|
return ret;
|
|
|
|
XMEMCPY(ssl->buffers.outputBuffer.buffer, buf->buffer, buf->length);
|
|
ssl->buffers.outputBuffer.idx = 0;
|
|
ssl->buffers.outputBuffer.length = buf->length;
|
|
|
|
sendResult = SendBuffered(ssl);
|
|
if (sendResult < 0) {
|
|
return sendResult;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* functions for managing DTLS datagram reordering */
|
|
|
|
/* Need to allocate space for the handshake message header. The hashing
|
|
* routines assume the message pointer is still within the buffer that
|
|
* has the headers, and will include those headers in the hash. The store
|
|
* routines need to take that into account as well. New will allocate
|
|
* extra space for the headers. */
|
|
DtlsMsg* DtlsMsgNew(word32 sz, void* heap)
|
|
{
|
|
DtlsMsg* msg = NULL;
|
|
|
|
msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG);
|
|
|
|
if (msg != NULL) {
|
|
msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ,
|
|
heap, DYNAMIC_TYPE_NONE);
|
|
if (msg->buf != NULL) {
|
|
msg->next = NULL;
|
|
msg->seq = 0;
|
|
msg->sz = sz;
|
|
msg->fragSz = 0;
|
|
msg->msg = msg->buf + DTLS_HANDSHAKE_HEADER_SZ;
|
|
}
|
|
else {
|
|
XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG);
|
|
msg = NULL;
|
|
}
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
void DtlsMsgDelete(DtlsMsg* item, void* heap)
|
|
{
|
|
(void)heap;
|
|
|
|
if (item != NULL) {
|
|
if (item->buf != NULL)
|
|
XFREE(item->buf, heap, DYNAMIC_TYPE_NONE);
|
|
XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG);
|
|
}
|
|
}
|
|
|
|
|
|
void DtlsMsgListDelete(DtlsMsg* head, void* heap)
|
|
{
|
|
DtlsMsg* next;
|
|
while (head) {
|
|
next = head->next;
|
|
DtlsMsgDelete(head, heap);
|
|
head = next;
|
|
}
|
|
}
|
|
|
|
|
|
void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type,
|
|
word32 fragOffset, word32 fragSz)
|
|
{
|
|
if (msg != NULL && data != NULL && msg->fragSz <= msg->sz &&
|
|
fragOffset < msg->sz && (fragOffset + fragSz) <= msg->sz) {
|
|
|
|
msg->seq = seq;
|
|
msg->type = type;
|
|
msg->fragSz += fragSz;
|
|
/* If fragOffset is zero, this is either a full message that is out
|
|
* of order, or the first fragment of a fragmented message. Copy the
|
|
* handshake message header as well as the message data. */
|
|
if (fragOffset == 0)
|
|
XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ,
|
|
fragSz + DTLS_HANDSHAKE_HEADER_SZ);
|
|
else {
|
|
/* If fragOffet is non-zero, this is an additional fragment that
|
|
* needs to be copied to its location in the message buffer. Also
|
|
* copy the total size of the message over the fragment size. The
|
|
* hash routines look at a defragmented message if it had actually
|
|
* come across as a single handshake message. */
|
|
XMEMCPY(msg->msg + fragOffset, data, fragSz);
|
|
c32to24(msg->sz, msg->msg - DTLS_HANDSHAKE_FRAG_SZ);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq)
|
|
{
|
|
while (head != NULL && head->seq != seq) {
|
|
head = head->next;
|
|
}
|
|
return head;
|
|
}
|
|
|
|
|
|
DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data,
|
|
word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap)
|
|
{
|
|
|
|
/* See if seq exists in the list. If it isn't in the list, make
|
|
* a new item of size dataSz, copy fragSz bytes from data to msg->msg
|
|
* starting at offset fragOffset, and add fragSz to msg->fragSz. If
|
|
* the seq is in the list and it isn't full, copy fragSz bytes from
|
|
* data to msg->msg starting at offset fragOffset, and add fragSz to
|
|
* msg->fragSz. The new item should be inserted into the list in its
|
|
* proper position.
|
|
*
|
|
* 1. Find seq in list, or where seq should go in list. If seq not in
|
|
* list, create new item and insert into list. Either case, keep
|
|
* pointer to item.
|
|
* 2. If msg->fragSz + fragSz < sz, copy data to msg->msg at offset
|
|
* fragOffset. Add fragSz to msg->fragSz.
|
|
*/
|
|
|
|
if (head != NULL) {
|
|
DtlsMsg* cur = DtlsMsgFind(head, seq);
|
|
if (cur == NULL) {
|
|
cur = DtlsMsgNew(dataSz, heap);
|
|
if (cur != NULL) {
|
|
DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
|
|
head = DtlsMsgInsert(head, cur);
|
|
}
|
|
}
|
|
else {
|
|
DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
|
|
}
|
|
}
|
|
else {
|
|
head = DtlsMsgNew(dataSz, heap);
|
|
DtlsMsgSet(head, seq, data, type, fragOffset, fragSz);
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
|
|
/* DtlsMsgInsert() is an in-order insert. */
|
|
DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item)
|
|
{
|
|
if (head == NULL || item->seq < head->seq) {
|
|
item->next = head;
|
|
head = item;
|
|
}
|
|
else if (head->next == NULL) {
|
|
head->next = item;
|
|
}
|
|
else {
|
|
DtlsMsg* cur = head->next;
|
|
DtlsMsg* prev = head;
|
|
while (cur) {
|
|
if (item->seq < cur->seq) {
|
|
item->next = cur;
|
|
prev->next = item;
|
|
break;
|
|
}
|
|
prev = cur;
|
|
cur = cur->next;
|
|
}
|
|
if (cur == NULL) {
|
|
prev->next = item;
|
|
}
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DTLS */
|
|
|
|
#ifndef NO_OLD_TLS
|
|
|
|
ProtocolVersion MakeSSLv3(void)
|
|
{
|
|
ProtocolVersion pv;
|
|
pv.major = SSLv3_MAJOR;
|
|
pv.minor = SSLv3_MINOR;
|
|
|
|
return pv;
|
|
}
|
|
|
|
#endif /* NO_OLD_TLS */
|
|
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
|
|
ProtocolVersion MakeDTLSv1(void)
|
|
{
|
|
ProtocolVersion pv;
|
|
pv.major = DTLS_MAJOR;
|
|
pv.minor = DTLS_MINOR;
|
|
|
|
return pv;
|
|
}
|
|
|
|
ProtocolVersion MakeDTLSv1_2(void)
|
|
{
|
|
ProtocolVersion pv;
|
|
pv.major = DTLS_MAJOR;
|
|
pv.minor = DTLSv1_2_MINOR;
|
|
|
|
return pv;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DTLS */
|
|
|
|
|
|
|
|
|
|
#ifdef USE_WINDOWS_API
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
static int init = 0;
|
|
static LARGE_INTEGER freq;
|
|
LARGE_INTEGER count;
|
|
|
|
if (!init) {
|
|
QueryPerformanceFrequency(&freq);
|
|
init = 1;
|
|
}
|
|
|
|
QueryPerformanceCounter(&count);
|
|
|
|
return (word32)(count.QuadPart / freq.QuadPart);
|
|
}
|
|
|
|
#elif defined(HAVE_RTP_SYS)
|
|
|
|
#include "rtptime.h"
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
return (word32)rtp_get_system_sec();
|
|
}
|
|
|
|
|
|
#elif defined(MICRIUM)
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
NET_SECURE_OS_TICK clk;
|
|
|
|
#if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
|
|
clk = NetSecure_OS_TimeGet();
|
|
#endif
|
|
return (word32)clk;
|
|
}
|
|
|
|
|
|
#elif defined(MICROCHIP_TCPIP_V5)
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
return (word32) TickGet();
|
|
}
|
|
|
|
|
|
#elif defined(MICROCHIP_TCPIP)
|
|
|
|
#if defined(MICROCHIP_MPLAB_HARMONY)
|
|
|
|
#include <system/tmr/sys_tmr.h>
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
return (word32) SYS_TMR_TickCountGet();
|
|
}
|
|
|
|
#else
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
return (word32) SYS_TICK_Get();
|
|
}
|
|
|
|
#endif
|
|
|
|
#elif defined(FREESCALE_MQX)
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
TIME_STRUCT mqxTime;
|
|
|
|
_time_get_elapsed(&mqxTime);
|
|
|
|
return (word32) mqxTime.SECONDS;
|
|
}
|
|
|
|
#elif defined(WOLFSSL_TIRTOS)
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
return (word32) MYTIME_gettime();
|
|
}
|
|
|
|
#elif defined(USER_TICKS)
|
|
#if 0
|
|
word32 LowResTimer(void)
|
|
{
|
|
/*
|
|
write your own clock tick function if don't want time(0)
|
|
needs second accuracy but doesn't have to correlated to EPOCH
|
|
*/
|
|
}
|
|
#endif
|
|
#else /* !USE_WINDOWS_API && !HAVE_RTP_SYS && !MICRIUM && !USER_TICKS */
|
|
|
|
#include <time.h>
|
|
|
|
word32 LowResTimer(void)
|
|
{
|
|
return (word32)time(0);
|
|
}
|
|
|
|
|
|
#endif /* USE_WINDOWS_API */
|
|
|
|
|
|
/* add output to md5 and sha handshake hashes, exclude record header */
|
|
static int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
|
|
{
|
|
const byte* adj = output + RECORD_HEADER_SZ + ivSz;
|
|
sz -= RECORD_HEADER_SZ;
|
|
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx);
|
|
#endif
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
adj += DTLS_RECORD_EXTRA;
|
|
sz -= DTLS_RECORD_EXTRA;
|
|
}
|
|
#endif
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_SHA
|
|
ShaUpdate(&ssl->hashSha, adj, sz);
|
|
#endif
|
|
#ifndef NO_MD5
|
|
Md5Update(&ssl->hashMd5, adj, sz);
|
|
#endif
|
|
#endif
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
int ret;
|
|
|
|
#ifndef NO_SHA256
|
|
ret = Sha256Update(&ssl->hashSha256, adj, sz);
|
|
if (ret != 0)
|
|
return ret;
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
ret = Sha384Update(&ssl->hashSha384, adj, sz);
|
|
if (ret != 0)
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* add input to md5 and sha handshake hashes, include handshake header */
|
|
static int HashInput(WOLFSSL* ssl, const byte* input, int sz)
|
|
{
|
|
const byte* adj = input - HANDSHAKE_HEADER_SZ;
|
|
sz += HANDSHAKE_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
adj -= DTLS_HANDSHAKE_EXTRA;
|
|
sz += DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_SHA
|
|
ShaUpdate(&ssl->hashSha, adj, sz);
|
|
#endif
|
|
#ifndef NO_MD5
|
|
Md5Update(&ssl->hashMd5, adj, sz);
|
|
#endif
|
|
#endif
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
int ret;
|
|
|
|
#ifndef NO_SHA256
|
|
ret = Sha256Update(&ssl->hashSha256, adj, sz);
|
|
if (ret != 0)
|
|
return ret;
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
ret = Sha384Update(&ssl->hashSha384, adj, sz);
|
|
if (ret != 0)
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* add record layer header for message */
|
|
static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl)
|
|
{
|
|
RecordLayerHeader* rl;
|
|
|
|
/* record layer header */
|
|
rl = (RecordLayerHeader*)output;
|
|
rl->type = type;
|
|
rl->pvMajor = ssl->version.major; /* type and version same in each */
|
|
rl->pvMinor = ssl->version.minor;
|
|
|
|
if (!ssl->options.dtls)
|
|
c16toa((word16)length, rl->length);
|
|
else {
|
|
#ifdef WOLFSSL_DTLS
|
|
DtlsRecordLayerHeader* dtls;
|
|
|
|
/* dtls record layer header extensions */
|
|
dtls = (DtlsRecordLayerHeader*)output;
|
|
c16toa(ssl->keys.dtls_epoch, dtls->epoch);
|
|
c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number);
|
|
c16toa((word16)length, dtls->length);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/* add handshake header for message */
|
|
static void AddHandShakeHeader(byte* output, word32 length, byte type,
|
|
WOLFSSL* ssl)
|
|
{
|
|
HandShakeHeader* hs;
|
|
(void)ssl;
|
|
|
|
/* handshake header */
|
|
hs = (HandShakeHeader*)output;
|
|
hs->type = type;
|
|
c32to24(length, hs->length); /* type and length same for each */
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
DtlsHandShakeHeader* dtls;
|
|
|
|
/* dtls handshake header extensions */
|
|
dtls = (DtlsHandShakeHeader*)output;
|
|
c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq);
|
|
c32to24(0, dtls->fragment_offset);
|
|
c32to24(length, dtls->fragment_length);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* add both headers for handshake message */
|
|
static void AddHeaders(byte* output, word32 length, byte type, WOLFSSL* ssl)
|
|
{
|
|
if (!ssl->options.dtls) {
|
|
AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl);
|
|
AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl);
|
|
}
|
|
#ifdef WOLFSSL_DTLS
|
|
else {
|
|
AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl);
|
|
AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* return bytes received, -1 on error */
|
|
static int Receive(WOLFSSL* ssl, byte* buf, word32 sz)
|
|
{
|
|
int recvd;
|
|
|
|
if (ssl->ctx->CBIORecv == NULL) {
|
|
WOLFSSL_MSG("Your IO Recv callback is null, please set");
|
|
return -1;
|
|
}
|
|
|
|
retry:
|
|
recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx);
|
|
if (recvd < 0)
|
|
switch (recvd) {
|
|
case WOLFSSL_CBIO_ERR_GENERAL: /* general/unknown error */
|
|
return -1;
|
|
|
|
case WOLFSSL_CBIO_ERR_WANT_READ: /* want read, would block */
|
|
return WANT_READ;
|
|
|
|
case WOLFSSL_CBIO_ERR_CONN_RST: /* connection reset */
|
|
#ifdef USE_WINDOWS_API
|
|
if (ssl->options.dtls) {
|
|
goto retry;
|
|
}
|
|
#endif
|
|
ssl->options.connReset = 1;
|
|
return -1;
|
|
|
|
case WOLFSSL_CBIO_ERR_ISR: /* interrupt */
|
|
/* see if we got our timeout */
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->toInfoOn) {
|
|
struct itimerval timeout;
|
|
getitimer(ITIMER_REAL, &timeout);
|
|
if (timeout.it_value.tv_sec == 0 &&
|
|
timeout.it_value.tv_usec == 0) {
|
|
XSTRNCPY(ssl->timeoutInfo.timeoutName,
|
|
"recv() timeout", MAX_TIMEOUT_NAME_SZ);
|
|
WOLFSSL_MSG("Got our timeout");
|
|
return WANT_READ;
|
|
}
|
|
}
|
|
#endif
|
|
goto retry;
|
|
|
|
case WOLFSSL_CBIO_ERR_CONN_CLOSE: /* peer closed connection */
|
|
ssl->options.isClosed = 1;
|
|
return -1;
|
|
|
|
case WOLFSSL_CBIO_ERR_TIMEOUT:
|
|
#ifdef WOLFSSL_DTLS
|
|
if (DtlsPoolTimeout(ssl) == 0 && DtlsPoolSend(ssl) == 0)
|
|
goto retry;
|
|
else
|
|
#endif
|
|
return -1;
|
|
|
|
default:
|
|
return recvd;
|
|
}
|
|
|
|
return recvd;
|
|
}
|
|
|
|
|
|
/* Switch dynamic output buffer back to static, buffer is assumed clear */
|
|
void ShrinkOutputBuffer(WOLFSSL* ssl)
|
|
{
|
|
WOLFSSL_MSG("Shrinking output buffer\n");
|
|
XFREE(ssl->buffers.outputBuffer.buffer - ssl->buffers.outputBuffer.offset,
|
|
ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
|
|
ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
|
|
ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN;
|
|
ssl->buffers.outputBuffer.dynamicFlag = 0;
|
|
ssl->buffers.outputBuffer.offset = 0;
|
|
}
|
|
|
|
|
|
/* Switch dynamic input buffer back to static, keep any remaining input */
|
|
/* forced free means cleaning up */
|
|
void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree)
|
|
{
|
|
int usedLength = ssl->buffers.inputBuffer.length -
|
|
ssl->buffers.inputBuffer.idx;
|
|
if (!forcedFree && usedLength > STATIC_BUFFER_LEN)
|
|
return;
|
|
|
|
WOLFSSL_MSG("Shrinking input buffer\n");
|
|
|
|
if (!forcedFree && usedLength)
|
|
XMEMCPY(ssl->buffers.inputBuffer.staticBuffer,
|
|
ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
|
|
usedLength);
|
|
|
|
XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset,
|
|
ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
|
|
ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
|
|
ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN;
|
|
ssl->buffers.inputBuffer.dynamicFlag = 0;
|
|
ssl->buffers.inputBuffer.offset = 0;
|
|
ssl->buffers.inputBuffer.idx = 0;
|
|
ssl->buffers.inputBuffer.length = usedLength;
|
|
}
|
|
|
|
|
|
int SendBuffered(WOLFSSL* ssl)
|
|
{
|
|
if (ssl->ctx->CBIOSend == NULL) {
|
|
WOLFSSL_MSG("Your IO Send callback is null, please set");
|
|
return SOCKET_ERROR_E;
|
|
}
|
|
|
|
while (ssl->buffers.outputBuffer.length > 0) {
|
|
int sent = ssl->ctx->CBIOSend(ssl,
|
|
(char*)ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.idx,
|
|
(int)ssl->buffers.outputBuffer.length,
|
|
ssl->IOCB_WriteCtx);
|
|
if (sent < 0) {
|
|
switch (sent) {
|
|
|
|
case WOLFSSL_CBIO_ERR_WANT_WRITE: /* would block */
|
|
return WANT_WRITE;
|
|
|
|
case WOLFSSL_CBIO_ERR_CONN_RST: /* connection reset */
|
|
ssl->options.connReset = 1;
|
|
break;
|
|
|
|
case WOLFSSL_CBIO_ERR_ISR: /* interrupt */
|
|
/* see if we got our timeout */
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->toInfoOn) {
|
|
struct itimerval timeout;
|
|
getitimer(ITIMER_REAL, &timeout);
|
|
if (timeout.it_value.tv_sec == 0 &&
|
|
timeout.it_value.tv_usec == 0) {
|
|
XSTRNCPY(ssl->timeoutInfo.timeoutName,
|
|
"send() timeout", MAX_TIMEOUT_NAME_SZ);
|
|
WOLFSSL_MSG("Got our timeout");
|
|
return WANT_WRITE;
|
|
}
|
|
}
|
|
#endif
|
|
continue;
|
|
|
|
case WOLFSSL_CBIO_ERR_CONN_CLOSE: /* epipe / conn closed */
|
|
ssl->options.connReset = 1; /* treat same as reset */
|
|
break;
|
|
|
|
default:
|
|
return SOCKET_ERROR_E;
|
|
}
|
|
|
|
return SOCKET_ERROR_E;
|
|
}
|
|
|
|
if (sent > (int)ssl->buffers.outputBuffer.length) {
|
|
WOLFSSL_MSG("SendBuffered() out of bounds read");
|
|
return SEND_OOB_READ_E;
|
|
}
|
|
|
|
ssl->buffers.outputBuffer.idx += sent;
|
|
ssl->buffers.outputBuffer.length -= sent;
|
|
}
|
|
|
|
ssl->buffers.outputBuffer.idx = 0;
|
|
|
|
if (ssl->buffers.outputBuffer.dynamicFlag)
|
|
ShrinkOutputBuffer(ssl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Grow the output buffer */
|
|
static INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size)
|
|
{
|
|
byte* tmp;
|
|
byte hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ :
|
|
RECORD_HEADER_SZ;
|
|
byte align = WOLFSSL_GENERAL_ALIGNMENT;
|
|
/* the encrypted data will be offset from the front of the buffer by
|
|
the header, if the user wants encrypted alignment they need
|
|
to define their alignment requirement */
|
|
|
|
if (align) {
|
|
while (align < hdrSz)
|
|
align *= 2;
|
|
}
|
|
|
|
tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length + align,
|
|
ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
|
|
WOLFSSL_MSG("growing output buffer\n");
|
|
|
|
if (!tmp) return MEMORY_E;
|
|
if (align)
|
|
tmp += align - hdrSz;
|
|
|
|
if (ssl->buffers.outputBuffer.length)
|
|
XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer,
|
|
ssl->buffers.outputBuffer.length);
|
|
|
|
if (ssl->buffers.outputBuffer.dynamicFlag)
|
|
XFREE(ssl->buffers.outputBuffer.buffer -
|
|
ssl->buffers.outputBuffer.offset, ssl->heap,
|
|
DYNAMIC_TYPE_OUT_BUFFER);
|
|
ssl->buffers.outputBuffer.dynamicFlag = 1;
|
|
if (align)
|
|
ssl->buffers.outputBuffer.offset = align - hdrSz;
|
|
else
|
|
ssl->buffers.outputBuffer.offset = 0;
|
|
ssl->buffers.outputBuffer.buffer = tmp;
|
|
ssl->buffers.outputBuffer.bufferSize = size +
|
|
ssl->buffers.outputBuffer.length;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Grow the input buffer, should only be to read cert or big app data */
|
|
int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength)
|
|
{
|
|
byte* tmp;
|
|
byte hdrSz = DTLS_RECORD_HEADER_SZ;
|
|
byte align = ssl->options.dtls ? WOLFSSL_GENERAL_ALIGNMENT : 0;
|
|
/* the encrypted data will be offset from the front of the buffer by
|
|
the dtls record header, if the user wants encrypted alignment they need
|
|
to define their alignment requirement. in tls we read record header
|
|
to get size of record and put actual data back at front, so don't need */
|
|
|
|
if (align) {
|
|
while (align < hdrSz)
|
|
align *= 2;
|
|
}
|
|
tmp = (byte*) XMALLOC(size + usedLength + align, ssl->heap,
|
|
DYNAMIC_TYPE_IN_BUFFER);
|
|
WOLFSSL_MSG("growing input buffer\n");
|
|
|
|
if (!tmp) return MEMORY_E;
|
|
if (align)
|
|
tmp += align - hdrSz;
|
|
|
|
if (usedLength)
|
|
XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx, usedLength);
|
|
|
|
if (ssl->buffers.inputBuffer.dynamicFlag)
|
|
XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset,
|
|
ssl->heap,DYNAMIC_TYPE_IN_BUFFER);
|
|
|
|
ssl->buffers.inputBuffer.dynamicFlag = 1;
|
|
if (align)
|
|
ssl->buffers.inputBuffer.offset = align - hdrSz;
|
|
else
|
|
ssl->buffers.inputBuffer.offset = 0;
|
|
ssl->buffers.inputBuffer.buffer = tmp;
|
|
ssl->buffers.inputBuffer.bufferSize = size + usedLength;
|
|
ssl->buffers.inputBuffer.idx = 0;
|
|
ssl->buffers.inputBuffer.length = usedLength;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* check available size into output buffer, make room if needed */
|
|
int CheckAvailableSize(WOLFSSL *ssl, int size)
|
|
{
|
|
|
|
if (size < 0) {
|
|
WOLFSSL_MSG("CheckAvailableSize() called with negative number");
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length
|
|
< (word32)size) {
|
|
if (GrowOutputBuffer(ssl, size) < 0)
|
|
return MEMORY_E;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* do all verify and sanity checks on record header */
|
|
static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|
RecordLayerHeader* rh, word16 *size)
|
|
{
|
|
if (!ssl->options.dtls) {
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, input + *inOutIdx, RECORD_HEADER_SZ, FUZZ_HEAD,
|
|
ssl->fuzzerCtx);
|
|
#endif
|
|
XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ);
|
|
*inOutIdx += RECORD_HEADER_SZ;
|
|
ato16(rh->length, size);
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_DTLS
|
|
/* type and version in same sport */
|
|
XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ);
|
|
*inOutIdx += ENUM_LEN + VERSION_SZ;
|
|
ato16(input + *inOutIdx, &ssl->keys.dtls_state.curEpoch);
|
|
*inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */
|
|
ato32(input + *inOutIdx, &ssl->keys.dtls_state.curSeq);
|
|
*inOutIdx += 4; /* advance past rest of seq */
|
|
ato16(input + *inOutIdx, size);
|
|
*inOutIdx += LENGTH_SZ;
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, input + *inOutIdx - LENGTH_SZ - 8 - ENUM_LEN -
|
|
VERSION_SZ, ENUM_LEN + VERSION_SZ + 8 + LENGTH_SZ,
|
|
FUZZ_HEAD, ssl->fuzzerCtx);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/* catch version mismatch */
|
|
if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){
|
|
if (ssl->options.side == WOLFSSL_SERVER_END &&
|
|
ssl->options.acceptState == ACCEPT_BEGIN)
|
|
WOLFSSL_MSG("Client attempting to connect with different version");
|
|
else if (ssl->options.side == WOLFSSL_CLIENT_END &&
|
|
ssl->options.downgrade &&
|
|
ssl->options.connectState < FIRST_REPLY_DONE)
|
|
WOLFSSL_MSG("Server attempting to accept with different version");
|
|
else {
|
|
WOLFSSL_MSG("SSL version error");
|
|
return VERSION_ERROR; /* only use requested version */
|
|
}
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if (DtlsCheckWindow(&ssl->keys.dtls_state) != 1)
|
|
return SEQUENCE_ERROR;
|
|
}
|
|
#endif
|
|
|
|
/* record layer length check */
|
|
#ifdef HAVE_MAX_FRAGMENT
|
|
if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) {
|
|
SendAlert(ssl, alert_fatal, record_overflow);
|
|
return LENGTH_ERROR;
|
|
}
|
|
#else
|
|
if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
|
|
return LENGTH_ERROR;
|
|
#endif
|
|
|
|
/* verify record type here as well */
|
|
switch (rh->type) {
|
|
case handshake:
|
|
case change_cipher_spec:
|
|
case application_data:
|
|
case alert:
|
|
break;
|
|
case no_type:
|
|
default:
|
|
WOLFSSL_MSG("Unknown Record Type");
|
|
return UNKNOWN_RECORD_TYPE;
|
|
}
|
|
|
|
/* haven't decrypted this record yet */
|
|
ssl->keys.decryptedCur = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int GetHandShakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|
byte *type, word32 *size, word32 totalSz)
|
|
{
|
|
const byte *ptr = input + *inOutIdx;
|
|
(void)ssl;
|
|
|
|
*inOutIdx += HANDSHAKE_HEADER_SZ;
|
|
if (*inOutIdx > totalSz)
|
|
return BUFFER_E;
|
|
|
|
*type = ptr[0];
|
|
c24to32(&ptr[1], size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input,
|
|
word32* inOutIdx, byte *type, word32 *size,
|
|
word32 *fragOffset, word32 *fragSz,
|
|
word32 totalSz)
|
|
{
|
|
word32 idx = *inOutIdx;
|
|
|
|
*inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA;
|
|
if (*inOutIdx > totalSz)
|
|
return BUFFER_E;
|
|
|
|
*type = input[idx++];
|
|
c24to32(input + idx, size);
|
|
idx += BYTE3_LEN;
|
|
|
|
ato16(input + idx, &ssl->keys.dtls_peer_handshake_number);
|
|
idx += DTLS_HANDSHAKE_SEQ_SZ;
|
|
|
|
c24to32(input + idx, fragOffset);
|
|
idx += DTLS_HANDSHAKE_FRAG_SZ;
|
|
c24to32(input + idx, fragSz);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifndef NO_OLD_TLS
|
|
/* fill with MD5 pad size since biggest required */
|
|
static const byte PAD1[PAD_MD5] =
|
|
{ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
|
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
|
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
|
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
|
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
|
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
|
|
};
|
|
static const byte PAD2[PAD_MD5] =
|
|
{ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
|
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
|
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
|
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
|
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
|
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
|
|
};
|
|
|
|
/* calculate MD5 hash for finished */
|
|
static void BuildMD5(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
|
|
{
|
|
byte md5_result[MD5_DIGEST_SIZE];
|
|
|
|
/* make md5 inner */
|
|
Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER);
|
|
Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
|
|
Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
|
|
Md5Final(&ssl->hashMd5, md5_result);
|
|
|
|
/* make md5 outer */
|
|
Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
|
|
Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
|
|
Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
|
|
|
|
Md5Final(&ssl->hashMd5, hashes->md5);
|
|
}
|
|
|
|
|
|
/* calculate SHA hash for finished */
|
|
static void BuildSHA(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
|
|
{
|
|
byte sha_result[SHA_DIGEST_SIZE];
|
|
|
|
/* make sha inner */
|
|
ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER);
|
|
ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
|
|
ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
|
|
ShaFinal(&ssl->hashSha, sha_result);
|
|
|
|
/* make sha outer */
|
|
ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
|
|
ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
|
|
ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
|
|
|
|
ShaFinal(&ssl->hashSha, hashes->sha);
|
|
}
|
|
#endif
|
|
|
|
|
|
static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
|
|
{
|
|
int ret = 0;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
Md5* md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifndef NO_SHA
|
|
Sha* sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
Sha256* sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
Sha384* sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#else
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
Md5 md5[1];
|
|
#endif
|
|
#ifndef NO_SHA
|
|
Sha sha[1];
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
Sha256 sha256[1];
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
Sha384 sha384[1];
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
if (ssl == NULL
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
|| md5 == NULL
|
|
#endif
|
|
#ifndef NO_SHA
|
|
|| sha == NULL
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
|| sha256 == NULL
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
|| sha384 == NULL
|
|
#endif
|
|
) {
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifndef NO_SHA
|
|
XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return MEMORY_E;
|
|
}
|
|
#endif
|
|
|
|
/* store current states, building requires get_digest which resets state */
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
md5[0] = ssl->hashMd5;
|
|
#endif
|
|
#ifndef NO_SHA
|
|
sha[0] = ssl->hashSha;
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
sha256[0] = ssl->hashSha256;
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
sha384[0] = ssl->hashSha384;
|
|
#endif
|
|
|
|
#ifndef NO_TLS
|
|
if (ssl->options.tls) {
|
|
ret = BuildTlsFinished(ssl, hashes, sender);
|
|
}
|
|
#endif
|
|
#ifndef NO_OLD_TLS
|
|
if (!ssl->options.tls) {
|
|
BuildMD5(ssl, hashes, sender);
|
|
BuildSHA(ssl, hashes, sender);
|
|
}
|
|
#endif
|
|
|
|
/* restore */
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
ssl->hashMd5 = md5[0];
|
|
#endif
|
|
#ifndef NO_SHA
|
|
ssl->hashSha = sha[0];
|
|
#endif
|
|
#endif
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
#ifndef NO_SHA256
|
|
ssl->hashSha256 = sha256[0];
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
ssl->hashSha384 = sha384[0];
|
|
#endif
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifndef NO_SHA
|
|
XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* cipher requirements */
|
|
enum {
|
|
REQUIRES_RSA,
|
|
REQUIRES_DHE,
|
|
REQUIRES_ECC_DSA,
|
|
REQUIRES_ECC_STATIC,
|
|
REQUIRES_PSK,
|
|
REQUIRES_NTRU,
|
|
REQUIRES_RSA_SIG
|
|
};
|
|
|
|
|
|
|
|
/* Does this cipher suite (first, second) have the requirement
|
|
an ephemeral key exchange will still require the key for signing
|
|
the key exchange so ECHDE_RSA requires an rsa key thus rsa_kea */
|
|
static int CipherRequires(byte first, byte second, int requirement)
|
|
{
|
|
|
|
if (first == CHACHA_BYTE) {
|
|
|
|
switch (second) {
|
|
|
|
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ECC extensions */
|
|
if (first == ECC_BYTE) {
|
|
|
|
switch (second) {
|
|
|
|
#ifndef NO_RSA
|
|
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
|
|
#ifndef NO_DES3
|
|
case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_RC4
|
|
case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_RC4_128_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
#endif /* NO_RSA */
|
|
|
|
#ifndef NO_DES3
|
|
case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
#ifndef NO_RC4
|
|
case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
#ifndef NO_RSA
|
|
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
|
|
#ifndef NO_RSA
|
|
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 :
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_128_CCM_8 :
|
|
case TLS_RSA_WITH_AES_256_CCM_8 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
|
|
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
|
|
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 :
|
|
case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
|
|
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
|
|
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
|
|
if (requirement == REQUIRES_ECC_DSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_ECC_STATIC)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_PSK_WITH_AES_128_CCM:
|
|
case TLS_PSK_WITH_AES_256_CCM:
|
|
case TLS_PSK_WITH_AES_128_CCM_8:
|
|
case TLS_PSK_WITH_AES_256_CCM_8:
|
|
if (requirement == REQUIRES_PSK)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_PSK_WITH_AES_128_CCM:
|
|
case TLS_DHE_PSK_WITH_AES_256_CCM:
|
|
if (requirement == REQUIRES_PSK)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
|
|
default:
|
|
WOLFSSL_MSG("Unsupported cipher suite, CipherRequires ECC");
|
|
return 0;
|
|
} /* switch */
|
|
} /* if */
|
|
if (first != ECC_BYTE) { /* normal suites */
|
|
switch (second) {
|
|
|
|
#ifndef NO_RSA
|
|
case SSL_RSA_WITH_RC4_128_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_NTRU_RSA_WITH_RC4_128_SHA :
|
|
if (requirement == REQUIRES_NTRU)
|
|
return 1;
|
|
break;
|
|
|
|
case SSL_RSA_WITH_RC4_128_MD5 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
|
|
if (requirement == REQUIRES_NTRU)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_128_CBC_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_NTRU)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_256_CBC_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_NULL_SHA :
|
|
case TLS_RSA_WITH_NULL_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_NTRU)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
|
|
case TLS_PSK_WITH_AES_128_GCM_SHA256 :
|
|
case TLS_PSK_WITH_AES_256_GCM_SHA384 :
|
|
case TLS_PSK_WITH_AES_128_CBC_SHA256 :
|
|
case TLS_PSK_WITH_AES_256_CBC_SHA384 :
|
|
case TLS_PSK_WITH_AES_128_CBC_SHA :
|
|
case TLS_PSK_WITH_AES_256_CBC_SHA :
|
|
case TLS_PSK_WITH_NULL_SHA384 :
|
|
case TLS_PSK_WITH_NULL_SHA256 :
|
|
case TLS_PSK_WITH_NULL_SHA :
|
|
if (requirement == REQUIRES_PSK)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 :
|
|
case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 :
|
|
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
|
|
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
|
|
case TLS_DHE_PSK_WITH_NULL_SHA384 :
|
|
case TLS_DHE_PSK_WITH_NULL_SHA256 :
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
if (requirement == REQUIRES_PSK)
|
|
return 1;
|
|
break;
|
|
|
|
#ifndef NO_RSA
|
|
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_HC_128_MD5 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_HC_128_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_HC_128_B2B256:
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_128_CBC_B2B256:
|
|
case TLS_RSA_WITH_AES_256_CBC_B2B256:
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_RABBIT_SHA :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_AES_128_GCM_SHA256 :
|
|
case TLS_RSA_WITH_AES_256_GCM_SHA384 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
|
|
case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
|
|
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
|
|
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
|
|
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
break;
|
|
|
|
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA :
|
|
case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA :
|
|
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
|
|
case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
|
|
if (requirement == REQUIRES_RSA)
|
|
return 1;
|
|
if (requirement == REQUIRES_RSA_SIG)
|
|
return 1;
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
#ifdef HAVE_ANON
|
|
case TLS_DH_anon_WITH_AES_128_CBC_SHA :
|
|
if (requirement == REQUIRES_DHE)
|
|
return 1;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
WOLFSSL_MSG("Unsupported cipher suite, CipherRequires");
|
|
return 0;
|
|
} /* switch */
|
|
} /* if ECC / Normal suites else */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifndef NO_CERTS
|
|
|
|
|
|
/* Match names with wildcards, each wildcard can represent a single name
|
|
component or fragment but not mulitple names, i.e.,
|
|
*.z.com matches y.z.com but not x.y.z.com
|
|
|
|
return 1 on success */
|
|
static int MatchDomainName(const char* pattern, int len, const char* str)
|
|
{
|
|
char p, s;
|
|
|
|
if (pattern == NULL || str == NULL || len <= 0)
|
|
return 0;
|
|
|
|
while (len > 0) {
|
|
|
|
p = (char)XTOLOWER(*pattern++);
|
|
if (p == 0)
|
|
break;
|
|
|
|
if (p == '*') {
|
|
while (--len > 0 && (p = (char)XTOLOWER(*pattern++)) == '*')
|
|
;
|
|
|
|
if (len == 0)
|
|
p = '\0';
|
|
|
|
while ( (s = (char)XTOLOWER(*str)) != '\0') {
|
|
if (s == p)
|
|
break;
|
|
if (s == '.')
|
|
return 0;
|
|
str++;
|
|
}
|
|
}
|
|
else {
|
|
if (p != (char)XTOLOWER(*str))
|
|
return 0;
|
|
}
|
|
|
|
if (*str != '\0')
|
|
str++;
|
|
|
|
if (len > 0)
|
|
len--;
|
|
}
|
|
|
|
return *str == '\0';
|
|
}
|
|
|
|
|
|
/* try to find an altName match to domain, return 1 on success */
|
|
static int CheckAltNames(DecodedCert* dCert, char* domain)
|
|
{
|
|
int match = 0;
|
|
DNS_entry* altName = NULL;
|
|
|
|
WOLFSSL_MSG("Checking AltNames");
|
|
|
|
if (dCert)
|
|
altName = dCert->altNames;
|
|
|
|
while (altName) {
|
|
WOLFSSL_MSG(" individual AltName check");
|
|
|
|
if (MatchDomainName(altName->name,(int)XSTRLEN(altName->name), domain)){
|
|
match = 1;
|
|
break;
|
|
}
|
|
|
|
altName = altName->next;
|
|
}
|
|
|
|
return match;
|
|
}
|
|
|
|
|
|
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
|
|
|
|
/* Copy parts X509 needs from Decoded cert, 0 on success */
|
|
int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (x509 == NULL || dCert == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
x509->version = dCert->version + 1;
|
|
|
|
XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX);
|
|
x509->issuer.name[ASN_NAME_MAX - 1] = '\0';
|
|
x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1;
|
|
#ifdef OPENSSL_EXTRA
|
|
if (dCert->issuerName.fullName != NULL) {
|
|
XMEMCPY(&x509->issuer.fullName,
|
|
&dCert->issuerName, sizeof(DecodedName));
|
|
x509->issuer.fullName.fullName = (char*)XMALLOC(
|
|
dCert->issuerName.fullNameLen, NULL, DYNAMIC_TYPE_X509);
|
|
if (x509->issuer.fullName.fullName != NULL)
|
|
XMEMCPY(x509->issuer.fullName.fullName,
|
|
dCert->issuerName.fullName, dCert->issuerName.fullNameLen);
|
|
}
|
|
#endif /* OPENSSL_EXTRA */
|
|
|
|
XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX);
|
|
x509->subject.name[ASN_NAME_MAX - 1] = '\0';
|
|
x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1;
|
|
#ifdef OPENSSL_EXTRA
|
|
if (dCert->subjectName.fullName != NULL) {
|
|
XMEMCPY(&x509->subject.fullName,
|
|
&dCert->subjectName, sizeof(DecodedName));
|
|
x509->subject.fullName.fullName = (char*)XMALLOC(
|
|
dCert->subjectName.fullNameLen, NULL, DYNAMIC_TYPE_X509);
|
|
if (x509->subject.fullName.fullName != NULL)
|
|
XMEMCPY(x509->subject.fullName.fullName,
|
|
dCert->subjectName.fullName, dCert->subjectName.fullNameLen);
|
|
}
|
|
#endif /* OPENSSL_EXTRA */
|
|
|
|
XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE);
|
|
x509->serialSz = dCert->serialSz;
|
|
if (dCert->subjectCNLen < ASN_NAME_MAX) {
|
|
XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen);
|
|
x509->subjectCN[dCert->subjectCNLen] = '\0';
|
|
}
|
|
else
|
|
x509->subjectCN[0] = '\0';
|
|
|
|
#ifdef WOLFSSL_SEP
|
|
{
|
|
int minSz = min(dCert->deviceTypeSz, EXTERNAL_SERIAL_SIZE);
|
|
if (minSz > 0) {
|
|
x509->deviceTypeSz = minSz;
|
|
XMEMCPY(x509->deviceType, dCert->deviceType, minSz);
|
|
}
|
|
else
|
|
x509->deviceTypeSz = 0;
|
|
minSz = min(dCert->hwTypeSz, EXTERNAL_SERIAL_SIZE);
|
|
if (minSz != 0) {
|
|
x509->hwTypeSz = minSz;
|
|
XMEMCPY(x509->hwType, dCert->hwType, minSz);
|
|
}
|
|
else
|
|
x509->hwTypeSz = 0;
|
|
minSz = min(dCert->hwSerialNumSz, EXTERNAL_SERIAL_SIZE);
|
|
if (minSz != 0) {
|
|
x509->hwSerialNumSz = minSz;
|
|
XMEMCPY(x509->hwSerialNum, dCert->hwSerialNum, minSz);
|
|
}
|
|
else
|
|
x509->hwSerialNumSz = 0;
|
|
}
|
|
#endif /* WOLFSSL_SEP */
|
|
{
|
|
int minSz = min(dCert->beforeDateLen, MAX_DATE_SZ);
|
|
if (minSz != 0) {
|
|
x509->notBeforeSz = minSz;
|
|
XMEMCPY(x509->notBefore, dCert->beforeDate, minSz);
|
|
}
|
|
else
|
|
x509->notBeforeSz = 0;
|
|
minSz = min(dCert->afterDateLen, MAX_DATE_SZ);
|
|
if (minSz != 0) {
|
|
x509->notAfterSz = minSz;
|
|
XMEMCPY(x509->notAfter, dCert->afterDate, minSz);
|
|
}
|
|
else
|
|
x509->notAfterSz = 0;
|
|
}
|
|
|
|
if (dCert->publicKey != NULL && dCert->pubKeySize != 0) {
|
|
x509->pubKey.buffer = (byte*)XMALLOC(
|
|
dCert->pubKeySize, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
if (x509->pubKey.buffer != NULL) {
|
|
x509->pubKeyOID = dCert->keyOID;
|
|
x509->pubKey.length = dCert->pubKeySize;
|
|
XMEMCPY(x509->pubKey.buffer, dCert->publicKey, dCert->pubKeySize);
|
|
}
|
|
else
|
|
ret = MEMORY_E;
|
|
}
|
|
|
|
if (dCert->signature != NULL && dCert->sigLength != 0) {
|
|
x509->sig.buffer = (byte*)XMALLOC(
|
|
dCert->sigLength, NULL, DYNAMIC_TYPE_SIGNATURE);
|
|
if (x509->sig.buffer == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMCPY(x509->sig.buffer, dCert->signature, dCert->sigLength);
|
|
x509->sig.length = dCert->sigLength;
|
|
x509->sigOID = dCert->signatureOID;
|
|
}
|
|
}
|
|
|
|
/* store cert for potential retrieval */
|
|
x509->derCert.buffer = (byte*)XMALLOC(dCert->maxIdx, NULL,
|
|
DYNAMIC_TYPE_CERT);
|
|
if (x509->derCert.buffer == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMCPY(x509->derCert.buffer, dCert->source, dCert->maxIdx);
|
|
x509->derCert.length = dCert->maxIdx;
|
|
}
|
|
|
|
x509->altNames = dCert->altNames;
|
|
dCert->altNames = NULL; /* takes ownership */
|
|
x509->altNamesNext = x509->altNames; /* index hint */
|
|
|
|
x509->isCa = dCert->isCA;
|
|
#ifdef OPENSSL_EXTRA
|
|
x509->pathLength = dCert->pathLength;
|
|
x509->keyUsage = dCert->extKeyUsage;
|
|
|
|
x509->basicConstSet = dCert->extBasicConstSet;
|
|
x509->basicConstCrit = dCert->extBasicConstCrit;
|
|
x509->basicConstPlSet = dCert->extBasicConstPlSet;
|
|
x509->subjAltNameSet = dCert->extSubjAltNameSet;
|
|
x509->subjAltNameCrit = dCert->extSubjAltNameCrit;
|
|
x509->authKeyIdSet = dCert->extAuthKeyIdSet;
|
|
x509->authKeyIdCrit = dCert->extAuthKeyIdCrit;
|
|
if (dCert->extAuthKeyIdSrc != NULL && dCert->extAuthKeyIdSz != 0) {
|
|
x509->authKeyId = (byte*)XMALLOC(dCert->extAuthKeyIdSz, NULL, 0);
|
|
if (x509->authKeyId != NULL) {
|
|
XMEMCPY(x509->authKeyId,
|
|
dCert->extAuthKeyIdSrc, dCert->extAuthKeyIdSz);
|
|
x509->authKeyIdSz = dCert->extAuthKeyIdSz;
|
|
}
|
|
else
|
|
ret = MEMORY_E;
|
|
}
|
|
x509->subjKeyIdSet = dCert->extSubjKeyIdSet;
|
|
x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit;
|
|
if (dCert->extSubjKeyIdSrc != NULL && dCert->extSubjKeyIdSz != 0) {
|
|
x509->subjKeyId = (byte*)XMALLOC(dCert->extSubjKeyIdSz, NULL, 0);
|
|
if (x509->subjKeyId != NULL) {
|
|
XMEMCPY(x509->subjKeyId,
|
|
dCert->extSubjKeyIdSrc, dCert->extSubjKeyIdSz);
|
|
x509->subjKeyIdSz = dCert->extSubjKeyIdSz;
|
|
}
|
|
else
|
|
ret = MEMORY_E;
|
|
}
|
|
x509->keyUsageSet = dCert->extKeyUsageSet;
|
|
x509->keyUsageCrit = dCert->extKeyUsageCrit;
|
|
#ifdef WOLFSSL_SEP
|
|
x509->certPolicySet = dCert->extCertPolicySet;
|
|
x509->certPolicyCrit = dCert->extCertPolicyCrit;
|
|
#endif /* WOLFSSL_SEP */
|
|
#endif /* OPENSSL_EXTRA */
|
|
#ifdef HAVE_ECC
|
|
x509->pkCurveOID = dCert->pkCurveOID;
|
|
#endif /* HAVE_ECC */
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* KEEP_PEER_CERT || SESSION_CERTS */
|
|
|
|
|
|
static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
|
word32 size)
|
|
{
|
|
word32 listSz;
|
|
word32 begin = *inOutIdx;
|
|
int ret = 0;
|
|
int anyError = 0;
|
|
int totalCerts = 0; /* number of certs in certs buffer */
|
|
int count;
|
|
buffer certs[MAX_CHAIN_DEPTH];
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
char* domain = NULL;
|
|
DecodedCert* dCert = NULL;
|
|
WOLFSSL_X509_STORE_CTX* store = NULL;
|
|
#else
|
|
char domain[ASN_NAME_MAX];
|
|
DecodedCert dCert[1];
|
|
WOLFSSL_X509_STORE_CTX store[1];
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE24_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
c24to32(input + *inOutIdx, &listSz);
|
|
*inOutIdx += OPAQUE24_LEN;
|
|
|
|
#ifdef HAVE_MAX_FRAGMENT
|
|
if (listSz > ssl->max_fragment) {
|
|
SendAlert(ssl, alert_fatal, record_overflow);
|
|
return BUFFER_E;
|
|
}
|
|
#else
|
|
if (listSz > MAX_RECORD_SIZE)
|
|
return BUFFER_E;
|
|
#endif
|
|
|
|
if ((*inOutIdx - begin) + listSz != size)
|
|
return BUFFER_ERROR;
|
|
|
|
WOLFSSL_MSG("Loading peer's cert chain");
|
|
/* first put cert chain into buffer so can verify top down
|
|
we're sent bottom up */
|
|
while (listSz) {
|
|
word32 certSz;
|
|
|
|
if (totalCerts >= MAX_CHAIN_DEPTH)
|
|
return MAX_CHAIN_ERROR;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE24_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
c24to32(input + *inOutIdx, &certSz);
|
|
*inOutIdx += OPAQUE24_LEN;
|
|
|
|
if ((*inOutIdx - begin) + certSz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
certs[totalCerts].length = certSz;
|
|
certs[totalCerts].buffer = input + *inOutIdx;
|
|
|
|
#ifdef SESSION_CERTS
|
|
if (ssl->session.chain.count < MAX_CHAIN_DEPTH &&
|
|
certSz < MAX_X509_SIZE) {
|
|
ssl->session.chain.certs[ssl->session.chain.count].length = certSz;
|
|
XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer,
|
|
input + *inOutIdx, certSz);
|
|
ssl->session.chain.count++;
|
|
} else {
|
|
WOLFSSL_MSG("Couldn't store chain cert for session");
|
|
}
|
|
#endif
|
|
|
|
*inOutIdx += certSz;
|
|
listSz -= certSz + CERT_HEADER_SZ;
|
|
|
|
totalCerts++;
|
|
WOLFSSL_MSG(" Put another cert into chain");
|
|
}
|
|
|
|
count = totalCerts;
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (dCert == NULL)
|
|
return MEMORY_E;
|
|
#endif
|
|
|
|
/* verify up to peer's first */
|
|
while (count > 1) {
|
|
buffer myCert = certs[count - 1];
|
|
byte* subjectHash;
|
|
|
|
InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap);
|
|
ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone,
|
|
ssl->ctx->cm);
|
|
#ifndef NO_SKID
|
|
subjectHash = dCert->extSubjKeyId;
|
|
#else
|
|
subjectHash = dCert->subjectHash;
|
|
#endif
|
|
|
|
if (ret == 0 && dCert->isCA == 0) {
|
|
WOLFSSL_MSG("Chain cert is not a CA, not adding as one");
|
|
}
|
|
else if (ret == 0 && ssl->options.verifyNone) {
|
|
WOLFSSL_MSG("Chain cert not verified by option, not adding as CA");
|
|
}
|
|
else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) {
|
|
buffer add;
|
|
add.length = myCert.length;
|
|
add.buffer = (byte*)XMALLOC(myCert.length, ssl->heap,
|
|
DYNAMIC_TYPE_CA);
|
|
WOLFSSL_MSG("Adding CA from chain");
|
|
|
|
if (add.buffer == NULL)
|
|
return MEMORY_E;
|
|
XMEMCPY(add.buffer, myCert.buffer, myCert.length);
|
|
|
|
ret = AddCA(ssl->ctx->cm, add, WOLFSSL_CHAIN_CA,
|
|
ssl->ctx->verifyPeer);
|
|
if (ret == 1) ret = 0; /* SSL_SUCCESS for external */
|
|
}
|
|
else if (ret != 0) {
|
|
WOLFSSL_MSG("Failed to verify CA from chain");
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("Verified CA from chain and already had it");
|
|
}
|
|
|
|
#ifdef HAVE_CRL
|
|
if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) {
|
|
WOLFSSL_MSG("Doing Non Leaf CRL check");
|
|
ret = CheckCertCRL(ssl->ctx->cm->crl, dCert);
|
|
|
|
if (ret != 0) {
|
|
WOLFSSL_MSG("\tCRL check not ok");
|
|
}
|
|
}
|
|
#endif /* HAVE_CRL */
|
|
|
|
if (ret != 0 && anyError == 0)
|
|
anyError = ret; /* save error from last time */
|
|
|
|
FreeDecodedCert(dCert);
|
|
count--;
|
|
}
|
|
|
|
/* peer's, may not have one if blank client cert sent by TLSv1.2 */
|
|
if (count) {
|
|
buffer myCert = certs[0];
|
|
int fatal = 0;
|
|
|
|
WOLFSSL_MSG("Verifying Peer's cert");
|
|
|
|
InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap);
|
|
ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone,
|
|
ssl->ctx->cm);
|
|
if (ret == 0) {
|
|
WOLFSSL_MSG("Verified Peer's cert");
|
|
fatal = 0;
|
|
}
|
|
else if (ret == ASN_PARSE_E) {
|
|
WOLFSSL_MSG("Got Peer cert ASN PARSE ERROR, fatal");
|
|
fatal = 1;
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("Failed to verify Peer's cert");
|
|
if (ssl->verifyCallback) {
|
|
WOLFSSL_MSG("\tCallback override available, will continue");
|
|
fatal = 0;
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("\tNo callback override available, fatal");
|
|
fatal = 1;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (fatal == 0 && ssl->secure_renegotiation
|
|
&& ssl->secure_renegotiation->enabled) {
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
/* compare against previous time */
|
|
if (XMEMCMP(dCert->subjectHash,
|
|
ssl->secure_renegotiation->subject_hash,
|
|
SHA_DIGEST_SIZE) != 0) {
|
|
WOLFSSL_MSG("Peer sent different cert during scr, fatal");
|
|
fatal = 1;
|
|
ret = SCR_DIFFERENT_CERT_E;
|
|
}
|
|
}
|
|
|
|
/* cache peer's hash */
|
|
if (fatal == 0) {
|
|
XMEMCPY(ssl->secure_renegotiation->subject_hash,
|
|
dCert->subjectHash, SHA_DIGEST_SIZE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_OCSP
|
|
if (fatal == 0 && ssl->ctx->cm->ocspEnabled) {
|
|
ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert);
|
|
if (ret != 0) {
|
|
WOLFSSL_MSG("\tOCSP Lookup not ok");
|
|
fatal = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_CRL
|
|
if (fatal == 0 && ssl->ctx->cm->crlEnabled) {
|
|
int doCrlLookup = 1;
|
|
|
|
#ifdef HAVE_OCSP
|
|
if (ssl->ctx->cm->ocspEnabled) {
|
|
doCrlLookup = (ret == OCSP_CERT_UNKNOWN);
|
|
}
|
|
#endif /* HAVE_OCSP */
|
|
|
|
if (doCrlLookup) {
|
|
WOLFSSL_MSG("Doing Leaf CRL check");
|
|
ret = CheckCertCRL(ssl->ctx->cm->crl, dCert);
|
|
|
|
if (ret != 0) {
|
|
WOLFSSL_MSG("\tCRL check not ok");
|
|
fatal = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* HAVE_CRL */
|
|
|
|
#ifdef KEEP_PEER_CERT
|
|
{
|
|
/* set X509 format for peer cert even if fatal */
|
|
int copyRet = CopyDecodedToX509(&ssl->peerCert, dCert);
|
|
if (copyRet == MEMORY_E)
|
|
fatal = 1;
|
|
}
|
|
#endif
|
|
|
|
#ifndef IGNORE_KEY_EXTENSIONS
|
|
if (dCert->extKeyUsageSet) {
|
|
if ((ssl->specs.kea == rsa_kea) &&
|
|
(dCert->extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) {
|
|
ret = KEYUSE_ENCIPHER_E;
|
|
}
|
|
if ((ssl->specs.sig_algo == rsa_sa_algo ||
|
|
(ssl->specs.sig_algo == ecc_dsa_sa_algo &&
|
|
!ssl->specs.static_ecdh)) &&
|
|
(dCert->extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) {
|
|
WOLFSSL_MSG("KeyUse Digital Sig not set");
|
|
ret = KEYUSE_SIGNATURE_E;
|
|
}
|
|
}
|
|
|
|
if (dCert->extExtKeyUsageSet) {
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
if ((dCert->extExtKeyUsage &
|
|
(EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) {
|
|
WOLFSSL_MSG("ExtKeyUse Server Auth not set");
|
|
ret = EXTKEYUSE_AUTH_E;
|
|
}
|
|
}
|
|
else {
|
|
if ((dCert->extExtKeyUsage &
|
|
(EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) {
|
|
WOLFSSL_MSG("ExtKeyUse Client Auth not set");
|
|
ret = EXTKEYUSE_AUTH_E;
|
|
}
|
|
}
|
|
}
|
|
#endif /* IGNORE_KEY_EXTENSIONS */
|
|
|
|
if (fatal) {
|
|
FreeDecodedCert(dCert);
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
ssl->error = ret;
|
|
return ret;
|
|
}
|
|
ssl->options.havePeerCert = 1;
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
domain = (char*)XMALLOC(ASN_NAME_MAX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (domain == NULL) {
|
|
FreeDecodedCert(dCert);
|
|
XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
return MEMORY_E;
|
|
}
|
|
#endif
|
|
/* store for callback use */
|
|
if (dCert->subjectCNLen < ASN_NAME_MAX) {
|
|
XMEMCPY(domain, dCert->subjectCN, dCert->subjectCNLen);
|
|
domain[dCert->subjectCNLen] = '\0';
|
|
}
|
|
else
|
|
domain[0] = '\0';
|
|
|
|
if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) {
|
|
if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen,
|
|
(char*)ssl->buffers.domainName.buffer) == 0) {
|
|
WOLFSSL_MSG("DomainName match on common name failed");
|
|
if (CheckAltNames(dCert,
|
|
(char*)ssl->buffers.domainName.buffer) == 0 ) {
|
|
WOLFSSL_MSG("DomainName match on alt names failed too");
|
|
ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* decode peer key */
|
|
switch (dCert->keyOID) {
|
|
#ifndef NO_RSA
|
|
case RSAk:
|
|
{
|
|
word32 idx = 0;
|
|
int keyRet = 0;
|
|
|
|
if (ssl->peerRsaKeyPresent) { /* don't leak on reuse */
|
|
FreeRsaKey(ssl->peerRsaKey);
|
|
ssl->peerRsaKeyPresent = 0;
|
|
keyRet = InitRsaKey(ssl->peerRsaKey, ssl->heap);
|
|
}
|
|
|
|
if (keyRet != 0 || RsaPublicKeyDecode(dCert->publicKey,
|
|
&idx, ssl->peerRsaKey, dCert->pubKeySize) != 0) {
|
|
ret = PEER_KEY_ERROR;
|
|
}
|
|
else {
|
|
ssl->peerRsaKeyPresent = 1;
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifndef NO_RSA
|
|
ssl->buffers.peerRsaKey.buffer =
|
|
(byte*)XMALLOC(dCert->pubKeySize,
|
|
ssl->heap, DYNAMIC_TYPE_RSA);
|
|
if (ssl->buffers.peerRsaKey.buffer == NULL)
|
|
ret = MEMORY_ERROR;
|
|
else {
|
|
XMEMCPY(ssl->buffers.peerRsaKey.buffer,
|
|
dCert->publicKey, dCert->pubKeySize);
|
|
ssl->buffers.peerRsaKey.length =
|
|
dCert->pubKeySize;
|
|
}
|
|
#endif /* NO_RSA */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
}
|
|
break;
|
|
#endif /* NO_RSA */
|
|
#ifdef HAVE_NTRU
|
|
case NTRUk:
|
|
{
|
|
if (dCert->pubKeySize > sizeof(ssl->peerNtruKey)) {
|
|
ret = PEER_KEY_ERROR;
|
|
}
|
|
else {
|
|
XMEMCPY(ssl->peerNtruKey, dCert->publicKey,
|
|
dCert->pubKeySize);
|
|
ssl->peerNtruKeyLen = (word16)dCert->pubKeySize;
|
|
ssl->peerNtruKeyPresent = 1;
|
|
}
|
|
}
|
|
break;
|
|
#endif /* HAVE_NTRU */
|
|
#ifdef HAVE_ECC
|
|
case ECDSAk:
|
|
{
|
|
if (ssl->peerEccDsaKeyPresent) { /* don't leak on reuse */
|
|
ecc_free(ssl->peerEccDsaKey);
|
|
ssl->peerEccDsaKeyPresent = 0;
|
|
ecc_init(ssl->peerEccDsaKey);
|
|
}
|
|
if (ecc_import_x963(dCert->publicKey, dCert->pubKeySize,
|
|
ssl->peerEccDsaKey) != 0) {
|
|
ret = PEER_KEY_ERROR;
|
|
}
|
|
else {
|
|
ssl->peerEccDsaKeyPresent = 1;
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
ssl->buffers.peerEccDsaKey.buffer =
|
|
(byte*)XMALLOC(dCert->pubKeySize,
|
|
ssl->heap, DYNAMIC_TYPE_ECC);
|
|
if (ssl->buffers.peerEccDsaKey.buffer == NULL)
|
|
ret = MEMORY_ERROR;
|
|
else {
|
|
XMEMCPY(ssl->buffers.peerEccDsaKey.buffer,
|
|
dCert->publicKey, dCert->pubKeySize);
|
|
ssl->buffers.peerEccDsaKey.length =
|
|
dCert->pubKeySize;
|
|
}
|
|
#endif /* HAVE_ECC */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
}
|
|
break;
|
|
#endif /* HAVE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
FreeDecodedCert(dCert);
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
|
|
store = (WOLFSSL_X509_STORE_CTX*)XMALLOC(sizeof(WOLFSSL_X509_STORE_CTX),
|
|
NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (store == NULL) {
|
|
XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
return MEMORY_E;
|
|
}
|
|
#endif
|
|
|
|
if (anyError != 0 && ret == 0)
|
|
ret = anyError;
|
|
|
|
if (ret != 0) {
|
|
if (!ssl->options.verifyNone) {
|
|
int why = bad_certificate;
|
|
|
|
if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E)
|
|
why = certificate_expired;
|
|
if (ssl->verifyCallback) {
|
|
int ok;
|
|
|
|
store->error = ret;
|
|
store->error_depth = totalCerts;
|
|
store->discardSessionCerts = 0;
|
|
store->domain = domain;
|
|
store->userCtx = ssl->verifyCbCtx;
|
|
#ifdef KEEP_PEER_CERT
|
|
store->current_cert = &ssl->peerCert;
|
|
#else
|
|
store->current_cert = NULL;
|
|
#endif
|
|
#ifdef FORTRESS
|
|
store->ex_data = ssl;
|
|
#endif
|
|
ok = ssl->verifyCallback(0, store);
|
|
if (ok) {
|
|
WOLFSSL_MSG("Verify callback overriding error!");
|
|
ret = 0;
|
|
}
|
|
#ifdef SESSION_CERTS
|
|
if (store->discardSessionCerts) {
|
|
WOLFSSL_MSG("Verify callback requested discard sess certs");
|
|
ssl->session.chain.count = 0;
|
|
}
|
|
#endif
|
|
}
|
|
if (ret != 0) {
|
|
SendAlert(ssl, alert_fatal, why); /* try to send */
|
|
ssl->options.isClosed = 1;
|
|
}
|
|
}
|
|
ssl->error = ret;
|
|
}
|
|
#ifdef WOLFSSL_ALWAYS_VERIFY_CB
|
|
else {
|
|
if (ssl->verifyCallback) {
|
|
int ok;
|
|
|
|
store->error = ret;
|
|
store->error_depth = totalCerts;
|
|
store->discardSessionCerts = 0;
|
|
store->domain = domain;
|
|
store->userCtx = ssl->verifyCbCtx;
|
|
#ifdef KEEP_PEER_CERT
|
|
store->current_cert = &ssl->peerCert;
|
|
#endif
|
|
store->ex_data = ssl;
|
|
|
|
ok = ssl->verifyCallback(1, store);
|
|
if (!ok) {
|
|
WOLFSSL_MSG("Verify callback overriding valid certificate!");
|
|
ret = -1;
|
|
SendAlert(ssl, alert_fatal, bad_certificate);
|
|
ssl->options.isClosed = 1;
|
|
}
|
|
#ifdef SESSION_CERTS
|
|
if (store->discardSessionCerts) {
|
|
WOLFSSL_MSG("Verify callback requested discard sess certs");
|
|
ssl->session.chain.count = 0;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ssl->options.verifyNone &&
|
|
(ret == CRL_MISSING || ret == CRL_CERT_REVOKED)) {
|
|
WOLFSSL_MSG("Ignoring CRL problem based on verify setting");
|
|
ret = ssl->error = 0;
|
|
}
|
|
|
|
if (ret == 0 && ssl->options.side == WOLFSSL_CLIENT_END)
|
|
ssl->options.serverState = SERVER_CERT_COMPLETE;
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(store, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* !NO_CERTS */
|
|
|
|
|
|
static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|
word32 size, word32 totalSz)
|
|
{
|
|
(void)input;
|
|
|
|
if (size) /* must be 0 */
|
|
return BUFFER_ERROR;
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
/* access beyond input + size should be checked against totalSz */
|
|
if (*inOutIdx + ssl->keys.padSz > totalSz)
|
|
return BUFFER_E;
|
|
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
|
|
if (ssl->options.side == WOLFSSL_SERVER_END) {
|
|
SendAlert(ssl, alert_fatal, unexpected_message); /* try */
|
|
return FATAL_ERROR;
|
|
}
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
|
|
ssl->secure_renegotiation->startScr = 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
else {
|
|
return SendAlert(ssl, alert_warning, no_renegotiation);
|
|
}
|
|
}
|
|
|
|
|
|
int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size,
|
|
word32 totalSz, int sniff)
|
|
{
|
|
word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ);
|
|
|
|
if (finishedSz != size)
|
|
return BUFFER_ERROR;
|
|
|
|
/* check against totalSz */
|
|
if (*inOutIdx + size + ssl->keys.padSz > totalSz)
|
|
return BUFFER_E;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
if (sniff == NO_SNIFF) {
|
|
if (XMEMCMP(input + *inOutIdx, &ssl->verifyHashes, size) != 0) {
|
|
WOLFSSL_MSG("Verify finished error on hashes");
|
|
return VERIFY_FINISHED_ERROR;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (ssl->secure_renegotiation) {
|
|
/* save peer's state */
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END)
|
|
XMEMCPY(ssl->secure_renegotiation->server_verify_data,
|
|
input + *inOutIdx, TLS_FINISHED_SZ);
|
|
else
|
|
XMEMCPY(ssl->secure_renegotiation->client_verify_data,
|
|
input + *inOutIdx, TLS_FINISHED_SZ);
|
|
}
|
|
#endif
|
|
|
|
/* force input exhaustion at ProcessReply consuming padSz */
|
|
*inOutIdx += size + ssl->keys.padSz;
|
|
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
ssl->options.serverState = SERVER_FINISHED_COMPLETE;
|
|
if (!ssl->options.resuming) {
|
|
ssl->options.handShakeState = HANDSHAKE_DONE;
|
|
ssl->options.handShakeDone = 1;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
/* Other side has received our Finished, go to next epoch */
|
|
ssl->keys.dtls_epoch++;
|
|
ssl->keys.dtls_sequence_number = 1;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
|
|
if (ssl->options.resuming) {
|
|
ssl->options.handShakeState = HANDSHAKE_DONE;
|
|
ssl->options.handShakeDone = 1;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
/* Other side has received our Finished, go to next epoch */
|
|
ssl->keys.dtls_epoch++;
|
|
ssl->keys.dtls_sequence_number = 1;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Make sure no duplicates, no fast forward, or other problems; 0 on success */
|
|
static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
|
|
{
|
|
/* verify not a duplicate, mark received, check state */
|
|
switch (type) {
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case hello_request:
|
|
if (ssl->msgsReceived.got_hello_request) {
|
|
WOLFSSL_MSG("Duplicate HelloRequest received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_hello_request = 1;
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
case client_hello:
|
|
if (ssl->msgsReceived.got_client_hello) {
|
|
WOLFSSL_MSG("Duplicate ClientHello received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_client_hello = 1;
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case server_hello:
|
|
if (ssl->msgsReceived.got_server_hello) {
|
|
WOLFSSL_MSG("Duplicate ServerHello received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_server_hello = 1;
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case hello_verify_request:
|
|
if (ssl->msgsReceived.got_hello_verify_request) {
|
|
WOLFSSL_MSG("Duplicate HelloVerifyRequest received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_hello_verify_request = 1;
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case session_ticket:
|
|
if (ssl->msgsReceived.got_session_ticket) {
|
|
WOLFSSL_MSG("Duplicate SessionTicket received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_session_ticket = 1;
|
|
|
|
break;
|
|
#endif
|
|
|
|
case certificate:
|
|
if (ssl->msgsReceived.got_certificate) {
|
|
WOLFSSL_MSG("Duplicate Certificate received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_certificate = 1;
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
if ( ssl->msgsReceived.got_server_hello == 0) {
|
|
WOLFSSL_MSG("No ServerHello before Cert");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
if (ssl->options.side == WOLFSSL_SERVER_END) {
|
|
if ( ssl->msgsReceived.got_client_hello == 0) {
|
|
WOLFSSL_MSG("No ClientHello before Cert");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case server_key_exchange:
|
|
if (ssl->msgsReceived.got_server_key_exchange) {
|
|
WOLFSSL_MSG("Duplicate ServerKeyExchange received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_server_key_exchange = 1;
|
|
|
|
if ( ssl->msgsReceived.got_server_hello == 0) {
|
|
WOLFSSL_MSG("No ServerHello before Cert");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case certificate_request:
|
|
if (ssl->msgsReceived.got_certificate_request) {
|
|
WOLFSSL_MSG("Duplicate CertificateRequest received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_certificate_request = 1;
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case server_hello_done:
|
|
if (ssl->msgsReceived.got_server_hello_done) {
|
|
WOLFSSL_MSG("Duplicate ServerHelloDone received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_server_hello_done = 1;
|
|
|
|
if (ssl->msgsReceived.got_certificate == 0) {
|
|
if (ssl->specs.kea == psk_kea ||
|
|
ssl->specs.kea == dhe_psk_kea ||
|
|
ssl->options.usingAnon_cipher) {
|
|
WOLFSSL_MSG("No Cert required");
|
|
} else {
|
|
WOLFSSL_MSG("No Certificate before ServerHelloDone");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
}
|
|
if (ssl->msgsReceived.got_server_key_exchange == 0) {
|
|
if (ssl->specs.static_ecdh == 1 ||
|
|
ssl->specs.kea == rsa_kea ||
|
|
ssl->specs.kea == ntru_kea) {
|
|
WOLFSSL_MSG("No KeyExchange required");
|
|
} else {
|
|
WOLFSSL_MSG("No ServerKeyExchange before ServerDone");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
case certificate_verify:
|
|
if (ssl->msgsReceived.got_certificate_verify) {
|
|
WOLFSSL_MSG("Duplicate CertificateVerify received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_certificate_verify = 1;
|
|
|
|
if ( ssl->msgsReceived.got_certificate == 0) {
|
|
WOLFSSL_MSG("No Cert before CertVerify");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
case client_key_exchange:
|
|
if (ssl->msgsReceived.got_client_key_exchange) {
|
|
WOLFSSL_MSG("Duplicate ClientKeyExchange received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_client_key_exchange = 1;
|
|
|
|
if (ssl->msgsReceived.got_client_hello == 0) {
|
|
WOLFSSL_MSG("No ClientHello before ClientKeyExchange");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case finished:
|
|
if (ssl->msgsReceived.got_finished) {
|
|
WOLFSSL_MSG("Duplicate Finished received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_finished = 1;
|
|
|
|
if (ssl->msgsReceived.got_change_cipher == 0) {
|
|
WOLFSSL_MSG("Finished received before ChangeCipher");
|
|
return NO_CHANGE_CIPHER_E;
|
|
}
|
|
|
|
break;
|
|
|
|
case change_cipher_hs:
|
|
if (ssl->msgsReceived.got_change_cipher) {
|
|
WOLFSSL_MSG("Duplicate ChangeCipher received");
|
|
return DUPLICATE_MSG_E;
|
|
}
|
|
ssl->msgsReceived.got_change_cipher = 1;
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
if (!ssl->options.resuming &&
|
|
ssl->msgsReceived.got_server_hello_done == 0) {
|
|
WOLFSSL_MSG("No ServerHelloDone before ChangeCipher");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
if (ssl->options.side == WOLFSSL_SERVER_END) {
|
|
if (!ssl->options.resuming &&
|
|
ssl->msgsReceived.got_client_key_exchange == 0) {
|
|
WOLFSSL_MSG("No ClientKeyExchange before ChangeCipher");
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
WOLFSSL_MSG("Unknown message type");
|
|
return SANITY_MSG_E;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
|
byte type, word32 size, word32 totalSz)
|
|
{
|
|
int ret = 0;
|
|
(void)totalSz;
|
|
|
|
WOLFSSL_ENTER("DoHandShakeMsgType");
|
|
|
|
/* make sure can read the message */
|
|
if (*inOutIdx + size > totalSz)
|
|
return INCOMPLETE_DATA;
|
|
|
|
/* sanity check msg received */
|
|
if ( (ret = SanityCheckMsgReceived(ssl, type)) != 0) {
|
|
WOLFSSL_MSG("Sanity Check on handshake message type received failed");
|
|
return ret;
|
|
}
|
|
|
|
/* hello_request not hashed */
|
|
if (type != hello_request) {
|
|
ret = HashInput(ssl, input + *inOutIdx, size);
|
|
if (ret != 0) return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
/* add name later, add on record and handshake header part back on */
|
|
if (ssl->toInfoOn) {
|
|
int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add,
|
|
size + add, ssl->heap);
|
|
AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
|
|
}
|
|
#endif
|
|
|
|
if (ssl->options.handShakeState == HANDSHAKE_DONE && type != hello_request){
|
|
WOLFSSL_MSG("HandShake message after handshake complete");
|
|
SendAlert(ssl, alert_fatal, unexpected_message);
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls == 0 &&
|
|
ssl->options.serverState == NULL_STATE && type != server_hello) {
|
|
WOLFSSL_MSG("First server message not server hello");
|
|
SendAlert(ssl, alert_fatal, unexpected_message);
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls &&
|
|
type == server_hello_done &&
|
|
ssl->options.serverState < SERVER_HELLO_COMPLETE) {
|
|
WOLFSSL_MSG("Server hello done received before server hello in DTLS");
|
|
SendAlert(ssl, alert_fatal, unexpected_message);
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
if (ssl->options.side == WOLFSSL_SERVER_END &&
|
|
ssl->options.clientState == NULL_STATE && type != client_hello) {
|
|
WOLFSSL_MSG("First client message not client hello");
|
|
SendAlert(ssl, alert_fatal, unexpected_message);
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
|
|
switch (type) {
|
|
|
|
case hello_request:
|
|
WOLFSSL_MSG("processing hello request");
|
|
ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz);
|
|
break;
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
case hello_verify_request:
|
|
WOLFSSL_MSG("processing hello verify request");
|
|
ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size);
|
|
break;
|
|
|
|
case server_hello:
|
|
WOLFSSL_MSG("processing server hello");
|
|
ret = DoServerHello(ssl, input, inOutIdx, size);
|
|
break;
|
|
|
|
#ifndef NO_CERTS
|
|
case certificate_request:
|
|
WOLFSSL_MSG("processing certificate request");
|
|
ret = DoCertificateRequest(ssl, input, inOutIdx, size);
|
|
break;
|
|
#endif
|
|
|
|
case server_key_exchange:
|
|
WOLFSSL_MSG("processing server key exchange");
|
|
ret = DoServerKeyExchange(ssl, input, inOutIdx, size);
|
|
break;
|
|
|
|
#ifdef HAVE_SESSION_TICKET
|
|
case session_ticket:
|
|
WOLFSSL_MSG("processing session ticket");
|
|
ret = DoSessionTicket(ssl, input, inOutIdx, size);
|
|
break;
|
|
#endif /* HAVE_SESSION_TICKET */
|
|
#endif
|
|
|
|
#ifndef NO_CERTS
|
|
case certificate:
|
|
WOLFSSL_MSG("processing certificate");
|
|
ret = DoCertificate(ssl, input, inOutIdx, size);
|
|
break;
|
|
#endif
|
|
|
|
case server_hello_done:
|
|
WOLFSSL_MSG("processing server hello done");
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddLateName("ServerHelloDone", &ssl->timeoutInfo);
|
|
#endif
|
|
ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
|
|
if (ssl->keys.encryptionOn) {
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
break;
|
|
|
|
case finished:
|
|
WOLFSSL_MSG("processing finished");
|
|
ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF);
|
|
break;
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
case client_hello:
|
|
WOLFSSL_MSG("processing client hello");
|
|
ret = DoClientHello(ssl, input, inOutIdx, size);
|
|
break;
|
|
|
|
case client_key_exchange:
|
|
WOLFSSL_MSG("processing client key exchange");
|
|
ret = DoClientKeyExchange(ssl, input, inOutIdx, size);
|
|
break;
|
|
|
|
#if !defined(NO_RSA) || defined(HAVE_ECC)
|
|
case certificate_verify:
|
|
WOLFSSL_MSG("processing certificate verify");
|
|
ret = DoCertificateVerify(ssl, input, inOutIdx, size);
|
|
break;
|
|
#endif /* !NO_RSA || HAVE_ECC */
|
|
|
|
#endif /* !NO_WOLFSSL_SERVER */
|
|
|
|
default:
|
|
WOLFSSL_MSG("Unknown handshake message type");
|
|
ret = UNKNOWN_HANDSHAKE_TYPE;
|
|
break;
|
|
}
|
|
|
|
WOLFSSL_LEAVE("DoHandShakeMsgType()", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
|
word32 totalSz)
|
|
{
|
|
byte type;
|
|
word32 size;
|
|
int ret = 0;
|
|
|
|
WOLFSSL_ENTER("DoHandShakeMsg()");
|
|
|
|
if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size, totalSz) != 0)
|
|
return PARSE_ERROR;
|
|
|
|
ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
|
|
|
|
WOLFSSL_LEAVE("DoHandShakeMsg()", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
|
|
static INLINE int DtlsCheckWindow(DtlsState* state)
|
|
{
|
|
word32 cur;
|
|
word32 next;
|
|
DtlsSeq window;
|
|
|
|
if (state->curEpoch == state->nextEpoch) {
|
|
next = state->nextSeq;
|
|
window = state->window;
|
|
}
|
|
else if (state->curEpoch < state->nextEpoch) {
|
|
next = state->prevSeq;
|
|
window = state->prevWindow;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
|
|
cur = state->curSeq;
|
|
|
|
if ((next > DTLS_SEQ_BITS) && (cur < next - DTLS_SEQ_BITS)) {
|
|
return 0;
|
|
}
|
|
else if ((cur < next) && (window & ((DtlsSeq)1 << (next - cur - 1)))) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static INLINE int DtlsUpdateWindow(DtlsState* state)
|
|
{
|
|
word32 cur;
|
|
word32* next;
|
|
DtlsSeq* window;
|
|
|
|
if (state->curEpoch == state->nextEpoch) {
|
|
next = &state->nextSeq;
|
|
window = &state->window;
|
|
}
|
|
else {
|
|
next = &state->prevSeq;
|
|
window = &state->prevWindow;
|
|
}
|
|
|
|
cur = state->curSeq;
|
|
|
|
if (cur < *next) {
|
|
*window |= ((DtlsSeq)1 << (*next - cur - 1));
|
|
}
|
|
else {
|
|
*window <<= (1 + cur - *next);
|
|
*window |= 1;
|
|
*next = cur + 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int DtlsMsgDrain(WOLFSSL* ssl)
|
|
{
|
|
DtlsMsg* item = ssl->dtls_msg_list;
|
|
int ret = 0;
|
|
|
|
/* While there is an item in the store list, and it is the expected
|
|
* message, and it is complete, and there hasn't been an error in the
|
|
* last messge... */
|
|
while (item != NULL &&
|
|
ssl->keys.dtls_expected_peer_handshake_number == item->seq &&
|
|
item->fragSz == item->sz &&
|
|
ret == 0) {
|
|
word32 idx = 0;
|
|
ssl->keys.dtls_expected_peer_handshake_number++;
|
|
ret = DoHandShakeMsgType(ssl, item->msg,
|
|
&idx, item->type, item->sz, item->sz);
|
|
ssl->dtls_msg_list = item->next;
|
|
DtlsMsgDelete(item, ssl->heap);
|
|
item = ssl->dtls_msg_list;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
|
word32 totalSz)
|
|
{
|
|
byte type;
|
|
word32 size;
|
|
word32 fragOffset, fragSz;
|
|
int ret = 0;
|
|
|
|
WOLFSSL_ENTER("DoDtlsHandShakeMsg()");
|
|
if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type,
|
|
&size, &fragOffset, &fragSz, totalSz) != 0)
|
|
return PARSE_ERROR;
|
|
|
|
if (*inOutIdx + fragSz > totalSz)
|
|
return INCOMPLETE_DATA;
|
|
|
|
/* Check the handshake sequence number first. If out of order,
|
|
* add the current message to the list. If the message is in order,
|
|
* but it is a fragment, add the current message to the list, then
|
|
* check the head of the list to see if it is complete, if so, pop
|
|
* it out as the current message. If the message is complete and in
|
|
* order, process it. Check the head of the list to see if it is in
|
|
* order, if so, process it. (Repeat until list exhausted.) If the
|
|
* head is out of order, return for more processing.
|
|
*/
|
|
if (ssl->keys.dtls_peer_handshake_number >
|
|
ssl->keys.dtls_expected_peer_handshake_number) {
|
|
/* Current message is out of order. It will get stored in the list.
|
|
* Storing also takes care of defragmentation. */
|
|
ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list,
|
|
ssl->keys.dtls_peer_handshake_number, input + *inOutIdx,
|
|
size, type, fragOffset, fragSz, ssl->heap);
|
|
*inOutIdx += fragSz;
|
|
ret = 0;
|
|
}
|
|
else if (ssl->keys.dtls_peer_handshake_number <
|
|
ssl->keys.dtls_expected_peer_handshake_number) {
|
|
/* Already saw this message and processed it. It can be ignored. */
|
|
*inOutIdx += fragSz;
|
|
ret = 0;
|
|
}
|
|
else if (fragSz < size) {
|
|
/* Since this branch is in order, but fragmented, dtls_msg_list will be
|
|
* pointing to the message with this fragment in it. Check it to see
|
|
* if it is completed. */
|
|
ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list,
|
|
ssl->keys.dtls_peer_handshake_number, input + *inOutIdx,
|
|
size, type, fragOffset, fragSz, ssl->heap);
|
|
*inOutIdx += fragSz;
|
|
ret = 0;
|
|
if (ssl->dtls_msg_list != NULL &&
|
|
ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz)
|
|
ret = DtlsMsgDrain(ssl);
|
|
}
|
|
else {
|
|
/* This branch is in order next, and a complete message. */
|
|
ssl->keys.dtls_expected_peer_handshake_number++;
|
|
ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
|
|
if (ret == 0 && ssl->dtls_msg_list != NULL)
|
|
ret = DtlsMsgDrain(ssl);
|
|
}
|
|
|
|
WOLFSSL_LEAVE("DoDtlsHandShakeMsg()", ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \
|
|
|| defined(HAVE_AESGCM)
|
|
static INLINE word32 GetSEQIncrement(WOLFSSL* ssl, int verify)
|
|
{
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if (verify)
|
|
return ssl->keys.dtls_state.curSeq; /* explicit from peer */
|
|
else
|
|
return ssl->keys.dtls_sequence_number - 1; /* already incremented */
|
|
}
|
|
#endif
|
|
if (verify)
|
|
return ssl->keys.peer_sequence_number++;
|
|
else
|
|
return ssl->keys.sequence_number++;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef HAVE_AEAD
|
|
static INLINE void AeadIncrementExpIV(WOLFSSL* ssl)
|
|
{
|
|
int i;
|
|
for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) {
|
|
if (++ssl->keys.aead_exp_IV[i]) return;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef HAVE_POLY1305
|
|
/*more recent rfc's concatonate input for poly1305 differently*/
|
|
static int Poly1305Tag(WOLFSSL* ssl, byte* additional, const byte* out,
|
|
byte* cipher, word16 sz, byte* tag)
|
|
{
|
|
int ret = 0;
|
|
int paddingSz = 0;
|
|
int msglen = (sz - ssl->specs.aead_mac_size);
|
|
word32 keySz = 32;
|
|
byte padding[16];
|
|
|
|
if (msglen < 0)
|
|
return INPUT_CASE_ERROR;
|
|
|
|
XMEMSET(padding, 0, sizeof(padding));
|
|
|
|
if ((ret = Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0)
|
|
return ret;
|
|
|
|
/* additional input to poly1305 */
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, additional,
|
|
CHACHA20_BLOCK_SIZE)) != 0)
|
|
return ret;
|
|
|
|
/* cipher input */
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, out, msglen)) != 0)
|
|
return ret;
|
|
|
|
/* handle padding for cipher input to make it 16 bytes long */
|
|
if (msglen % 16 != 0) {
|
|
paddingSz = (16 - (sz - ssl->specs.aead_mac_size) % 16);
|
|
if (paddingSz < 0)
|
|
return INPUT_CASE_ERROR;
|
|
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, padding, paddingSz))
|
|
!= 0)
|
|
return ret;
|
|
}
|
|
|
|
/* add size of AD and size of cipher to poly input */
|
|
XMEMSET(padding, 0, sizeof(padding));
|
|
padding[0] = CHACHA20_BLOCK_SIZE;
|
|
|
|
/* 32 bit size of cipher to 64 bit endian */
|
|
padding[8] = msglen & 0xff;
|
|
padding[9] = (msglen >> 8) & 0xff;
|
|
padding[10] = (msglen >>16) & 0xff;
|
|
padding[11] = (msglen >>24) & 0xff;
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding)))
|
|
!= 0)
|
|
return ret;
|
|
|
|
/* generate tag */
|
|
if ((ret = Poly1305Final(ssl->auth.poly1305, tag)) != 0)
|
|
return ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Used for the older version of creating AEAD tags with Poly1305 */
|
|
static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out,
|
|
byte* cipher, word16 sz, byte* tag)
|
|
{
|
|
int ret = 0;
|
|
int msglen = (sz - ssl->specs.aead_mac_size);
|
|
word32 keySz = 32;
|
|
byte padding[8]; /* used to temporarly store lengths */
|
|
|
|
#ifdef CHACHA_AEAD_TEST
|
|
printf("Using old version of poly1305 input.\n");
|
|
#endif
|
|
|
|
if (msglen < 0)
|
|
return INPUT_CASE_ERROR;
|
|
|
|
if ((ret = Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0)
|
|
return ret;
|
|
|
|
/* add TLS compressed length and additional input to poly1305 */
|
|
additional[AEAD_AUTH_DATA_SZ - 2] = (msglen >> 8) & 0xff;
|
|
additional[AEAD_AUTH_DATA_SZ - 1] = msglen & 0xff;
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, additional,
|
|
AEAD_AUTH_DATA_SZ)) != 0)
|
|
return ret;
|
|
|
|
/* length of additional input plus padding */
|
|
XMEMSET(padding, 0, sizeof(padding));
|
|
padding[0] = AEAD_AUTH_DATA_SZ;
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, padding,
|
|
sizeof(padding))) != 0)
|
|
return ret;
|
|
|
|
|
|
/* add cipher info and then its length */
|
|
XMEMSET(padding, 0, sizeof(padding));
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, out, msglen)) != 0)
|
|
return ret;
|
|
|
|
/* 32 bit size of cipher to 64 bit endian */
|
|
padding[0] = msglen & 0xff;
|
|
padding[1] = (msglen >> 8) & 0xff;
|
|
padding[2] = (msglen >> 16) & 0xff;
|
|
padding[3] = (msglen >> 24) & 0xff;
|
|
if ((ret = Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding)))
|
|
!= 0)
|
|
return ret;
|
|
|
|
/* generate tag */
|
|
if ((ret = Poly1305Final(ssl->auth.poly1305, tag)) != 0)
|
|
return ret;
|
|
|
|
return ret;
|
|
}
|
|
#endif /*HAVE_POLY1305*/
|
|
|
|
|
|
#ifdef HAVE_CHACHA
|
|
static int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input,
|
|
word16 sz)
|
|
{
|
|
const byte* additionalSrc = input - RECORD_HEADER_SZ;
|
|
int ret = 0;
|
|
byte tag[POLY1305_AUTH_SZ];
|
|
byte additional[CHACHA20_BLOCK_SIZE];
|
|
byte nonce[AEAD_NONCE_SZ];
|
|
byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */
|
|
#ifdef CHACHA_AEAD_TEST
|
|
int i;
|
|
#endif
|
|
|
|
XMEMSET(tag, 0, sizeof(tag));
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
XMEMSET(cipher, 0, sizeof(cipher));
|
|
XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE);
|
|
|
|
/* get nonce */
|
|
c32toa(ssl->keys.sequence_number, nonce + AEAD_IMP_IV_SZ
|
|
+ AEAD_SEQ_OFFSET);
|
|
|
|
/* opaque SEQ number stored for AD */
|
|
c32toa(GetSEQIncrement(ssl, 0), additional + AEAD_SEQ_OFFSET);
|
|
|
|
/* Store the type, version. Unfortunately, they are in
|
|
* the input buffer ahead of the plaintext. */
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
c16toa(ssl->keys.dtls_epoch, additional);
|
|
additionalSrc -= DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
|
|
|
|
#ifdef CHACHA_AEAD_TEST
|
|
printf("Encrypt Additional : ");
|
|
for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) {
|
|
printf("%02x", additional[i]);
|
|
}
|
|
printf("\n\n");
|
|
printf("input before encryption :\n");
|
|
for (i = 0; i < sz; i++) {
|
|
printf("%02x", input[i]);
|
|
if ((i + 1) % 16 == 0)
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
/* set the nonce for chacha and get poly1305 key */
|
|
if ((ret = Chacha_SetIV(ssl->encrypt.chacha, nonce, 0)) != 0)
|
|
return ret;
|
|
|
|
if ((ret = Chacha_Process(ssl->encrypt.chacha, cipher,
|
|
cipher, sizeof(cipher))) != 0)
|
|
return ret;
|
|
|
|
/* encrypt the plain text */
|
|
if ((ret = Chacha_Process(ssl->encrypt.chacha, out, input,
|
|
sz - ssl->specs.aead_mac_size)) != 0)
|
|
return ret;
|
|
|
|
#ifdef HAVE_POLY1305
|
|
/* get the tag : future use of hmac could go here*/
|
|
if (ssl->options.oldPoly == 1) {
|
|
if ((ret = Poly1305TagOld(ssl, additional, (const byte* )out,
|
|
cipher, sz, tag)) != 0)
|
|
return ret;
|
|
}
|
|
else {
|
|
if ((ret = Poly1305Tag(ssl, additional, (const byte* )out,
|
|
cipher, sz, tag)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* append tag to ciphertext */
|
|
XMEMCPY(out + sz - ssl->specs.aead_mac_size, tag, sizeof(tag));
|
|
|
|
AeadIncrementExpIV(ssl);
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
|
|
#ifdef CHACHA_AEAD_TEST
|
|
printf("mac tag :\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%02x", tag[i]);
|
|
if ((i + 1) % 16 == 0)
|
|
printf("\n");
|
|
}
|
|
printf("\n\noutput after encrypt :\n");
|
|
for (i = 0; i < sz; i++) {
|
|
printf("%02x", out[i]);
|
|
if ((i + 1) % 16 == 0)
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input,
|
|
word16 sz)
|
|
{
|
|
byte additional[CHACHA20_BLOCK_SIZE];
|
|
byte nonce[AEAD_NONCE_SZ];
|
|
byte tag[POLY1305_AUTH_SZ];
|
|
byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for mac */
|
|
int i;
|
|
int ret = 0;
|
|
|
|
XMEMSET(tag, 0, sizeof(tag));
|
|
XMEMSET(cipher, 0, sizeof(cipher));
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE);
|
|
|
|
#ifdef CHACHA_AEAD_TEST
|
|
printf("input before decrypt :\n");
|
|
for (i = 0; i < sz; i++) {
|
|
printf("%02x", input[i]);
|
|
if ((i + 1) % 16 == 0)
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
/* get nonce */
|
|
c32toa(ssl->keys.peer_sequence_number, nonce + AEAD_IMP_IV_SZ
|
|
+ AEAD_SEQ_OFFSET);
|
|
|
|
/* sequence number field is 64-bits, we only use 32-bits */
|
|
c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
|
|
|
|
/* get AD info */
|
|
additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
|
|
additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
|
|
additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
|
|
|
|
/* Store the type, version. */
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
c16toa(ssl->keys.dtls_state.curEpoch, additional);
|
|
#endif
|
|
|
|
#ifdef CHACHA_AEAD_TEST
|
|
printf("Decrypt Additional : ");
|
|
for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) {
|
|
printf("%02x", additional[i]);
|
|
}
|
|
printf("\n\n");
|
|
#endif
|
|
|
|
/* set nonce and get poly1305 key */
|
|
if ((ret = Chacha_SetIV(ssl->decrypt.chacha, nonce, 0)) != 0)
|
|
return ret;
|
|
|
|
if ((ret = Chacha_Process(ssl->decrypt.chacha, cipher,
|
|
cipher, sizeof(cipher))) != 0)
|
|
return ret;
|
|
|
|
#ifdef HAVE_POLY1305
|
|
/* get the tag : future use of hmac could go here*/
|
|
if (ssl->options.oldPoly == 1) {
|
|
if ((ret = Poly1305TagOld(ssl, additional, input, cipher,
|
|
sz, tag)) != 0)
|
|
return ret;
|
|
}
|
|
else {
|
|
if ((ret = Poly1305Tag(ssl, additional, input, cipher,
|
|
sz, tag)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* check mac sent along with packet */
|
|
ret = 0;
|
|
for (i = 0; i < ssl->specs.aead_mac_size; i++) {
|
|
if ((input + sz - ssl->specs.aead_mac_size)[i] != tag[i])
|
|
ret = 1;
|
|
}
|
|
|
|
if (ret == 1) {
|
|
WOLFSSL_MSG("Mac did not match");
|
|
SendAlert(ssl, alert_fatal, bad_record_mac);
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
|
|
/* if mac was good decrypt message */
|
|
if ((ret = Chacha_Process(ssl->decrypt.chacha, plain, input,
|
|
sz - ssl->specs.aead_mac_size)) != 0)
|
|
return ret;
|
|
|
|
#ifdef CHACHA_AEAD_TEST
|
|
printf("plain after decrypt :\n");
|
|
for (i = 0; i < sz; i++) {
|
|
printf("%02x", plain[i]);
|
|
if ((i + 1) % 16 == 0)
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_CHACHA */
|
|
#endif
|
|
|
|
|
|
static INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz)
|
|
{
|
|
(void)out;
|
|
(void)input;
|
|
(void)sz;
|
|
|
|
if (ssl->encrypt.setup == 0) {
|
|
WOLFSSL_MSG("Encrypt ciphers not setup");
|
|
return ENCRYPT_ERROR;
|
|
}
|
|
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, input, sz, FUZZ_ENCRYPT, ssl->fuzzerCtx);
|
|
#endif
|
|
|
|
switch (ssl->specs.bulk_cipher_algorithm) {
|
|
#ifdef BUILD_ARC4
|
|
case wolfssl_rc4:
|
|
wc_Arc4Process(ssl->encrypt.arc4, out, input, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef BUILD_DES3
|
|
case wolfssl_triple_des:
|
|
return Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz);
|
|
#endif
|
|
|
|
#ifdef BUILD_AES
|
|
case wolfssl_aes:
|
|
return wc_AesCbcEncrypt(ssl->encrypt.aes, out, input, sz);
|
|
#endif
|
|
|
|
#ifdef BUILD_AESGCM
|
|
case wolfssl_aes_gcm:
|
|
{
|
|
int gcmRet;
|
|
byte additional[AEAD_AUTH_DATA_SZ];
|
|
byte nonce[AEAD_NONCE_SZ];
|
|
const byte* additionalSrc = input - 5;
|
|
|
|
XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
|
|
|
|
/* sequence number field is 64-bits, we only use 32-bits */
|
|
c32toa(GetSEQIncrement(ssl, 0),
|
|
additional + AEAD_SEQ_OFFSET);
|
|
|
|
/* Store the type, version. Unfortunately, they are in
|
|
* the input buffer ahead of the plaintext. */
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
c16toa(ssl->keys.dtls_epoch, additional);
|
|
additionalSrc -= DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
|
|
|
|
/* Store the length of the plain text minus the explicit
|
|
* IV length minus the authentication tag size. */
|
|
c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
additional + AEAD_LEN_OFFSET);
|
|
XMEMCPY(nonce,
|
|
ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ);
|
|
XMEMCPY(nonce + AEAD_IMP_IV_SZ,
|
|
ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
|
|
gcmRet = wc_AesGcmEncrypt(ssl->encrypt.aes,
|
|
out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ,
|
|
sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
nonce, AEAD_NONCE_SZ,
|
|
out + sz - ssl->specs.aead_mac_size,
|
|
ssl->specs.aead_mac_size,
|
|
additional, AEAD_AUTH_DATA_SZ);
|
|
if (gcmRet == 0)
|
|
AeadIncrementExpIV(ssl);
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
return gcmRet;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_AESCCM
|
|
case wolfssl_aes_ccm:
|
|
{
|
|
byte additional[AEAD_AUTH_DATA_SZ];
|
|
byte nonce[AEAD_NONCE_SZ];
|
|
const byte* additionalSrc = input - 5;
|
|
|
|
XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
|
|
|
|
/* sequence number field is 64-bits, we only use 32-bits */
|
|
c32toa(GetSEQIncrement(ssl, 0),
|
|
additional + AEAD_SEQ_OFFSET);
|
|
|
|
/* Store the type, version. Unfortunately, they are in
|
|
* the input buffer ahead of the plaintext. */
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
c16toa(ssl->keys.dtls_epoch, additional);
|
|
additionalSrc -= DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
|
|
|
|
/* Store the length of the plain text minus the explicit
|
|
* IV length minus the authentication tag size. */
|
|
c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
additional + AEAD_LEN_OFFSET);
|
|
XMEMCPY(nonce,
|
|
ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ);
|
|
XMEMCPY(nonce + AEAD_IMP_IV_SZ,
|
|
ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
|
|
wc_AesCcmEncrypt(ssl->encrypt.aes,
|
|
out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ,
|
|
sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
nonce, AEAD_NONCE_SZ,
|
|
out + sz - ssl->specs.aead_mac_size,
|
|
ssl->specs.aead_mac_size,
|
|
additional, AEAD_AUTH_DATA_SZ);
|
|
AeadIncrementExpIV(ssl);
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_CAMELLIA
|
|
case wolfssl_camellia:
|
|
CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_HC128
|
|
case wolfssl_hc128:
|
|
return Hc128_Process(ssl->encrypt.hc128, out, input, sz);
|
|
#endif
|
|
|
|
#ifdef BUILD_RABBIT
|
|
case wolfssl_rabbit:
|
|
return RabbitProcess(ssl->encrypt.rabbit, out, input, sz);
|
|
#endif
|
|
|
|
#ifdef HAVE_CHACHA
|
|
case wolfssl_chacha:
|
|
return ChachaAEADEncrypt(ssl, out, input, sz);
|
|
#endif
|
|
|
|
#ifdef HAVE_NULL_CIPHER
|
|
case wolfssl_cipher_null:
|
|
if (input != out) {
|
|
XMEMMOVE(out, input, sz);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
WOLFSSL_MSG("wolfSSL Encrypt programming error");
|
|
return ENCRYPT_ERROR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input,
|
|
word16 sz)
|
|
{
|
|
(void)plain;
|
|
(void)input;
|
|
(void)sz;
|
|
|
|
if (ssl->decrypt.setup == 0) {
|
|
WOLFSSL_MSG("Decrypt ciphers not setup");
|
|
return DECRYPT_ERROR;
|
|
}
|
|
|
|
switch (ssl->specs.bulk_cipher_algorithm) {
|
|
#ifdef BUILD_ARC4
|
|
case wolfssl_rc4:
|
|
wc_Arc4Process(ssl->decrypt.arc4, plain, input, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef BUILD_DES3
|
|
case wolfssl_triple_des:
|
|
return Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz);
|
|
#endif
|
|
|
|
#ifdef BUILD_AES
|
|
case wolfssl_aes:
|
|
return wc_AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz);
|
|
#endif
|
|
|
|
#ifdef BUILD_AESGCM
|
|
case wolfssl_aes_gcm:
|
|
{
|
|
byte additional[AEAD_AUTH_DATA_SZ];
|
|
byte nonce[AEAD_NONCE_SZ];
|
|
|
|
XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
|
|
|
|
/* sequence number field is 64-bits, we only use 32-bits */
|
|
c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
c16toa(ssl->keys.dtls_state.curEpoch, additional);
|
|
#endif
|
|
|
|
additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
|
|
additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
|
|
additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
|
|
|
|
c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
additional + AEAD_LEN_OFFSET);
|
|
XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ);
|
|
XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ);
|
|
if (wc_AesGcmDecrypt(ssl->decrypt.aes,
|
|
plain + AEAD_EXP_IV_SZ,
|
|
input + AEAD_EXP_IV_SZ,
|
|
sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
nonce, AEAD_NONCE_SZ,
|
|
input + sz - ssl->specs.aead_mac_size,
|
|
ssl->specs.aead_mac_size,
|
|
additional, AEAD_AUTH_DATA_SZ) < 0) {
|
|
SendAlert(ssl, alert_fatal, bad_record_mac);
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_AESCCM
|
|
case wolfssl_aes_ccm:
|
|
{
|
|
byte additional[AEAD_AUTH_DATA_SZ];
|
|
byte nonce[AEAD_NONCE_SZ];
|
|
|
|
XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
|
|
|
|
/* sequence number field is 64-bits, we only use 32-bits */
|
|
c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
c16toa(ssl->keys.dtls_state.curEpoch, additional);
|
|
#endif
|
|
|
|
additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
|
|
additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
|
|
additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
|
|
|
|
c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
additional + AEAD_LEN_OFFSET);
|
|
XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ);
|
|
XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ);
|
|
if (wc_AesCcmDecrypt(ssl->decrypt.aes,
|
|
plain + AEAD_EXP_IV_SZ,
|
|
input + AEAD_EXP_IV_SZ,
|
|
sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
|
nonce, AEAD_NONCE_SZ,
|
|
input + sz - ssl->specs.aead_mac_size,
|
|
ssl->specs.aead_mac_size,
|
|
additional, AEAD_AUTH_DATA_SZ) < 0) {
|
|
SendAlert(ssl, alert_fatal, bad_record_mac);
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
XMEMSET(nonce, 0, AEAD_NONCE_SZ);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_CAMELLIA
|
|
case wolfssl_camellia:
|
|
CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_HC128
|
|
case wolfssl_hc128:
|
|
return Hc128_Process(ssl->decrypt.hc128, plain, input, sz);
|
|
#endif
|
|
|
|
#ifdef BUILD_RABBIT
|
|
case wolfssl_rabbit:
|
|
return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz);
|
|
#endif
|
|
|
|
#ifdef HAVE_CHACHA
|
|
case wolfssl_chacha:
|
|
return ChachaAEADDecrypt(ssl, plain, input, sz);
|
|
#endif
|
|
|
|
#ifdef HAVE_NULL_CIPHER
|
|
case wolfssl_cipher_null:
|
|
if (input != plain) {
|
|
XMEMMOVE(plain, input, sz);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
WOLFSSL_MSG("wolfSSL Decrypt programming error");
|
|
return DECRYPT_ERROR;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* check cipher text size for sanity */
|
|
static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz)
|
|
{
|
|
#ifdef HAVE_TRUNCATED_HMAC
|
|
word32 minLength = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ
|
|
: ssl->specs.hash_size;
|
|
#else
|
|
word32 minLength = ssl->specs.hash_size; /* covers stream */
|
|
#endif
|
|
|
|
if (ssl->specs.cipher_type == block) {
|
|
if (encryptSz % ssl->specs.block_size) {
|
|
WOLFSSL_MSG("Block ciphertext not block size");
|
|
return SANITY_CIPHER_E;
|
|
}
|
|
|
|
minLength++; /* pad byte */
|
|
|
|
if (ssl->specs.block_size > minLength)
|
|
minLength = ssl->specs.block_size;
|
|
|
|
if (ssl->options.tls1_1)
|
|
minLength += ssl->specs.block_size; /* explicit IV */
|
|
}
|
|
else if (ssl->specs.cipher_type == aead) {
|
|
minLength = ssl->specs.aead_mac_size; /* authTag size */
|
|
if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
|
|
minLength += AEAD_EXP_IV_SZ; /* explicit IV */
|
|
}
|
|
|
|
if (encryptSz < minLength) {
|
|
WOLFSSL_MSG("Ciphertext not minimum size");
|
|
return SANITY_CIPHER_E;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifndef NO_OLD_TLS
|
|
|
|
static INLINE void Md5Rounds(int rounds, const byte* data, int sz)
|
|
{
|
|
Md5 md5;
|
|
int i;
|
|
|
|
InitMd5(&md5);
|
|
|
|
for (i = 0; i < rounds; i++)
|
|
Md5Update(&md5, data, sz);
|
|
}
|
|
|
|
|
|
|
|
/* do a dummy sha round */
|
|
static INLINE void ShaRounds(int rounds, const byte* data, int sz)
|
|
{
|
|
Sha sha;
|
|
int i;
|
|
|
|
InitSha(&sha); /* no error check on purpose, dummy round */
|
|
|
|
for (i = 0; i < rounds; i++)
|
|
ShaUpdate(&sha, data, sz);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifndef NO_SHA256
|
|
|
|
static INLINE void Sha256Rounds(int rounds, const byte* data, int sz)
|
|
{
|
|
Sha256 sha256;
|
|
int i;
|
|
|
|
InitSha256(&sha256); /* no error check on purpose, dummy round */
|
|
|
|
for (i = 0; i < rounds; i++) {
|
|
Sha256Update(&sha256, data, sz);
|
|
/* no error check on purpose, dummy round */
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef WOLFSSL_SHA384
|
|
|
|
static INLINE void Sha384Rounds(int rounds, const byte* data, int sz)
|
|
{
|
|
Sha384 sha384;
|
|
int i;
|
|
|
|
InitSha384(&sha384); /* no error check on purpose, dummy round */
|
|
|
|
for (i = 0; i < rounds; i++) {
|
|
Sha384Update(&sha384, data, sz);
|
|
/* no error check on purpose, dummy round */
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef WOLFSSL_SHA512
|
|
|
|
static INLINE void Sha512Rounds(int rounds, const byte* data, int sz)
|
|
{
|
|
Sha512 sha512;
|
|
int i;
|
|
|
|
InitSha512(&sha512); /* no error check on purpose, dummy round */
|
|
|
|
for (i = 0; i < rounds; i++) {
|
|
Sha512Update(&sha512, data, sz);
|
|
/* no error check on purpose, dummy round */
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef WOLFSSL_RIPEMD
|
|
|
|
static INLINE void RmdRounds(int rounds, const byte* data, int sz)
|
|
{
|
|
RipeMd ripemd;
|
|
int i;
|
|
|
|
InitRipeMd(&ripemd);
|
|
|
|
for (i = 0; i < rounds; i++)
|
|
RipeMdUpdate(&ripemd, data, sz);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/* Do dummy rounds */
|
|
static INLINE void DoRounds(int type, int rounds, const byte* data, int sz)
|
|
{
|
|
switch (type) {
|
|
|
|
case no_mac :
|
|
break;
|
|
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
case md5_mac :
|
|
Md5Rounds(rounds, data, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NO_SHA
|
|
case sha_mac :
|
|
ShaRounds(rounds, data, sz);
|
|
break;
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef NO_SHA256
|
|
case sha256_mac :
|
|
Sha256Rounds(rounds, data, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SHA384
|
|
case sha384_mac :
|
|
Sha384Rounds(rounds, data, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SHA512
|
|
case sha512_mac :
|
|
Sha512Rounds(rounds, data, sz);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_RIPEMD
|
|
case rmd_mac :
|
|
RmdRounds(rounds, data, sz);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
WOLFSSL_MSG("Bad round type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* do number of compression rounds on dummy data */
|
|
static INLINE void CompressRounds(WOLFSSL* ssl, int rounds, const byte* dummy)
|
|
{
|
|
if (rounds)
|
|
DoRounds(ssl->specs.mac_algorithm, rounds, dummy, COMPRESS_LOWER);
|
|
}
|
|
|
|
|
|
/* check all length bytes for equality, return 0 on success */
|
|
static int ConstantCompare(const byte* a, const byte* b, int length)
|
|
{
|
|
int i;
|
|
int good = 0;
|
|
int bad = 0;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
if (a[i] == b[i])
|
|
good++;
|
|
else
|
|
bad++;
|
|
}
|
|
|
|
if (good == length)
|
|
return 0;
|
|
else
|
|
return 0 - bad; /* compare failed */
|
|
}
|
|
|
|
|
|
/* check all length bytes for the pad value, return 0 on success */
|
|
static int PadCheck(const byte* input, byte pad, int length)
|
|
{
|
|
int i;
|
|
int good = 0;
|
|
int bad = 0;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
if (input[i] == pad)
|
|
good++;
|
|
else
|
|
bad++;
|
|
}
|
|
|
|
if (good == length)
|
|
return 0;
|
|
else
|
|
return 0 - bad; /* pad check failed */
|
|
}
|
|
|
|
|
|
/* get compression extra rounds */
|
|
static INLINE int GetRounds(int pLen, int padLen, int t)
|
|
{
|
|
int roundL1 = 1; /* round up flags */
|
|
int roundL2 = 1;
|
|
|
|
int L1 = COMPRESS_CONSTANT + pLen - t;
|
|
int L2 = COMPRESS_CONSTANT + pLen - padLen - 1 - t;
|
|
|
|
L1 -= COMPRESS_UPPER;
|
|
L2 -= COMPRESS_UPPER;
|
|
|
|
if ( (L1 % COMPRESS_LOWER) == 0)
|
|
roundL1 = 0;
|
|
if ( (L2 % COMPRESS_LOWER) == 0)
|
|
roundL2 = 0;
|
|
|
|
L1 /= COMPRESS_LOWER;
|
|
L2 /= COMPRESS_LOWER;
|
|
|
|
L1 += roundL1;
|
|
L2 += roundL2;
|
|
|
|
return L1 - L2;
|
|
}
|
|
|
|
|
|
/* timing resistant pad/verify check, return 0 on success */
|
|
static int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int t,
|
|
int pLen, int content)
|
|
{
|
|
byte verify[MAX_DIGEST_SIZE];
|
|
byte dummy[MAX_PAD_SIZE];
|
|
int ret = 0;
|
|
|
|
XMEMSET(dummy, 1, sizeof(dummy));
|
|
|
|
if ( (t + padLen + 1) > pLen) {
|
|
WOLFSSL_MSG("Plain Len not long enough for pad/mac");
|
|
PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE);
|
|
ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */
|
|
ConstantCompare(verify, input + pLen - t, t);
|
|
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
|
|
if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) {
|
|
WOLFSSL_MSG("PadCheck failed");
|
|
PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
|
|
ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */
|
|
ConstantCompare(verify, input + pLen - t, t);
|
|
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
|
|
PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
|
|
ret = ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, content, 1);
|
|
|
|
CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy);
|
|
|
|
if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) {
|
|
WOLFSSL_MSG("Verify MAC compare failed");
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
|
|
if (ret != 0)
|
|
return VERIFY_MAC_ERROR;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx)
|
|
{
|
|
word32 msgSz = ssl->keys.encryptSz;
|
|
word32 idx = *inOutIdx;
|
|
int dataSz;
|
|
int ivExtra = 0;
|
|
byte* rawData = input + idx; /* keep current for hmac */
|
|
#ifdef HAVE_LIBZ
|
|
byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
|
|
#endif
|
|
|
|
if (ssl->options.handShakeDone == 0) {
|
|
WOLFSSL_MSG("Received App data before a handshake completed");
|
|
SendAlert(ssl, alert_fatal, unexpected_message);
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
if (ssl->specs.cipher_type == block) {
|
|
if (ssl->options.tls1_1)
|
|
ivExtra = ssl->specs.block_size;
|
|
}
|
|
else if (ssl->specs.cipher_type == aead) {
|
|
if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
|
|
ivExtra = AEAD_EXP_IV_SZ;
|
|
}
|
|
|
|
dataSz = msgSz - ivExtra - ssl->keys.padSz;
|
|
if (dataSz < 0) {
|
|
WOLFSSL_MSG("App data buffer error, malicious input?");
|
|
return BUFFER_ERROR;
|
|
}
|
|
|
|
/* read data */
|
|
if (dataSz) {
|
|
int rawSz = dataSz; /* keep raw size for idx adjustment */
|
|
|
|
#ifdef HAVE_LIBZ
|
|
if (ssl->options.usingCompression) {
|
|
dataSz = myDeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp));
|
|
if (dataSz < 0) return dataSz;
|
|
}
|
|
#endif
|
|
idx += rawSz;
|
|
|
|
ssl->buffers.clearOutputBuffer.buffer = rawData;
|
|
ssl->buffers.clearOutputBuffer.length = dataSz;
|
|
}
|
|
|
|
idx += ssl->keys.padSz;
|
|
|
|
#ifdef HAVE_LIBZ
|
|
/* decompress could be bigger, overwrite after verify */
|
|
if (ssl->options.usingCompression)
|
|
XMEMMOVE(rawData, decomp, dataSz);
|
|
#endif
|
|
|
|
*inOutIdx = idx;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* process alert, return level */
|
|
static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type,
|
|
word32 totalSz)
|
|
{
|
|
byte level;
|
|
byte code;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("Alert", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
/* add record header back on to info + 2 byte level, data */
|
|
AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx -
|
|
RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap);
|
|
#endif
|
|
|
|
/* make sure can read the message */
|
|
if (*inOutIdx + ALERT_SIZE > totalSz)
|
|
return BUFFER_E;
|
|
|
|
level = input[(*inOutIdx)++];
|
|
code = input[(*inOutIdx)++];
|
|
ssl->alert_history.last_rx.code = code;
|
|
ssl->alert_history.last_rx.level = level;
|
|
*type = code;
|
|
if (level == alert_fatal) {
|
|
ssl->options.isClosed = 1; /* Don't send close_notify */
|
|
}
|
|
|
|
WOLFSSL_MSG("Got alert");
|
|
if (*type == close_notify) {
|
|
WOLFSSL_MSG(" close notify");
|
|
ssl->options.closeNotify = 1;
|
|
}
|
|
WOLFSSL_ERROR(*type);
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
if (*inOutIdx + ssl->keys.padSz > totalSz)
|
|
return BUFFER_E;
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
|
|
return level;
|
|
}
|
|
|
|
static int GetInputData(WOLFSSL *ssl, word32 size)
|
|
{
|
|
int in;
|
|
int inSz;
|
|
int maxLength;
|
|
int usedLength;
|
|
int dtlsExtra = 0;
|
|
|
|
|
|
/* check max input length */
|
|
usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx;
|
|
maxLength = ssl->buffers.inputBuffer.bufferSize - usedLength;
|
|
inSz = (int)(size - usedLength); /* from last partial read */
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if (size < ssl->dtls_expected_rx)
|
|
dtlsExtra = (int)(ssl->dtls_expected_rx - size);
|
|
inSz = ssl->dtls_expected_rx;
|
|
}
|
|
#endif
|
|
|
|
if (inSz > maxLength) {
|
|
if (GrowInputBuffer(ssl, size + dtlsExtra, usedLength) < 0)
|
|
return MEMORY_E;
|
|
}
|
|
|
|
if (inSz <= 0)
|
|
return BUFFER_ERROR;
|
|
|
|
/* Put buffer data at start if not there */
|
|
if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0)
|
|
XMEMMOVE(ssl->buffers.inputBuffer.buffer,
|
|
ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
|
|
usedLength);
|
|
|
|
/* remove processed data */
|
|
ssl->buffers.inputBuffer.idx = 0;
|
|
ssl->buffers.inputBuffer.length = usedLength;
|
|
|
|
/* read data from network */
|
|
do {
|
|
in = Receive(ssl,
|
|
ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.length,
|
|
inSz);
|
|
if (in == -1)
|
|
return SOCKET_ERROR_E;
|
|
|
|
if (in == WANT_READ)
|
|
return WANT_READ;
|
|
|
|
if (in > inSz)
|
|
return RECV_OVERFLOW_E;
|
|
|
|
ssl->buffers.inputBuffer.length += in;
|
|
inSz -= in;
|
|
|
|
} while (ssl->buffers.inputBuffer.length < size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz,
|
|
int content, word32* padSz)
|
|
{
|
|
int ivExtra = 0;
|
|
int ret;
|
|
word32 pad = 0;
|
|
word32 padByte = 0;
|
|
#ifdef HAVE_TRUNCATED_HMAC
|
|
word32 digestSz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ
|
|
: ssl->specs.hash_size;
|
|
#else
|
|
word32 digestSz = ssl->specs.hash_size;
|
|
#endif
|
|
byte verify[MAX_DIGEST_SIZE];
|
|
|
|
if (ssl->specs.cipher_type == block) {
|
|
if (ssl->options.tls1_1)
|
|
ivExtra = ssl->specs.block_size;
|
|
pad = *(input + msgSz - ivExtra - 1);
|
|
padByte = 1;
|
|
|
|
if (ssl->options.tls) {
|
|
ret = TimingPadVerify(ssl, input, pad, digestSz, msgSz - ivExtra,
|
|
content);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
else { /* sslv3, some implementations have bad padding, but don't
|
|
* allow bad read */
|
|
int badPadLen = 0;
|
|
byte dummy[MAX_PAD_SIZE];
|
|
|
|
XMEMSET(dummy, 1, sizeof(dummy));
|
|
|
|
if (pad > (msgSz - digestSz - 1)) {
|
|
WOLFSSL_MSG("Plain Len not long enough for pad/mac");
|
|
pad = 0; /* no bad read */
|
|
badPadLen = 1;
|
|
}
|
|
PadCheck(dummy, (byte)pad, MAX_PAD_SIZE); /* timing only */
|
|
ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1,
|
|
content, 1);
|
|
if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1,
|
|
digestSz) != 0)
|
|
return VERIFY_MAC_ERROR;
|
|
if (ret != 0 || badPadLen)
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
}
|
|
else if (ssl->specs.cipher_type == stream) {
|
|
ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1);
|
|
if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
if (ret != 0)
|
|
return VERIFY_MAC_ERROR;
|
|
}
|
|
|
|
if (ssl->specs.cipher_type == aead) {
|
|
*padSz = ssl->specs.aead_mac_size;
|
|
}
|
|
else {
|
|
*padSz = digestSz + pad + padByte;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* process input requests, return 0 is done, 1 is call again to complete, and
|
|
negative number is error */
|
|
int ProcessReply(WOLFSSL* ssl)
|
|
{
|
|
int ret = 0, type, readSz;
|
|
int atomicUser = 0;
|
|
word32 startIdx = 0;
|
|
#ifdef WOLFSSL_DTLS
|
|
int used;
|
|
#endif
|
|
|
|
#ifdef ATOMIC_USER
|
|
if (ssl->ctx->DecryptVerifyCb)
|
|
atomicUser = 1;
|
|
#endif
|
|
|
|
if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE){
|
|
WOLFSSL_MSG("ProcessReply retry in error state, not allowed");
|
|
return ssl->error;
|
|
}
|
|
|
|
for (;;) {
|
|
switch (ssl->options.processReply) {
|
|
|
|
/* in the WOLFSSL_SERVER case, get the first byte for detecting
|
|
* old client hello */
|
|
case doProcessInit:
|
|
|
|
readSz = RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
readSz = DTLS_RECORD_HEADER_SZ;
|
|
#endif
|
|
|
|
/* get header or return error */
|
|
if (!ssl->options.dtls) {
|
|
if ((ret = GetInputData(ssl, readSz)) < 0)
|
|
return ret;
|
|
} else {
|
|
#ifdef WOLFSSL_DTLS
|
|
/* read ahead may already have header */
|
|
used = ssl->buffers.inputBuffer.length -
|
|
ssl->buffers.inputBuffer.idx;
|
|
if (used < readSz)
|
|
if ((ret = GetInputData(ssl, readSz)) < 0)
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
#ifdef OLD_HELLO_ALLOWED
|
|
|
|
/* see if sending SSLv2 client hello */
|
|
if ( ssl->options.side == WOLFSSL_SERVER_END &&
|
|
ssl->options.clientState == NULL_STATE &&
|
|
ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
|
|
!= handshake) {
|
|
byte b0, b1;
|
|
|
|
ssl->options.processReply = runProcessOldClientHello;
|
|
|
|
/* sanity checks before getting size at front */
|
|
if (ssl->buffers.inputBuffer.buffer[
|
|
ssl->buffers.inputBuffer.idx + 2] != OLD_HELLO_ID) {
|
|
WOLFSSL_MSG("Not a valid old client hello");
|
|
return PARSE_ERROR;
|
|
}
|
|
|
|
if (ssl->buffers.inputBuffer.buffer[
|
|
ssl->buffers.inputBuffer.idx + 3] != SSLv3_MAJOR &&
|
|
ssl->buffers.inputBuffer.buffer[
|
|
ssl->buffers.inputBuffer.idx + 3] != DTLS_MAJOR) {
|
|
WOLFSSL_MSG("Not a valid version in old client hello");
|
|
return PARSE_ERROR;
|
|
}
|
|
|
|
/* how many bytes need ProcessOldClientHello */
|
|
b0 =
|
|
ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
|
|
b1 =
|
|
ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
|
|
ssl->curSize = (word16)(((b0 & 0x7f) << 8) | b1);
|
|
}
|
|
else {
|
|
ssl->options.processReply = getRecordLayerHeader;
|
|
continue;
|
|
}
|
|
|
|
/* in the WOLFSSL_SERVER case, run the old client hello */
|
|
case runProcessOldClientHello:
|
|
|
|
/* get sz bytes or return error */
|
|
if (!ssl->options.dtls) {
|
|
if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
|
|
return ret;
|
|
} else {
|
|
#ifdef WOLFSSL_DTLS
|
|
/* read ahead may already have */
|
|
used = ssl->buffers.inputBuffer.length -
|
|
ssl->buffers.inputBuffer.idx;
|
|
if (used < ssl->curSize)
|
|
if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
|
|
return ret;
|
|
#endif /* WOLFSSL_DTLS */
|
|
}
|
|
|
|
ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer,
|
|
&ssl->buffers.inputBuffer.idx,
|
|
ssl->buffers.inputBuffer.length -
|
|
ssl->buffers.inputBuffer.idx,
|
|
ssl->curSize);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
else if (ssl->buffers.inputBuffer.idx ==
|
|
ssl->buffers.inputBuffer.length) {
|
|
ssl->options.processReply = doProcessInit;
|
|
return 0;
|
|
}
|
|
|
|
#endif /* OLD_HELLO_ALLOWED */
|
|
|
|
/* get the record layer header */
|
|
case getRecordLayerHeader:
|
|
|
|
ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer,
|
|
&ssl->buffers.inputBuffer.idx,
|
|
&ssl->curRL, &ssl->curSize);
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls && ret == SEQUENCE_ERROR) {
|
|
ssl->options.processReply = doProcessInit;
|
|
ssl->buffers.inputBuffer.length = 0;
|
|
ssl->buffers.inputBuffer.idx = 0;
|
|
continue;
|
|
}
|
|
#endif
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ssl->options.processReply = getData;
|
|
|
|
/* retrieve record layer data */
|
|
case getData:
|
|
|
|
/* get sz bytes or return error */
|
|
if (!ssl->options.dtls) {
|
|
if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
|
|
return ret;
|
|
} else {
|
|
#ifdef WOLFSSL_DTLS
|
|
/* read ahead may already have */
|
|
used = ssl->buffers.inputBuffer.length -
|
|
ssl->buffers.inputBuffer.idx;
|
|
if (used < ssl->curSize)
|
|
if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
ssl->options.processReply = runProcessingOneMessage;
|
|
startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */
|
|
|
|
/* the record layer is here */
|
|
case runProcessingOneMessage:
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls &&
|
|
ssl->keys.dtls_state.curEpoch < ssl->keys.dtls_state.nextEpoch)
|
|
ssl->keys.decryptedCur = 1;
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0)
|
|
{
|
|
ret = SanityCheckCipherText(ssl, ssl->curSize);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (atomicUser) {
|
|
#ifdef ATOMIC_USER
|
|
ret = ssl->ctx->DecryptVerifyCb(ssl,
|
|
ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx,
|
|
ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx,
|
|
ssl->curSize, ssl->curRL.type, 1,
|
|
&ssl->keys.padSz, ssl->DecryptVerifyCtx);
|
|
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
|
|
ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
|
|
/* go past TLSv1.1 IV */
|
|
if (ssl->specs.cipher_type == aead &&
|
|
ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
|
|
ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ;
|
|
#endif /* ATOMIC_USER */
|
|
}
|
|
else {
|
|
ret = Decrypt(ssl, ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx,
|
|
ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx,
|
|
ssl->curSize);
|
|
if (ret < 0) {
|
|
WOLFSSL_ERROR(ret);
|
|
return DECRYPT_ERROR;
|
|
}
|
|
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
|
|
ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
|
|
/* go past TLSv1.1 IV */
|
|
if (ssl->specs.cipher_type == aead &&
|
|
ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
|
|
ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ;
|
|
|
|
ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx,
|
|
ssl->curSize, ssl->curRL.type,
|
|
&ssl->keys.padSz);
|
|
}
|
|
if (ret < 0) {
|
|
WOLFSSL_ERROR(ret);
|
|
return DECRYPT_ERROR;
|
|
}
|
|
ssl->keys.encryptSz = ssl->curSize;
|
|
ssl->keys.decryptedCur = 1;
|
|
}
|
|
|
|
if (ssl->options.dtls) {
|
|
#ifdef WOLFSSL_DTLS
|
|
DtlsUpdateWindow(&ssl->keys.dtls_state);
|
|
#endif /* WOLFSSL_DTLS */
|
|
}
|
|
|
|
WOLFSSL_MSG("received record layer msg");
|
|
|
|
switch (ssl->curRL.type) {
|
|
case handshake :
|
|
/* debugging in DoHandShakeMsg */
|
|
if (!ssl->options.dtls) {
|
|
ret = DoHandShakeMsg(ssl,
|
|
ssl->buffers.inputBuffer.buffer,
|
|
&ssl->buffers.inputBuffer.idx,
|
|
ssl->buffers.inputBuffer.length);
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_DTLS
|
|
ret = DoDtlsHandShakeMsg(ssl,
|
|
ssl->buffers.inputBuffer.buffer,
|
|
&ssl->buffers.inputBuffer.idx,
|
|
ssl->buffers.inputBuffer.length);
|
|
#endif
|
|
}
|
|
if (ret != 0)
|
|
return ret;
|
|
break;
|
|
|
|
case change_cipher_spec:
|
|
WOLFSSL_MSG("got CHANGE CIPHER SPEC");
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ChangeCipher", &ssl->handShakeInfo);
|
|
/* add record header back on info */
|
|
if (ssl->toInfoOn) {
|
|
AddPacketInfo("ChangeCipher", &ssl->timeoutInfo,
|
|
ssl->buffers.inputBuffer.buffer +
|
|
ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ,
|
|
1 + RECORD_HEADER_SZ, ssl->heap);
|
|
AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
|
|
}
|
|
#endif
|
|
|
|
ret = SanityCheckMsgReceived(ssl, change_cipher_hs);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef HAVE_SESSION_TICKET
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END &&
|
|
ssl->expect_session_ticket) {
|
|
WOLFSSL_MSG("Expected session ticket missing");
|
|
return SESSION_TICKET_EXPECT_E;
|
|
}
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn && ssl->options.handShakeDone) {
|
|
ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
|
|
ssl->curSize -= ssl->buffers.inputBuffer.idx;
|
|
}
|
|
|
|
if (ssl->curSize != 1) {
|
|
WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg");
|
|
return LENGTH_ERROR;
|
|
}
|
|
#ifndef NO_CERTS
|
|
if (ssl->options.side == WOLFSSL_SERVER_END &&
|
|
ssl->options.verifyPeer &&
|
|
ssl->options.havePeerCert)
|
|
if (!ssl->options.havePeerVerify) {
|
|
WOLFSSL_MSG("client didn't send cert verify");
|
|
return NO_PEER_VERIFY;
|
|
}
|
|
#endif
|
|
|
|
|
|
ssl->buffers.inputBuffer.idx++;
|
|
ssl->keys.encryptionOn = 1;
|
|
|
|
/* setup decrypt keys for following messages */
|
|
if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
DtlsPoolReset(ssl);
|
|
ssl->keys.dtls_state.nextEpoch++;
|
|
ssl->keys.dtls_state.nextSeq = 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_LIBZ
|
|
if (ssl->options.usingCompression)
|
|
if ( (ret = InitStreams(ssl)) != 0)
|
|
return ret;
|
|
#endif
|
|
if (ssl->options.resuming && ssl->options.side ==
|
|
WOLFSSL_CLIENT_END)
|
|
ret = BuildFinished(ssl, &ssl->verifyHashes, server);
|
|
else if (!ssl->options.resuming && ssl->options.side ==
|
|
WOLFSSL_SERVER_END)
|
|
ret = BuildFinished(ssl, &ssl->verifyHashes, client);
|
|
if (ret != 0)
|
|
return ret;
|
|
break;
|
|
|
|
case application_data:
|
|
WOLFSSL_MSG("got app DATA");
|
|
if ((ret = DoApplicationData(ssl,
|
|
ssl->buffers.inputBuffer.buffer,
|
|
&ssl->buffers.inputBuffer.idx))
|
|
!= 0) {
|
|
WOLFSSL_ERROR(ret);
|
|
return ret;
|
|
}
|
|
break;
|
|
|
|
case alert:
|
|
WOLFSSL_MSG("got ALERT!");
|
|
ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
|
|
&ssl->buffers.inputBuffer.idx, &type,
|
|
ssl->buffers.inputBuffer.length);
|
|
if (ret == alert_fatal)
|
|
return FATAL_ERROR;
|
|
else if (ret < 0)
|
|
return ret;
|
|
|
|
/* catch warnings that are handled as errors */
|
|
if (type == close_notify)
|
|
return ssl->error = ZERO_RETURN;
|
|
|
|
if (type == decrypt_error)
|
|
return FATAL_ERROR;
|
|
break;
|
|
|
|
default:
|
|
WOLFSSL_ERROR(UNKNOWN_RECORD_TYPE);
|
|
return UNKNOWN_RECORD_TYPE;
|
|
}
|
|
|
|
ssl->options.processReply = doProcessInit;
|
|
|
|
/* input exhausted? */
|
|
if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length)
|
|
return 0;
|
|
/* more messages per record */
|
|
else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) {
|
|
WOLFSSL_MSG("More messages in record");
|
|
#ifdef WOLFSSL_DTLS
|
|
/* read-ahead but dtls doesn't bundle messages per record */
|
|
if (ssl->options.dtls) {
|
|
ssl->options.processReply = doProcessInit;
|
|
continue;
|
|
}
|
|
#endif
|
|
ssl->options.processReply = runProcessingOneMessage;
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
WOLFSSL_MSG("Bundled encrypted messages, remove middle pad");
|
|
ssl->buffers.inputBuffer.idx -= ssl->keys.padSz;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
/* more records */
|
|
else {
|
|
WOLFSSL_MSG("More records in input");
|
|
ssl->options.processReply = doProcessInit;
|
|
continue;
|
|
}
|
|
|
|
default:
|
|
WOLFSSL_MSG("Bad process input state, programming error");
|
|
return INPUT_CASE_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int SendChangeCipher(WOLFSSL* ssl)
|
|
{
|
|
byte *output;
|
|
int sendSz = RECORD_HEADER_SZ + ENUM_LEN;
|
|
int idx = RECORD_HEADER_SZ;
|
|
int ret;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA;
|
|
idx += DTLS_RECORD_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
/* are we in scr */
|
|
if (ssl->keys.encryptionOn && ssl->options.handShakeDone) {
|
|
sendSz += MAX_MSG_EXTRA;
|
|
}
|
|
|
|
/* check for avalaible size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddRecordHeader(output, 1, change_cipher_spec, ssl);
|
|
|
|
output[idx] = 1; /* turn it on */
|
|
|
|
if (ssl->keys.encryptionOn && ssl->options.handShakeDone) {
|
|
byte input[ENUM_LEN];
|
|
int inputSz = ENUM_LEN;
|
|
|
|
input[0] = 1; /* turn it on */
|
|
sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
|
|
change_cipher_spec);
|
|
if (sendSz < 0)
|
|
return sendSz;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz,
|
|
ssl->heap);
|
|
#endif
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
if (ssl->options.groupMessages)
|
|
return 0;
|
|
#ifdef WOLFSSL_DTLS
|
|
else if (ssl->options.dtls) {
|
|
/* If using DTLS, force the ChangeCipherSpec message to be in the
|
|
* same datagram as the finished message. */
|
|
return 0;
|
|
}
|
|
#endif
|
|
else
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
|
|
#ifndef NO_OLD_TLS
|
|
static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
|
|
int content, int verify)
|
|
{
|
|
byte result[MAX_DIGEST_SIZE];
|
|
word32 digestSz = ssl->specs.hash_size; /* actual sizes */
|
|
word32 padSz = ssl->specs.pad_size;
|
|
int ret = 0;
|
|
|
|
Md5 md5;
|
|
Sha sha;
|
|
|
|
/* data */
|
|
byte seq[SEQ_SZ];
|
|
byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */
|
|
const byte* macSecret = wolfSSL_GetMacSecret(ssl, verify);
|
|
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
|
|
#endif
|
|
|
|
XMEMSET(seq, 0, SEQ_SZ);
|
|
conLen[0] = (byte)content;
|
|
c16toa((word16)sz, &conLen[ENUM_LEN]);
|
|
c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
|
|
|
|
if (ssl->specs.mac_algorithm == md5_mac) {
|
|
InitMd5(&md5);
|
|
/* inner */
|
|
Md5Update(&md5, macSecret, digestSz);
|
|
Md5Update(&md5, PAD1, padSz);
|
|
Md5Update(&md5, seq, SEQ_SZ);
|
|
Md5Update(&md5, conLen, sizeof(conLen));
|
|
/* in buffer */
|
|
Md5Update(&md5, in, sz);
|
|
Md5Final(&md5, result);
|
|
/* outer */
|
|
Md5Update(&md5, macSecret, digestSz);
|
|
Md5Update(&md5, PAD2, padSz);
|
|
Md5Update(&md5, result, digestSz);
|
|
Md5Final(&md5, digest);
|
|
}
|
|
else {
|
|
ret = InitSha(&sha);
|
|
if (ret != 0)
|
|
return ret;
|
|
/* inner */
|
|
ShaUpdate(&sha, macSecret, digestSz);
|
|
ShaUpdate(&sha, PAD1, padSz);
|
|
ShaUpdate(&sha, seq, SEQ_SZ);
|
|
ShaUpdate(&sha, conLen, sizeof(conLen));
|
|
/* in buffer */
|
|
ShaUpdate(&sha, in, sz);
|
|
ShaFinal(&sha, result);
|
|
/* outer */
|
|
ShaUpdate(&sha, macSecret, digestSz);
|
|
ShaUpdate(&sha, PAD2, padSz);
|
|
ShaUpdate(&sha, result, digestSz);
|
|
ShaFinal(&sha, digest);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifndef NO_CERTS
|
|
static void BuildMD5_CertVerify(WOLFSSL* ssl, byte* digest)
|
|
{
|
|
byte md5_result[MD5_DIGEST_SIZE];
|
|
|
|
/* make md5 inner */
|
|
Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
|
|
Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
|
|
Md5Final(&ssl->hashMd5, md5_result);
|
|
|
|
/* make md5 outer */
|
|
Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
|
|
Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
|
|
Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
|
|
|
|
Md5Final(&ssl->hashMd5, digest);
|
|
}
|
|
|
|
|
|
static void BuildSHA_CertVerify(WOLFSSL* ssl, byte* digest)
|
|
{
|
|
byte sha_result[SHA_DIGEST_SIZE];
|
|
|
|
/* make sha inner */
|
|
ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
|
|
ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
|
|
ShaFinal(&ssl->hashSha, sha_result);
|
|
|
|
/* make sha outer */
|
|
ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
|
|
ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
|
|
ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
|
|
|
|
ShaFinal(&ssl->hashSha, digest);
|
|
}
|
|
#endif /* NO_CERTS */
|
|
#endif /* NO_OLD_TLS */
|
|
|
|
|
|
#ifndef NO_CERTS
|
|
|
|
static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes)
|
|
{
|
|
/* store current states, building requires get_digest which resets state */
|
|
#ifndef NO_OLD_TLS
|
|
Md5 md5 = ssl->hashMd5;
|
|
Sha sha = ssl->hashSha;
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
Sha256 sha256 = ssl->hashSha256;
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
Sha384 sha384 = ssl->hashSha384;
|
|
#endif
|
|
|
|
if (ssl->options.tls) {
|
|
#if ! defined( NO_OLD_TLS )
|
|
Md5Final(&ssl->hashMd5, hashes->md5);
|
|
ShaFinal(&ssl->hashSha, hashes->sha);
|
|
#endif
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
int ret;
|
|
|
|
#ifndef NO_SHA256
|
|
ret = Sha256Final(&ssl->hashSha256, hashes->sha256);
|
|
if (ret != 0)
|
|
return ret;
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
ret = Sha384Final(&ssl->hashSha384, hashes->sha384);
|
|
if (ret != 0)
|
|
return ret;
|
|
#endif
|
|
}
|
|
}
|
|
#if ! defined( NO_OLD_TLS )
|
|
else {
|
|
BuildMD5_CertVerify(ssl, hashes->md5);
|
|
BuildSHA_CertVerify(ssl, hashes->sha);
|
|
}
|
|
|
|
/* restore */
|
|
ssl->hashMd5 = md5;
|
|
ssl->hashSha = sha;
|
|
#endif
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
#ifndef NO_SHA256
|
|
ssl->hashSha256 = sha256;
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
ssl->hashSha384 = sha384;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* WOLFSSL_LEANPSK */
|
|
|
|
/* Build SSL Message, encrypted */
|
|
static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
|
|
const byte* input, int inSz, int type)
|
|
{
|
|
#ifdef HAVE_TRUNCATED_HMAC
|
|
word32 digestSz = min(ssl->specs.hash_size,
|
|
ssl->truncated_hmac ? TRUNCATED_HMAC_SZ : ssl->specs.hash_size);
|
|
#else
|
|
word32 digestSz = ssl->specs.hash_size;
|
|
#endif
|
|
word32 sz = RECORD_HEADER_SZ + inSz + digestSz;
|
|
word32 pad = 0, i;
|
|
word32 idx = RECORD_HEADER_SZ;
|
|
word32 ivSz = 0; /* TLSv1.1 IV */
|
|
word32 headerSz = RECORD_HEADER_SZ;
|
|
word16 size;
|
|
byte iv[AES_BLOCK_SIZE]; /* max size */
|
|
int ret = 0;
|
|
int atomicUser = 0;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sz += DTLS_RECORD_EXTRA;
|
|
idx += DTLS_RECORD_EXTRA;
|
|
headerSz += DTLS_RECORD_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ATOMIC_USER
|
|
if (ssl->ctx->MacEncryptCb)
|
|
atomicUser = 1;
|
|
#endif
|
|
|
|
if (ssl->specs.cipher_type == block) {
|
|
word32 blockSz = ssl->specs.block_size;
|
|
if (ssl->options.tls1_1) {
|
|
ivSz = blockSz;
|
|
sz += ivSz;
|
|
|
|
if (ivSz > (word32)sizeof(iv))
|
|
return BUFFER_E;
|
|
|
|
ret = RNG_GenerateBlock(ssl->rng, iv, ivSz);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
}
|
|
sz += 1; /* pad byte */
|
|
pad = (sz - headerSz) % blockSz;
|
|
pad = blockSz - pad;
|
|
sz += pad;
|
|
}
|
|
|
|
#ifdef HAVE_AEAD
|
|
if (ssl->specs.cipher_type == aead) {
|
|
if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
|
|
ivSz = AEAD_EXP_IV_SZ;
|
|
|
|
sz += (ivSz + ssl->specs.aead_mac_size - digestSz);
|
|
XMEMCPY(iv, ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
|
|
}
|
|
#endif
|
|
if (sz > (word32)outSz) {
|
|
WOLFSSL_MSG("Oops, want to write past output buffer size");
|
|
return BUFFER_E;
|
|
}
|
|
size = (word16)(sz - headerSz); /* include mac and digest */
|
|
AddRecordHeader(output, size, (byte)type, ssl);
|
|
|
|
/* write to output */
|
|
if (ivSz) {
|
|
XMEMCPY(output + idx, iv, min(ivSz, sizeof(iv)));
|
|
idx += ivSz;
|
|
}
|
|
XMEMCPY(output + idx, input, inSz);
|
|
idx += inSz;
|
|
|
|
if (type == handshake) {
|
|
ret = HashOutput(ssl, output, headerSz + inSz, ivSz);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
if (ssl->specs.cipher_type == block) {
|
|
word32 tmpIdx = idx + digestSz;
|
|
|
|
for (i = 0; i <= pad; i++)
|
|
output[tmpIdx++] = (byte)pad; /* pad byte gets pad value too */
|
|
}
|
|
|
|
if (atomicUser) { /* User Record Layer Callback handling */
|
|
#ifdef ATOMIC_USER
|
|
if ( (ret = ssl->ctx->MacEncryptCb(ssl, output + idx,
|
|
output + headerSz + ivSz, inSz, type, 0,
|
|
output + headerSz, output + headerSz, size,
|
|
ssl->MacEncryptCtx)) != 0)
|
|
return ret;
|
|
#endif
|
|
}
|
|
else {
|
|
if (ssl->specs.cipher_type != aead) {
|
|
#ifdef HAVE_TRUNCATED_HMAC
|
|
if (ssl->truncated_hmac && ssl->specs.hash_size > digestSz) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* hmac = NULL;
|
|
#else
|
|
byte hmac[MAX_DIGEST_SIZE];
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
hmac = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (hmac == NULL)
|
|
return MEMORY_E;
|
|
#endif
|
|
|
|
ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz,
|
|
type, 0);
|
|
XMEMCPY(output + idx, hmac, digestSz);
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
} else
|
|
#endif
|
|
ret = ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz,
|
|
type, 0);
|
|
}
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
if ( (ret = Encrypt(ssl, output + headerSz, output+headerSz,size)) != 0)
|
|
return ret;
|
|
}
|
|
|
|
return sz;
|
|
}
|
|
|
|
|
|
int SendFinished(WOLFSSL* ssl)
|
|
{
|
|
int sendSz,
|
|
finishedSz = ssl->options.tls ? TLS_FINISHED_SZ :
|
|
FINISHED_SZ;
|
|
byte input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ]; /* max */
|
|
byte *output;
|
|
Hashes* hashes;
|
|
int ret;
|
|
int headerSz = HANDSHAKE_HEADER_SZ;
|
|
int outputSz;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
word32 sequence_number = ssl->keys.dtls_sequence_number;
|
|
word16 epoch = ssl->keys.dtls_epoch;
|
|
#endif
|
|
|
|
/* setup encrypt keys */
|
|
if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
|
|
return ret;
|
|
|
|
/* check for available size */
|
|
outputSz = sizeof(input) + MAX_MSG_EXTRA;
|
|
if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
/* Send Finished message with the next epoch, but don't commit that
|
|
* change until the other end confirms its reception. */
|
|
headerSz += DTLS_HANDSHAKE_EXTRA;
|
|
ssl->keys.dtls_epoch++;
|
|
ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */
|
|
}
|
|
#endif
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHandShakeHeader(input, finishedSz, finished, ssl);
|
|
|
|
/* make finished hashes */
|
|
hashes = (Hashes*)&input[headerSz];
|
|
ret = BuildFinished(ssl, hashes,
|
|
ssl->options.side == WOLFSSL_CLIENT_END ? client : server);
|
|
if (ret != 0) return ret;
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (ssl->secure_renegotiation) {
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END)
|
|
XMEMCPY(ssl->secure_renegotiation->client_verify_data, hashes,
|
|
TLS_FINISHED_SZ);
|
|
else
|
|
XMEMCPY(ssl->secure_renegotiation->server_verify_data, hashes,
|
|
TLS_FINISHED_SZ);
|
|
}
|
|
#endif
|
|
|
|
sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz,
|
|
handshake);
|
|
if (sendSz < 0)
|
|
return BUILD_MSG_ERROR;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
ssl->keys.dtls_epoch = epoch;
|
|
ssl->keys.dtls_sequence_number = sequence_number;
|
|
}
|
|
#endif
|
|
|
|
if (!ssl->options.resuming) {
|
|
#ifndef NO_SESSION_CACHE
|
|
AddSession(ssl); /* just try */
|
|
#endif
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
ret = BuildFinished(ssl, &ssl->verifyHashes, server);
|
|
if (ret != 0) return ret;
|
|
}
|
|
else {
|
|
ssl->options.handShakeState = HANDSHAKE_DONE;
|
|
ssl->options.handShakeDone = 1;
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
/* Other side will soon receive our Finished, go to next
|
|
* epoch. */
|
|
ssl->keys.dtls_epoch++;
|
|
ssl->keys.dtls_sequence_number = 1;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
|
ssl->options.handShakeState = HANDSHAKE_DONE;
|
|
ssl->options.handShakeDone = 1;
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
/* Other side will soon receive our Finished, go to next
|
|
* epoch. */
|
|
ssl->keys.dtls_epoch++;
|
|
ssl->keys.dtls_sequence_number = 1;
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
ret = BuildFinished(ssl, &ssl->verifyHashes, client);
|
|
if (ret != 0) return ret;
|
|
}
|
|
}
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
|
|
ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
#ifndef NO_CERTS
|
|
int SendCertificate(WOLFSSL* ssl)
|
|
{
|
|
int sendSz, length, ret = 0;
|
|
word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
word32 certSz, listSz;
|
|
byte* output = 0;
|
|
|
|
if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
|
|
return 0; /* not needed */
|
|
|
|
if (ssl->options.sendVerify == SEND_BLANK_CERT) {
|
|
certSz = 0;
|
|
length = CERT_HEADER_SZ;
|
|
listSz = 0;
|
|
}
|
|
else {
|
|
certSz = ssl->buffers.certificate.length;
|
|
/* list + cert size */
|
|
length = certSz + 2 * CERT_HEADER_SZ;
|
|
listSz = certSz + CERT_HEADER_SZ;
|
|
|
|
/* may need to send rest of chain, already has leading size(s) */
|
|
if (ssl->buffers.certChain.buffer) {
|
|
length += ssl->buffers.certChain.length;
|
|
listSz += ssl->buffers.certChain.length;
|
|
}
|
|
}
|
|
sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn)
|
|
sendSz += MAX_MSG_EXTRA;
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, length, certificate, ssl);
|
|
|
|
/* list total */
|
|
c32to24(listSz, output + i);
|
|
i += CERT_HEADER_SZ;
|
|
|
|
/* member */
|
|
if (certSz) {
|
|
c32to24(certSz, output + i);
|
|
i += CERT_HEADER_SZ;
|
|
XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz);
|
|
i += certSz;
|
|
|
|
/* send rest of chain? */
|
|
if (ssl->buffers.certChain.buffer) {
|
|
XMEMCPY(output + i, ssl->buffers.certChain.buffer,
|
|
ssl->buffers.certChain.length);
|
|
i += ssl->buffers.certChain.length;
|
|
}
|
|
}
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
byte* input;
|
|
int inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */
|
|
|
|
input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (input == NULL)
|
|
return MEMORY_E;
|
|
|
|
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
|
|
sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake);
|
|
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
|
|
if (sendSz < 0)
|
|
return sendSz;
|
|
} else {
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
|
|
ssl->heap);
|
|
#endif
|
|
|
|
if (ssl->options.side == WOLFSSL_SERVER_END)
|
|
ssl->options.serverState = SERVER_CERT_COMPLETE;
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
return 0;
|
|
else
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
|
|
int SendCertificateRequest(WOLFSSL* ssl)
|
|
{
|
|
byte *output;
|
|
int ret;
|
|
int sendSz;
|
|
word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
|
|
int typeTotal = 1; /* only 1 for now */
|
|
int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */
|
|
|
|
if (IsAtLeastTLSv1_2(ssl))
|
|
reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz;
|
|
|
|
if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
|
|
return 0; /* not needed */
|
|
|
|
sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, reqSz, certificate_request, ssl);
|
|
|
|
/* write to output */
|
|
output[i++] = (byte)typeTotal; /* # of types */
|
|
#ifdef HAVE_ECC
|
|
if (ssl->options.cipherSuite0 == ECC_BYTE &&
|
|
ssl->specs.sig_algo == ecc_dsa_sa_algo) {
|
|
output[i++] = ecdsa_sign;
|
|
} else
|
|
#endif /* HAVE_ECC */
|
|
{
|
|
output[i++] = rsa_sign;
|
|
}
|
|
|
|
/* supported hash/sig */
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
c16toa(ssl->suites->hashSigAlgoSz, &output[i]);
|
|
i += LENGTH_SZ;
|
|
|
|
XMEMCPY(&output[i],
|
|
ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz);
|
|
i += ssl->suites->hashSigAlgoSz;
|
|
}
|
|
|
|
c16toa(0, &output[i]); /* auth's */
|
|
/* if add more to output, adjust i
|
|
i += REQ_HEADER_SZ; */
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("CertificateRequest", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
|
|
sendSz, ssl->heap);
|
|
#endif
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
return 0;
|
|
else
|
|
return SendBuffered(ssl);
|
|
}
|
|
#endif /* !NO_CERTS */
|
|
|
|
|
|
int SendData(WOLFSSL* ssl, const void* data, int sz)
|
|
{
|
|
int sent = 0, /* plainText size */
|
|
sendSz,
|
|
ret,
|
|
dtlsExtra = 0;
|
|
|
|
if (ssl->error == WANT_WRITE)
|
|
ssl->error = 0;
|
|
|
|
if (ssl->options.handShakeState != HANDSHAKE_DONE) {
|
|
int err;
|
|
WOLFSSL_MSG("handshake not complete, trying to finish");
|
|
if ( (err = wolfSSL_negotiate(ssl)) != SSL_SUCCESS)
|
|
return err;
|
|
}
|
|
|
|
/* last time system socket output buffer was full, try again to send */
|
|
if (ssl->buffers.outputBuffer.length > 0) {
|
|
WOLFSSL_MSG("output buffer was full, trying to send again");
|
|
if ( (ssl->error = SendBuffered(ssl)) < 0) {
|
|
WOLFSSL_ERROR(ssl->error);
|
|
if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset)
|
|
return 0; /* peer reset */
|
|
return ssl->error;
|
|
}
|
|
else {
|
|
/* advance sent to previous sent + plain size just sent */
|
|
sent = ssl->buffers.prevSent + ssl->buffers.plainSz;
|
|
WOLFSSL_MSG("sent write buffered data");
|
|
|
|
if (sent > sz) {
|
|
WOLFSSL_MSG("error: write() after WANT_WRITE with short size");
|
|
return ssl->error = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
dtlsExtra = DTLS_RECORD_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
for (;;) {
|
|
#ifdef HAVE_MAX_FRAGMENT
|
|
int len = min(sz - sent, min(ssl->max_fragment, OUTPUT_RECORD_SIZE));
|
|
#else
|
|
int len = min(sz - sent, OUTPUT_RECORD_SIZE);
|
|
#endif
|
|
byte* out;
|
|
byte* sendBuffer = (byte*)data + sent; /* may switch on comp */
|
|
int buffSz = len; /* may switch on comp */
|
|
int outputSz;
|
|
#ifdef HAVE_LIBZ
|
|
byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
|
|
#endif
|
|
|
|
if (sent == sz) break;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
len = min(len, MAX_UDP_SIZE);
|
|
buffSz = len;
|
|
}
|
|
#endif
|
|
|
|
/* check for available size */
|
|
outputSz = len + COMP_EXTRA + dtlsExtra + MAX_MSG_EXTRA;
|
|
if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
|
|
return ssl->error = ret;
|
|
|
|
/* get ouput buffer */
|
|
out = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
#ifdef HAVE_LIBZ
|
|
if (ssl->options.usingCompression) {
|
|
buffSz = myCompress(ssl, sendBuffer, buffSz, comp, sizeof(comp));
|
|
if (buffSz < 0) {
|
|
return buffSz;
|
|
}
|
|
sendBuffer = comp;
|
|
}
|
|
#endif
|
|
sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz,
|
|
application_data);
|
|
if (sendSz < 0)
|
|
return BUILD_MSG_ERROR;
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
if ( (ret = SendBuffered(ssl)) < 0) {
|
|
WOLFSSL_ERROR(ret);
|
|
/* store for next call if WANT_WRITE or user embedSend() that
|
|
doesn't present like WANT_WRITE */
|
|
ssl->buffers.plainSz = len;
|
|
ssl->buffers.prevSent = sent;
|
|
if (ret == SOCKET_ERROR_E && ssl->options.connReset)
|
|
return 0; /* peer reset */
|
|
return ssl->error = ret;
|
|
}
|
|
|
|
sent += len;
|
|
|
|
/* only one message per attempt */
|
|
if (ssl->options.partialWrite == 1) {
|
|
WOLFSSL_MSG("Paritial Write on, only sending one record");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sent;
|
|
}
|
|
|
|
/* process input data */
|
|
int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek)
|
|
{
|
|
int size;
|
|
|
|
WOLFSSL_ENTER("ReceiveData()");
|
|
|
|
if (ssl->error == WANT_READ)
|
|
ssl->error = 0;
|
|
|
|
if (ssl->error != 0 && ssl->error != WANT_WRITE) {
|
|
WOLFSSL_MSG("User calling wolfSSL_read in error state, not allowed");
|
|
return ssl->error;
|
|
}
|
|
|
|
if (ssl->options.handShakeState != HANDSHAKE_DONE) {
|
|
int err;
|
|
WOLFSSL_MSG("Handshake not complete, trying to finish");
|
|
if ( (err = wolfSSL_negotiate(ssl)) != SSL_SUCCESS)
|
|
return err;
|
|
}
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
startScr:
|
|
if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) {
|
|
int err;
|
|
ssl->secure_renegotiation->startScr = 0; /* only start once */
|
|
WOLFSSL_MSG("Need to start scr, server requested");
|
|
if ( (err = wolfSSL_Rehandshake(ssl)) != SSL_SUCCESS)
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
while (ssl->buffers.clearOutputBuffer.length == 0) {
|
|
if ( (ssl->error = ProcessReply(ssl)) < 0) {
|
|
WOLFSSL_ERROR(ssl->error);
|
|
if (ssl->error == ZERO_RETURN) {
|
|
WOLFSSL_MSG("Zero return, no more data coming");
|
|
return 0; /* no more data coming */
|
|
}
|
|
if (ssl->error == SOCKET_ERROR_E) {
|
|
if (ssl->options.connReset || ssl->options.isClosed) {
|
|
WOLFSSL_MSG("Peer reset or closed, connection done");
|
|
return 0; /* peer reset or closed */
|
|
}
|
|
}
|
|
return ssl->error;
|
|
}
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (ssl->secure_renegotiation &&
|
|
ssl->secure_renegotiation->startScr) {
|
|
goto startScr;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (sz < (int)ssl->buffers.clearOutputBuffer.length)
|
|
size = sz;
|
|
else
|
|
size = ssl->buffers.clearOutputBuffer.length;
|
|
|
|
XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size);
|
|
|
|
if (peek == 0) {
|
|
ssl->buffers.clearOutputBuffer.length -= size;
|
|
ssl->buffers.clearOutputBuffer.buffer += size;
|
|
}
|
|
|
|
if (ssl->buffers.clearOutputBuffer.length == 0 &&
|
|
ssl->buffers.inputBuffer.dynamicFlag)
|
|
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
|
|
|
|
WOLFSSL_LEAVE("ReceiveData()", size);
|
|
return size;
|
|
}
|
|
|
|
|
|
/* send alert message */
|
|
int SendAlert(WOLFSSL* ssl, int severity, int type)
|
|
{
|
|
byte input[ALERT_SIZE];
|
|
byte *output;
|
|
int sendSz;
|
|
int ret;
|
|
int outputSz;
|
|
int dtlsExtra = 0;
|
|
|
|
/* if sendalert is called again for nonbloking */
|
|
if (ssl->options.sendAlertState != 0) {
|
|
ret = SendBuffered(ssl);
|
|
if (ret == 0)
|
|
ssl->options.sendAlertState = 0;
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
dtlsExtra = DTLS_RECORD_EXTRA;
|
|
#endif
|
|
|
|
/* check for available size */
|
|
outputSz = ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra;
|
|
if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
input[0] = (byte)severity;
|
|
input[1] = (byte)type;
|
|
ssl->alert_history.last_tx.code = type;
|
|
ssl->alert_history.last_tx.level = severity;
|
|
if (severity == alert_fatal) {
|
|
ssl->options.isClosed = 1; /* Don't send close_notify */
|
|
}
|
|
|
|
/* only send encrypted alert if handshake actually complete, otherwise
|
|
other side may not be able to handle it */
|
|
if (ssl->keys.encryptionOn && ssl->options.handShakeDone)
|
|
sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert);
|
|
else {
|
|
|
|
AddRecordHeader(output, ALERT_SIZE, alert, ssl);
|
|
output += RECORD_HEADER_SZ;
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
output += DTLS_RECORD_EXTRA;
|
|
#endif
|
|
XMEMCPY(output, input, ALERT_SIZE);
|
|
|
|
sendSz = RECORD_HEADER_SZ + ALERT_SIZE;
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
sendSz += DTLS_RECORD_EXTRA;
|
|
#endif
|
|
}
|
|
if (sendSz < 0)
|
|
return BUILD_MSG_ERROR;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("Alert", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
ssl->options.sendAlertState = 1;
|
|
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
const char* wolfSSL_ERR_reason_error_string(unsigned long e)
|
|
{
|
|
#ifdef NO_ERROR_STRINGS
|
|
|
|
(void)e;
|
|
return "no support for error strings built in";
|
|
|
|
#else
|
|
|
|
int error = (int)e;
|
|
|
|
/* pass to wolfCrypt */
|
|
if (error < MAX_CODE_E && error > MIN_CODE_E) {
|
|
return wc_GetErrorString(error);
|
|
}
|
|
|
|
switch (error) {
|
|
|
|
case UNSUPPORTED_SUITE :
|
|
return "unsupported cipher suite";
|
|
|
|
case INPUT_CASE_ERROR :
|
|
return "input state error";
|
|
|
|
case PREFIX_ERROR :
|
|
return "bad index to key rounds";
|
|
|
|
case MEMORY_ERROR :
|
|
return "out of memory";
|
|
|
|
case VERIFY_FINISHED_ERROR :
|
|
return "verify problem on finished";
|
|
|
|
case VERIFY_MAC_ERROR :
|
|
return "verify mac problem";
|
|
|
|
case PARSE_ERROR :
|
|
return "parse error on header";
|
|
|
|
case SIDE_ERROR :
|
|
return "wrong client/server type";
|
|
|
|
case NO_PEER_CERT :
|
|
return "peer didn't send cert";
|
|
|
|
case UNKNOWN_HANDSHAKE_TYPE :
|
|
return "weird handshake type";
|
|
|
|
case SOCKET_ERROR_E :
|
|
return "error state on socket";
|
|
|
|
case SOCKET_NODATA :
|
|
return "expected data, not there";
|
|
|
|
case INCOMPLETE_DATA :
|
|
return "don't have enough data to complete task";
|
|
|
|
case UNKNOWN_RECORD_TYPE :
|
|
return "unknown type in record hdr";
|
|
|
|
case DECRYPT_ERROR :
|
|
return "error during decryption";
|
|
|
|
case FATAL_ERROR :
|
|
return "revcd alert fatal error";
|
|
|
|
case ENCRYPT_ERROR :
|
|
return "error during encryption";
|
|
|
|
case FREAD_ERROR :
|
|
return "fread problem";
|
|
|
|
case NO_PEER_KEY :
|
|
return "need peer's key";
|
|
|
|
case NO_PRIVATE_KEY :
|
|
return "need the private key";
|
|
|
|
case NO_DH_PARAMS :
|
|
return "server missing DH params";
|
|
|
|
case RSA_PRIVATE_ERROR :
|
|
return "error during rsa priv op";
|
|
|
|
case MATCH_SUITE_ERROR :
|
|
return "can't match cipher suite";
|
|
|
|
case BUILD_MSG_ERROR :
|
|
return "build message failure";
|
|
|
|
case BAD_HELLO :
|
|
return "client hello malformed";
|
|
|
|
case DOMAIN_NAME_MISMATCH :
|
|
return "peer subject name mismatch";
|
|
|
|
case WANT_READ :
|
|
case SSL_ERROR_WANT_READ :
|
|
return "non-blocking socket wants data to be read";
|
|
|
|
case NOT_READY_ERROR :
|
|
return "handshake layer not ready yet, complete first";
|
|
|
|
case PMS_VERSION_ERROR :
|
|
return "premaster secret version mismatch error";
|
|
|
|
case VERSION_ERROR :
|
|
return "record layer version error";
|
|
|
|
case WANT_WRITE :
|
|
case SSL_ERROR_WANT_WRITE :
|
|
return "non-blocking socket write buffer full";
|
|
|
|
case BUFFER_ERROR :
|
|
return "malformed buffer input error";
|
|
|
|
case VERIFY_CERT_ERROR :
|
|
return "verify problem on certificate";
|
|
|
|
case VERIFY_SIGN_ERROR :
|
|
return "verify problem based on signature";
|
|
|
|
case CLIENT_ID_ERROR :
|
|
return "psk client identity error";
|
|
|
|
case SERVER_HINT_ERROR:
|
|
return "psk server hint error";
|
|
|
|
case PSK_KEY_ERROR:
|
|
return "psk key callback error";
|
|
|
|
case NTRU_KEY_ERROR:
|
|
return "NTRU key error";
|
|
|
|
case NTRU_DRBG_ERROR:
|
|
return "NTRU drbg error";
|
|
|
|
case NTRU_ENCRYPT_ERROR:
|
|
return "NTRU encrypt error";
|
|
|
|
case NTRU_DECRYPT_ERROR:
|
|
return "NTRU decrypt error";
|
|
|
|
case ZLIB_INIT_ERROR:
|
|
return "zlib init error";
|
|
|
|
case ZLIB_COMPRESS_ERROR:
|
|
return "zlib compress error";
|
|
|
|
case ZLIB_DECOMPRESS_ERROR:
|
|
return "zlib decompress error";
|
|
|
|
case GETTIME_ERROR:
|
|
return "gettimeofday() error";
|
|
|
|
case GETITIMER_ERROR:
|
|
return "getitimer() error";
|
|
|
|
case SIGACT_ERROR:
|
|
return "sigaction() error";
|
|
|
|
case SETITIMER_ERROR:
|
|
return "setitimer() error";
|
|
|
|
case LENGTH_ERROR:
|
|
return "record layer length error";
|
|
|
|
case PEER_KEY_ERROR:
|
|
return "cant decode peer key";
|
|
|
|
case ZERO_RETURN:
|
|
case SSL_ERROR_ZERO_RETURN:
|
|
return "peer sent close notify alert";
|
|
|
|
case ECC_CURVETYPE_ERROR:
|
|
return "Bad ECC Curve Type or unsupported";
|
|
|
|
case ECC_CURVE_ERROR:
|
|
return "Bad ECC Curve or unsupported";
|
|
|
|
case ECC_PEERKEY_ERROR:
|
|
return "Bad ECC Peer Key";
|
|
|
|
case ECC_MAKEKEY_ERROR:
|
|
return "ECC Make Key failure";
|
|
|
|
case ECC_EXPORT_ERROR:
|
|
return "ECC Export Key failure";
|
|
|
|
case ECC_SHARED_ERROR:
|
|
return "ECC DHE shared failure";
|
|
|
|
case NOT_CA_ERROR:
|
|
return "Not a CA by basic constraint error";
|
|
|
|
case BAD_PATH_ERROR:
|
|
return "Bad path for opendir error";
|
|
|
|
case BAD_CERT_MANAGER_ERROR:
|
|
return "Bad Cert Manager error";
|
|
|
|
case OCSP_CERT_REVOKED:
|
|
return "OCSP Cert revoked";
|
|
|
|
case CRL_CERT_REVOKED:
|
|
return "CRL Cert revoked";
|
|
|
|
case CRL_MISSING:
|
|
return "CRL missing, not loaded";
|
|
|
|
case MONITOR_RUNNING_E:
|
|
return "CRL monitor already running";
|
|
|
|
case THREAD_CREATE_E:
|
|
return "Thread creation problem";
|
|
|
|
case OCSP_NEED_URL:
|
|
return "OCSP need URL";
|
|
|
|
case OCSP_CERT_UNKNOWN:
|
|
return "OCSP Cert unknown";
|
|
|
|
case OCSP_LOOKUP_FAIL:
|
|
return "OCSP Responder lookup fail";
|
|
|
|
case MAX_CHAIN_ERROR:
|
|
return "Maximum Chain Depth Exceeded";
|
|
|
|
case COOKIE_ERROR:
|
|
return "DTLS Cookie Error";
|
|
|
|
case SEQUENCE_ERROR:
|
|
return "DTLS Sequence Error";
|
|
|
|
case SUITES_ERROR:
|
|
return "Suites Pointer Error";
|
|
|
|
case SSL_NO_PEM_HEADER:
|
|
return "No PEM Header Error";
|
|
|
|
case OUT_OF_ORDER_E:
|
|
return "Out of order message, fatal";
|
|
|
|
case BAD_KEA_TYPE_E:
|
|
return "Bad KEA type found";
|
|
|
|
case SANITY_CIPHER_E:
|
|
return "Sanity check on ciphertext failed";
|
|
|
|
case RECV_OVERFLOW_E:
|
|
return "Receive callback returned more than requested";
|
|
|
|
case GEN_COOKIE_E:
|
|
return "Generate Cookie Error";
|
|
|
|
case NO_PEER_VERIFY:
|
|
return "Need peer certificate verify Error";
|
|
|
|
case FWRITE_ERROR:
|
|
return "fwrite Error";
|
|
|
|
case CACHE_MATCH_ERROR:
|
|
return "Cache restore header match Error";
|
|
|
|
case UNKNOWN_SNI_HOST_NAME_E:
|
|
return "Unrecognized host name Error";
|
|
|
|
case KEYUSE_SIGNATURE_E:
|
|
return "Key Use digitalSignature not set Error";
|
|
|
|
case KEYUSE_ENCIPHER_E:
|
|
return "Key Use keyEncipherment not set Error";
|
|
|
|
case EXTKEYUSE_AUTH_E:
|
|
return "Ext Key Use server/client auth not set Error";
|
|
|
|
case SEND_OOB_READ_E:
|
|
return "Send Callback Out of Bounds Read Error";
|
|
|
|
case SECURE_RENEGOTIATION_E:
|
|
return "Invalid Renegotiation Error";
|
|
|
|
case SESSION_TICKET_LEN_E:
|
|
return "Session Ticket Too Long Error";
|
|
|
|
case SESSION_TICKET_EXPECT_E:
|
|
return "Session Ticket Error";
|
|
|
|
case SCR_DIFFERENT_CERT_E:
|
|
return "Peer sent different cert during SCR";
|
|
|
|
case SESSION_SECRET_CB_E:
|
|
return "Session Secret Callback Error";
|
|
|
|
case NO_CHANGE_CIPHER_E:
|
|
return "Finished received from peer before Change Cipher Error";
|
|
|
|
case SANITY_MSG_E:
|
|
return "Sanity Check on message order Error";
|
|
|
|
case DUPLICATE_MSG_E:
|
|
return "Duplicate HandShake message Error";
|
|
|
|
default :
|
|
return "unknown error number";
|
|
}
|
|
|
|
#endif /* NO_ERROR_STRINGS */
|
|
}
|
|
|
|
void SetErrorString(int error, char* str)
|
|
{
|
|
XSTRNCPY(str, wolfSSL_ERR_reason_error_string(error), WOLFSSL_MAX_ERROR_SZ);
|
|
}
|
|
|
|
|
|
/* be sure to add to cipher_name_idx too !!!! */
|
|
static const char* const cipher_names[] =
|
|
{
|
|
#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
|
|
"RC4-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
|
|
"RC4-MD5",
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
|
|
"DES-CBC3-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
|
|
"AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
|
|
"AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
|
|
"NULL-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
|
|
"NULL-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
|
"DHE-RSA-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
|
|
"DHE-RSA-AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
|
|
"DHE-PSK-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
|
|
"DHE-PSK-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
|
|
"PSK-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
|
|
"PSK-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
|
|
"DHE-PSK-AES256-CBC-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
|
|
"DHE-PSK-AES128-CBC-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
|
|
"PSK-AES256-CBC-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
|
|
"PSK-AES128-CBC-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
|
|
"PSK-AES128-CBC-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
|
|
"PSK-AES256-CBC-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
|
|
"DHE-PSK-AES128-CCM",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
|
|
"DHE-PSK-AES256-CCM",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
|
|
"PSK-AES128-CCM",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
|
|
"PSK-AES256-CCM",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
|
|
"PSK-AES128-CCM-8",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
|
|
"PSK-AES256-CCM-8",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
|
|
"DHE-PSK-NULL-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
|
|
"DHE-PSK-NULL-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
|
|
"PSK-NULL-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
|
|
"PSK-NULL-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA
|
|
"PSK-NULL-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
|
|
"HC128-MD5",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
|
|
"HC128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
|
|
"HC128-B2B256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
|
|
"AES128-B2B256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
|
|
"AES256-B2B256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
|
|
"RABBIT-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
|
|
"NTRU-RC4-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
|
|
"NTRU-DES-CBC3-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
|
|
"NTRU-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
|
|
"NTRU-AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
|
|
"AES128-CCM-8",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
|
|
"AES256-CCM-8",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
|
|
"ECDHE-ECDSA-AES128-CCM-8",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
|
|
"ECDHE-ECDSA-AES256-CCM-8",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
|
"ECDHE-RSA-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
|
"ECDHE-RSA-AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
|
"ECDHE-ECDSA-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
|
"ECDHE-ECDSA-AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
|
|
"ECDHE-RSA-RC4-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
|
|
"ECDHE-RSA-DES-CBC3-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
|
|
"ECDHE-ECDSA-RC4-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
|
|
"ECDHE-ECDSA-DES-CBC3-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
|
|
"AES128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
|
|
"AES256-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
|
|
"DHE-RSA-AES128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
|
|
"DHE-RSA-AES256-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
|
|
"ECDH-RSA-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
|
|
"ECDH-RSA-AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
|
|
"ECDH-ECDSA-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
|
|
"ECDH-ECDSA-AES256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
|
|
"ECDH-RSA-RC4-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
|
|
"ECDH-RSA-DES-CBC3-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
|
|
"ECDH-ECDSA-RC4-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
|
|
"ECDH-ECDSA-DES-CBC3-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
|
|
"AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
|
|
"AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
|
|
"DHE-RSA-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
|
|
"DHE-RSA-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
"ECDHE-RSA-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
"ECDHE-RSA-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
|
"ECDHE-ECDSA-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
|
"ECDHE-ECDSA-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
|
|
"ECDH-RSA-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
|
|
"ECDH-RSA-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
|
|
"ECDH-ECDSA-AES128-GCM-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
|
|
"ECDH-ECDSA-AES256-GCM-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
|
|
"CAMELLIA128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
|
|
"DHE-RSA-CAMELLIA128-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
|
|
"CAMELLIA256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
|
|
"DHE-RSA-CAMELLIA256-SHA",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
|
"CAMELLIA128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
|
"DHE-RSA-CAMELLIA128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
|
"CAMELLIA256-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
|
"DHE-RSA-CAMELLIA256-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
|
|
"ECDHE-RSA-AES128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
|
|
"ECDHE-ECDSA-AES128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
|
|
"ECDH-RSA-AES128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
|
|
"ECDH-ECDSA-AES128-SHA256",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
|
|
"ECDHE-RSA-AES256-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
|
|
"ECDHE-ECDSA-AES256-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
|
|
"ECDH-RSA-AES256-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
|
|
"ECDH-ECDSA-AES256-SHA384",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
"ECDHE-RSA-CHACHA20-POLY1305",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
|
"ECDHE-ECDSA-CHACHA20-POLY1305",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
"DHE-RSA-CHACHA20-POLY1305",
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
|
|
"ADH-AES128-SHA",
|
|
#endif
|
|
|
|
#ifdef HAVE_RENEGOTIATION_INDICATION
|
|
"RENEGOTIATION-INFO",
|
|
#endif
|
|
};
|
|
|
|
|
|
/* cipher suite number that matches above name table */
|
|
static int cipher_name_idx[] =
|
|
{
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
|
|
SSL_RSA_WITH_RC4_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
|
|
SSL_RSA_WITH_RC4_128_MD5,
|
|
#endif
|
|
|
|
#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
|
|
SSL_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
|
|
TLS_RSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
|
|
TLS_RSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
|
|
TLS_RSA_WITH_NULL_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
|
|
TLS_RSA_WITH_NULL_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
|
TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
|
|
TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
|
|
TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
|
|
TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
|
|
TLS_PSK_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
|
|
TLS_PSK_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
|
|
TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
|
|
TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
|
|
TLS_PSK_WITH_AES_256_CBC_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
|
|
TLS_PSK_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
|
|
TLS_PSK_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
|
|
TLS_PSK_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
|
|
TLS_DHE_PSK_WITH_AES_128_CCM,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
|
|
TLS_DHE_PSK_WITH_AES_256_CCM,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
|
|
TLS_PSK_WITH_AES_128_CCM,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
|
|
TLS_PSK_WITH_AES_256_CCM,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
|
|
TLS_PSK_WITH_AES_128_CCM_8,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
|
|
TLS_PSK_WITH_AES_256_CCM_8,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
|
|
TLS_DHE_PSK_WITH_NULL_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
|
|
TLS_DHE_PSK_WITH_NULL_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
|
|
TLS_PSK_WITH_NULL_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
|
|
TLS_PSK_WITH_NULL_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_PSK_WITH_NULL_SHA
|
|
TLS_PSK_WITH_NULL_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
|
|
TLS_RSA_WITH_HC_128_MD5,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
|
|
TLS_RSA_WITH_HC_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
|
|
TLS_RSA_WITH_HC_128_B2B256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
|
|
TLS_RSA_WITH_AES_128_CBC_B2B256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
|
|
TLS_RSA_WITH_AES_256_CBC_B2B256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
|
|
TLS_RSA_WITH_RABBIT_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
|
|
TLS_NTRU_RSA_WITH_RC4_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
|
|
TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
|
|
TLS_NTRU_RSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
|
|
TLS_NTRU_RSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
|
|
TLS_RSA_WITH_AES_128_CCM_8,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
|
|
TLS_RSA_WITH_AES_256_CCM_8,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
|
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
|
|
TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
|
|
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
|
|
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
|
|
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
|
|
TLS_RSA_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
|
|
TLS_RSA_WITH_AES_256_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
|
|
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
|
|
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
|
|
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
|
|
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
|
|
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
|
|
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
|
|
TLS_ECDH_RSA_WITH_RC4_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
|
|
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
|
|
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
|
|
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
|
|
TLS_RSA_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
|
|
TLS_RSA_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
|
|
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
|
|
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
|
|
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
|
|
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
|
|
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
|
|
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
|
|
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
|
|
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
|
|
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
|
|
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
|
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
|
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
|
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
|
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
|
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
|
|
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
|
|
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
|
|
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
|
|
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
|
|
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
|
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
#endif
|
|
|
|
#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
|
|
TLS_DH_anon_WITH_AES_128_CBC_SHA,
|
|
#endif
|
|
|
|
#ifdef HAVE_RENEGOTIATION_INDICATION
|
|
TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
|
#endif
|
|
};
|
|
|
|
|
|
/* returns the cipher_names array */
|
|
const char* const* GetCipherNames(void)
|
|
{
|
|
return cipher_names;
|
|
}
|
|
|
|
|
|
/* returns the size of the cipher_names array */
|
|
int GetCipherNamesSize(void)
|
|
{
|
|
return (int)(sizeof(cipher_names) / sizeof(char*));
|
|
}
|
|
|
|
|
|
/**
|
|
Set the enabled cipher suites.
|
|
|
|
@param [out] suites Suites structure.
|
|
@param [in] list List of cipher suites, only supports full name from
|
|
cipher_name[] delimited by ':'.
|
|
|
|
@return true on success, else false.
|
|
*/
|
|
int SetCipherList(Suites* suites, const char* list)
|
|
{
|
|
int ret = 0;
|
|
int idx = 0;
|
|
int haveRSAsig = 0;
|
|
int haveECDSAsig = 0;
|
|
int haveAnon = 0;
|
|
const int suiteSz = GetCipherNamesSize();
|
|
char* next = (char*)list;
|
|
|
|
if (suites == NULL || list == NULL) {
|
|
WOLFSSL_MSG("SetCipherList parameter error");
|
|
return 0;
|
|
}
|
|
|
|
if (next[0] == 0 || XSTRNCMP(next, "ALL", 3) == 0)
|
|
return 1; /* wolfSSL defualt */
|
|
|
|
do {
|
|
char* current = next;
|
|
char name[MAX_SUITE_NAME + 1];
|
|
int i;
|
|
word32 length;
|
|
|
|
next = XSTRSTR(next, ":");
|
|
length = min(sizeof(name), !next ? (word32)XSTRLEN(current) /* last */
|
|
: (word32)(next - current));
|
|
|
|
XSTRNCPY(name, current, length);
|
|
name[(length == sizeof(name)) ? length - 1 : length] = 0;
|
|
|
|
for (i = 0; i < suiteSz; i++) {
|
|
if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) {
|
|
suites->suites[idx++] = (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE
|
|
: (XSTRSTR(name, "EC")) ? ECC_BYTE
|
|
: (XSTRSTR(name, "CCM")) ? ECC_BYTE
|
|
: 0x00; /* normal */
|
|
|
|
suites->suites[idx++] = (byte)cipher_name_idx[i];
|
|
|
|
/* The suites are either ECDSA, RSA, PSK, or Anon. The RSA
|
|
* suites don't necessarily have RSA in the name. */
|
|
if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA"))
|
|
haveECDSAsig = 1;
|
|
else if (XSTRSTR(name, "ADH"))
|
|
haveAnon = 1;
|
|
else if ((haveRSAsig == 0) && (XSTRSTR(name, "PSK") == NULL))
|
|
haveRSAsig = 1;
|
|
|
|
ret = 1; /* found at least one */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (next++); /* ++ needed to skip ':' */
|
|
|
|
if (ret) {
|
|
suites->setSuites = 1;
|
|
suites->suiteSz = (word16)idx;
|
|
InitSuitesHashSigAlgo(suites, haveECDSAsig, haveRSAsig, haveAnon);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void PickHashSigAlgo(WOLFSSL* ssl,
|
|
const byte* hashSigAlgo, word32 hashSigAlgoSz)
|
|
{
|
|
word32 i;
|
|
|
|
ssl->suites->sigAlgo = ssl->specs.sig_algo;
|
|
ssl->suites->hashAlgo = sha_mac;
|
|
|
|
/* i+1 since peek a byte ahead for type */
|
|
for (i = 0; (i+1) < hashSigAlgoSz; i += 2) {
|
|
if (hashSigAlgo[i+1] == ssl->specs.sig_algo) {
|
|
if (hashSigAlgo[i] == sha_mac) {
|
|
break;
|
|
}
|
|
#ifndef NO_SHA256
|
|
else if (hashSigAlgo[i] == sha256_mac) {
|
|
ssl->suites->hashAlgo = sha256_mac;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
else if (hashSigAlgo[i] == sha384_mac) {
|
|
ssl->suites->hashAlgo = sha384_mac;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
|
|
/* Initialisze HandShakeInfo */
|
|
void InitHandShakeInfo(HandShakeInfo* info)
|
|
{
|
|
int i;
|
|
|
|
info->cipherName[0] = 0;
|
|
for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
|
|
info->packetNames[i][0] = 0;
|
|
info->numberPackets = 0;
|
|
info->negotiationError = 0;
|
|
}
|
|
|
|
/* Set Final HandShakeInfo parameters */
|
|
void FinishHandShakeInfo(HandShakeInfo* info, const WOLFSSL* ssl)
|
|
{
|
|
int i;
|
|
int sz = sizeof(cipher_name_idx)/sizeof(int);
|
|
|
|
for (i = 0; i < sz; i++)
|
|
if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) {
|
|
if (ssl->options.cipherSuite0 == ECC_BYTE)
|
|
continue; /* ECC suites at end */
|
|
XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ);
|
|
break;
|
|
}
|
|
|
|
/* error max and min are negative numbers */
|
|
if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR)
|
|
info->negotiationError = ssl->error;
|
|
}
|
|
|
|
|
|
/* Add name to info packet names, increase packet name count */
|
|
void AddPacketName(const char* name, HandShakeInfo* info)
|
|
{
|
|
if (info->numberPackets < MAX_PACKETS_HANDSHAKE) {
|
|
XSTRNCPY(info->packetNames[info->numberPackets++], name,
|
|
MAX_PACKETNAME_SZ);
|
|
}
|
|
}
|
|
|
|
|
|
/* Initialisze TimeoutInfo */
|
|
void InitTimeoutInfo(TimeoutInfo* info)
|
|
{
|
|
int i;
|
|
|
|
info->timeoutName[0] = 0;
|
|
info->flags = 0;
|
|
|
|
for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) {
|
|
info->packets[i].packetName[0] = 0;
|
|
info->packets[i].timestamp.tv_sec = 0;
|
|
info->packets[i].timestamp.tv_usec = 0;
|
|
info->packets[i].bufferValue = 0;
|
|
info->packets[i].valueSz = 0;
|
|
}
|
|
info->numberPackets = 0;
|
|
info->timeoutValue.tv_sec = 0;
|
|
info->timeoutValue.tv_usec = 0;
|
|
}
|
|
|
|
|
|
/* Free TimeoutInfo */
|
|
void FreeTimeoutInfo(TimeoutInfo* info, void* heap)
|
|
{
|
|
int i;
|
|
(void)heap;
|
|
for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
|
|
if (info->packets[i].bufferValue) {
|
|
XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO);
|
|
info->packets[i].bufferValue = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Add PacketInfo to TimeoutInfo */
|
|
void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data,
|
|
int sz, void* heap)
|
|
{
|
|
if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) {
|
|
Timeval currTime;
|
|
|
|
/* may add name after */
|
|
if (name)
|
|
XSTRNCPY(info->packets[info->numberPackets].packetName, name,
|
|
MAX_PACKETNAME_SZ);
|
|
|
|
/* add data, put in buffer if bigger than static buffer */
|
|
info->packets[info->numberPackets].valueSz = sz;
|
|
if (sz < MAX_VALUE_SZ)
|
|
XMEMCPY(info->packets[info->numberPackets].value, data, sz);
|
|
else {
|
|
info->packets[info->numberPackets].bufferValue =
|
|
XMALLOC(sz, heap, DYNAMIC_TYPE_INFO);
|
|
if (!info->packets[info->numberPackets].bufferValue)
|
|
/* let next alloc catch, just don't fill, not fatal here */
|
|
info->packets[info->numberPackets].valueSz = 0;
|
|
else
|
|
XMEMCPY(info->packets[info->numberPackets].bufferValue,
|
|
data, sz);
|
|
}
|
|
gettimeofday(&currTime, 0);
|
|
info->packets[info->numberPackets].timestamp.tv_sec =
|
|
currTime.tv_sec;
|
|
info->packets[info->numberPackets].timestamp.tv_usec =
|
|
currTime.tv_usec;
|
|
info->numberPackets++;
|
|
}
|
|
}
|
|
|
|
|
|
/* Add packet name to previsouly added packet info */
|
|
void AddLateName(const char* name, TimeoutInfo* info)
|
|
{
|
|
/* make sure we have a valid previous one */
|
|
if (info->numberPackets > 0 && info->numberPackets <
|
|
MAX_PACKETS_HANDSHAKE) {
|
|
XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name,
|
|
MAX_PACKETNAME_SZ);
|
|
}
|
|
}
|
|
|
|
/* Add record header to previsouly added packet info */
|
|
void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info)
|
|
{
|
|
/* make sure we have a valid previous one */
|
|
if (info->numberPackets > 0 && info->numberPackets <
|
|
MAX_PACKETS_HANDSHAKE) {
|
|
if (info->packets[info->numberPackets - 1].bufferValue)
|
|
XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl,
|
|
RECORD_HEADER_SZ);
|
|
else
|
|
XMEMCPY(info->packets[info->numberPackets - 1].value, rl,
|
|
RECORD_HEADER_SZ);
|
|
}
|
|
}
|
|
|
|
#endif /* WOLFSSL_CALLBACKS */
|
|
|
|
|
|
|
|
/* client only parts */
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
|
|
int SendClientHello(WOLFSSL* ssl)
|
|
{
|
|
byte *output;
|
|
word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
int sendSz;
|
|
int idSz = ssl->options.resuming
|
|
? ssl->session.sessionIDSz
|
|
: 0;
|
|
int ret;
|
|
|
|
if (ssl->suites == NULL) {
|
|
WOLFSSL_MSG("Bad suites pointer in SendClientHello");
|
|
return SUITES_ERROR;
|
|
}
|
|
|
|
#ifdef HAVE_SESSION_TICKET
|
|
if (ssl->options.resuming && ssl->session.ticketLen > 0) {
|
|
SessionTicket* ticket;
|
|
|
|
ticket = TLSX_SessionTicket_Create(0,
|
|
ssl->session.ticket, ssl->session.ticketLen);
|
|
if (ticket == NULL) return MEMORY_E;
|
|
|
|
ret = TLSX_UseSessionTicket(&ssl->extensions, ticket);
|
|
if (ret != SSL_SUCCESS) return ret;
|
|
|
|
idSz = 0;
|
|
}
|
|
#endif
|
|
|
|
length = VERSION_SZ + RAN_LEN
|
|
+ idSz + ENUM_LEN
|
|
+ ssl->suites->suiteSz + SUITE_LEN
|
|
+ COMP_LEN + ENUM_LEN;
|
|
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
length += TLSX_GetRequestSize(ssl);
|
|
#else
|
|
if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) {
|
|
length += ssl->suites->hashSigAlgoSz + HELLO_EXT_SZ;
|
|
}
|
|
#endif
|
|
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
length += ENUM_LEN; /* cookie */
|
|
if (ssl->arrays->cookieSz != 0) length += ssl->arrays->cookieSz;
|
|
sendSz = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ;
|
|
idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn)
|
|
sendSz += MAX_MSG_EXTRA;
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, length, client_hello, ssl);
|
|
|
|
/* client hello, first version */
|
|
output[idx++] = ssl->version.major;
|
|
output[idx++] = ssl->version.minor;
|
|
ssl->chVersion = ssl->version; /* store in case changed */
|
|
|
|
/* then random */
|
|
if (ssl->options.connectState == CONNECT_BEGIN) {
|
|
ret = RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
/* store random */
|
|
XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN);
|
|
} else {
|
|
#ifdef WOLFSSL_DTLS
|
|
/* send same random on hello again */
|
|
XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN);
|
|
#endif
|
|
}
|
|
idx += RAN_LEN;
|
|
|
|
/* then session id */
|
|
output[idx++] = (byte)idSz;
|
|
if (idSz) {
|
|
XMEMCPY(output + idx, ssl->session.sessionID,
|
|
ssl->session.sessionIDSz);
|
|
idx += ssl->session.sessionIDSz;
|
|
}
|
|
|
|
/* then DTLS cookie */
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
byte cookieSz = ssl->arrays->cookieSz;
|
|
|
|
output[idx++] = cookieSz;
|
|
if (cookieSz) {
|
|
XMEMCPY(&output[idx], ssl->arrays->cookie, cookieSz);
|
|
idx += cookieSz;
|
|
}
|
|
}
|
|
#endif
|
|
/* then cipher suites */
|
|
c16toa(ssl->suites->suiteSz, output + idx);
|
|
idx += 2;
|
|
XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz);
|
|
idx += ssl->suites->suiteSz;
|
|
|
|
/* last, compression */
|
|
output[idx++] = COMP_LEN;
|
|
if (ssl->options.usingCompression)
|
|
output[idx++] = ZLIB_COMPRESSION;
|
|
else
|
|
output[idx++] = NO_COMPRESSION;
|
|
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
idx += TLSX_WriteRequest(ssl, output + idx);
|
|
|
|
(void)idx; /* suppress analyzer warning, keep idx current */
|
|
#else
|
|
if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
|
|
{
|
|
int i;
|
|
/* add in the extensions length */
|
|
c16toa(HELLO_EXT_LEN + ssl->suites->hashSigAlgoSz, output + idx);
|
|
idx += 2;
|
|
|
|
c16toa(HELLO_EXT_SIG_ALGO, output + idx);
|
|
idx += 2;
|
|
c16toa(HELLO_EXT_SIGALGO_SZ+ssl->suites->hashSigAlgoSz, output+idx);
|
|
idx += 2;
|
|
c16toa(ssl->suites->hashSigAlgoSz, output + idx);
|
|
idx += 2;
|
|
for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, idx++) {
|
|
output[idx] = ssl->suites->hashSigAlgo[i];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
byte* input;
|
|
int inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
|
|
|
|
input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (input == NULL)
|
|
return MEMORY_E;
|
|
|
|
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
|
|
sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake);
|
|
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
|
|
if (sendSz < 0)
|
|
return sendSz;
|
|
} else {
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz,
|
|
ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
|
|
static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input,
|
|
word32* inOutIdx, word32 size)
|
|
{
|
|
ProtocolVersion pv;
|
|
byte cookieSz;
|
|
word32 begin = *inOutIdx;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest",
|
|
&ssl->handShakeInfo);
|
|
if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
DtlsPoolReset(ssl);
|
|
}
|
|
#endif
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN + OPAQUE8_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(&pv, input + *inOutIdx, OPAQUE16_LEN);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
cookieSz = input[(*inOutIdx)++];
|
|
|
|
if (cookieSz) {
|
|
if ((*inOutIdx - begin) + cookieSz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (cookieSz <= MAX_COOKIE_LEN) {
|
|
XMEMCPY(ssl->arrays->cookie, input + *inOutIdx, cookieSz);
|
|
ssl->arrays->cookieSz = cookieSz;
|
|
}
|
|
#endif
|
|
*inOutIdx += cookieSz;
|
|
}
|
|
|
|
ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static INLINE int DSH_CheckSessionId(WOLFSSL* ssl)
|
|
{
|
|
int ret = 0;
|
|
|
|
#ifdef HAVE_SECRET_CALLBACK
|
|
/* If a session secret callback exists, we are using that
|
|
* key instead of the saved session key. */
|
|
ret = ret || (ssl->sessionSecretCb != NULL);
|
|
#endif
|
|
|
|
#ifdef HAVE_SESSION_TICKET
|
|
ret = ret ||
|
|
(!ssl->expect_session_ticket && ssl->session.ticketLen > 0);
|
|
#endif
|
|
|
|
ret = ret ||
|
|
(ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID,
|
|
ssl->session.sessionID, ID_LEN) == 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int DoServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|
word32 helloSz)
|
|
{
|
|
byte cs0; /* cipher suite bytes 0, 1 */
|
|
byte cs1;
|
|
ProtocolVersion pv;
|
|
byte compression;
|
|
word32 i = *inOutIdx;
|
|
word32 begin = i;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
/* protocol version, random and session id length check */
|
|
if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
/* protocol version */
|
|
XMEMCPY(&pv, input + i, OPAQUE16_LEN);
|
|
i += OPAQUE16_LEN;
|
|
|
|
if (pv.minor > ssl->version.minor) {
|
|
WOLFSSL_MSG("Server using higher version, fatal error");
|
|
return VERSION_ERROR;
|
|
}
|
|
else if (pv.minor < ssl->version.minor) {
|
|
WOLFSSL_MSG("server using lower version");
|
|
|
|
if (!ssl->options.downgrade) {
|
|
WOLFSSL_MSG(" no downgrade allowed, fatal error");
|
|
return VERSION_ERROR;
|
|
}
|
|
if (pv.minor < ssl->options.minDowngrade) {
|
|
WOLFSSL_MSG(" version below minimum allowed, fatal error");
|
|
return VERSION_ERROR;
|
|
}
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (ssl->secure_renegotiation &&
|
|
ssl->secure_renegotiation->enabled &&
|
|
ssl->options.handShakeDone) {
|
|
WOLFSSL_MSG("Server changed version during scr");
|
|
return VERSION_ERROR;
|
|
}
|
|
#endif
|
|
|
|
if (pv.minor == SSLv3_MINOR) {
|
|
/* turn off tls */
|
|
WOLFSSL_MSG(" downgrading to SSLv3");
|
|
ssl->options.tls = 0;
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->version.minor = SSLv3_MINOR;
|
|
}
|
|
else if (pv.minor == TLSv1_MINOR) {
|
|
/* turn off tls 1.1+ */
|
|
WOLFSSL_MSG(" downgrading to TLSv1");
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->version.minor = TLSv1_MINOR;
|
|
}
|
|
else if (pv.minor == TLSv1_1_MINOR) {
|
|
WOLFSSL_MSG(" downgrading to TLSv1.1");
|
|
ssl->version.minor = TLSv1_1_MINOR;
|
|
}
|
|
}
|
|
|
|
/* random */
|
|
XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN);
|
|
i += RAN_LEN;
|
|
|
|
/* session id */
|
|
ssl->arrays->sessionIDSz = input[i++];
|
|
|
|
if (ssl->arrays->sessionIDSz > ID_LEN) {
|
|
WOLFSSL_MSG("Invalid session ID size");
|
|
ssl->arrays->sessionIDSz = 0;
|
|
return BUFFER_ERROR;
|
|
}
|
|
else if (ssl->arrays->sessionIDSz) {
|
|
if ((i - begin) + ssl->arrays->sessionIDSz > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(ssl->arrays->sessionID, input + i,
|
|
ssl->arrays->sessionIDSz);
|
|
i += ssl->arrays->sessionIDSz;
|
|
ssl->options.haveSessionId = 1;
|
|
}
|
|
|
|
|
|
/* suite and compression */
|
|
if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
cs0 = input[i++];
|
|
cs1 = input[i++];
|
|
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
|
|
ssl->options.handShakeDone) {
|
|
if (ssl->options.cipherSuite0 != cs0 ||
|
|
ssl->options.cipherSuite != cs1) {
|
|
WOLFSSL_MSG("Server changed cipher suite during scr");
|
|
return MATCH_SUITE_ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ssl->options.cipherSuite0 = cs0;
|
|
ssl->options.cipherSuite = cs1;
|
|
compression = input[i++];
|
|
|
|
if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) {
|
|
WOLFSSL_MSG("Server refused compression, turning off");
|
|
ssl->options.usingCompression = 0; /* turn off if server refused */
|
|
}
|
|
|
|
*inOutIdx = i;
|
|
|
|
/* tls extensions */
|
|
if ( (i - begin) < helloSz) {
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
if (TLSX_SupportExtensions(ssl)) {
|
|
int ret = 0;
|
|
word16 totalExtSz;
|
|
|
|
if ((i - begin) + OPAQUE16_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(&input[i], &totalExtSz);
|
|
i += OPAQUE16_LEN;
|
|
|
|
if ((i - begin) + totalExtSz > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
if ((ret = TLSX_Parse(ssl, (byte *) input + i,
|
|
totalExtSz, 0, NULL)))
|
|
return ret;
|
|
|
|
i += totalExtSz;
|
|
*inOutIdx = i;
|
|
}
|
|
else
|
|
#endif
|
|
*inOutIdx = begin + helloSz; /* skip extensions */
|
|
}
|
|
|
|
ssl->options.serverState = SERVER_HELLO_COMPLETE;
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
|
|
#ifdef HAVE_SECRET_CALLBACK
|
|
if (ssl->sessionSecretCb != NULL) {
|
|
int secretSz = SECRET_LEN, ret;
|
|
ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret,
|
|
&secretSz, ssl->sessionSecretCtx);
|
|
if (ret != 0 || secretSz != SECRET_LEN)
|
|
return SESSION_SECRET_CB_E;
|
|
}
|
|
#endif /* HAVE_SECRET_CALLBACK */
|
|
|
|
if (ssl->options.resuming) {
|
|
if (DSH_CheckSessionId(ssl)) {
|
|
if (SetCipherSpecs(ssl) == 0) {
|
|
int ret = -1;
|
|
|
|
XMEMCPY(ssl->arrays->masterSecret,
|
|
ssl->session.masterSecret, SECRET_LEN);
|
|
#ifdef NO_OLD_TLS
|
|
ret = DeriveTlsKeys(ssl);
|
|
#else
|
|
#ifndef NO_TLS
|
|
if (ssl->options.tls)
|
|
ret = DeriveTlsKeys(ssl);
|
|
#endif
|
|
if (!ssl->options.tls)
|
|
ret = DeriveKeys(ssl);
|
|
#endif
|
|
ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
|
|
|
|
return ret;
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("Unsupported cipher suite, DoServerHello");
|
|
return UNSUPPORTED_SUITE;
|
|
}
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("Server denied resumption attempt");
|
|
ssl->options.resuming = 0; /* server denied resumption try */
|
|
}
|
|
}
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
DtlsPoolReset(ssl);
|
|
}
|
|
#endif
|
|
|
|
return SetCipherSpecs(ssl);
|
|
}
|
|
|
|
|
|
/* Make sure client setup is valid for this suite, true on success */
|
|
int VerifyClientSuite(WOLFSSL* ssl)
|
|
{
|
|
int havePSK = 0;
|
|
byte first = ssl->options.cipherSuite0;
|
|
byte second = ssl->options.cipherSuite;
|
|
|
|
WOLFSSL_ENTER("VerifyClientSuite");
|
|
|
|
#ifndef NO_PSK
|
|
havePSK = ssl->options.havePSK;
|
|
#endif
|
|
|
|
if (CipherRequires(first, second, REQUIRES_PSK)) {
|
|
WOLFSSL_MSG("Requires PSK");
|
|
if (havePSK == 0) {
|
|
WOLFSSL_MSG("Don't have PSK");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1; /* success */
|
|
}
|
|
|
|
|
|
#ifndef NO_CERTS
|
|
/* just read in and ignore for now TODO: */
|
|
static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32*
|
|
inOutIdx, word32 size)
|
|
{
|
|
word16 len;
|
|
word32 begin = *inOutIdx;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("CertificateRequest", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddLateName("CertificateRequest", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
len = input[(*inOutIdx)++];
|
|
|
|
if ((*inOutIdx - begin) + len > size)
|
|
return BUFFER_ERROR;
|
|
|
|
/* types, read in here */
|
|
*inOutIdx += len;
|
|
|
|
/* signature and hash signature algorithm */
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &len);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + len > size)
|
|
return BUFFER_ERROR;
|
|
|
|
PickHashSigAlgo(ssl, input + *inOutIdx, len);
|
|
*inOutIdx += len;
|
|
}
|
|
|
|
/* authorities */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &len);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + len > size)
|
|
return BUFFER_ERROR;
|
|
|
|
while (len) {
|
|
word16 dnSz;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &dnSz);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + dnSz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
*inOutIdx += dnSz;
|
|
len -= OPAQUE16_LEN + dnSz;
|
|
}
|
|
|
|
/* don't send client cert or cert verify if user hasn't provided
|
|
cert and private key */
|
|
if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer)
|
|
ssl->options.sendVerify = SEND_CERT;
|
|
else if (IsTLS(ssl))
|
|
ssl->options.sendVerify = SEND_BLANK_CERT;
|
|
|
|
if (ssl->keys.encryptionOn)
|
|
*inOutIdx += ssl->keys.padSz;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* !NO_CERTS */
|
|
|
|
|
|
static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
|
|
word32* inOutIdx, word32 size)
|
|
{
|
|
word16 length = 0;
|
|
word32 begin = *inOutIdx;
|
|
int ret = 0;
|
|
#define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0)
|
|
|
|
(void)length; /* shut up compiler warnings */
|
|
(void)begin;
|
|
(void)ssl;
|
|
(void)input;
|
|
(void)size;
|
|
(void)ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddLateName("ServerKeyExchange", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
#ifndef NO_PSK
|
|
if (ssl->specs.kea == psk_kea) {
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx,
|
|
min(length, MAX_PSK_ID_LEN));
|
|
|
|
ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0;
|
|
*inOutIdx += length;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
#ifndef NO_DH
|
|
if (ssl->specs.kea == diffie_hellman_kea)
|
|
{
|
|
/* p */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
|
|
if (ssl->buffers.serverDH_P.buffer)
|
|
ssl->buffers.serverDH_P.length = length;
|
|
else
|
|
return MEMORY_ERROR;
|
|
|
|
XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
|
|
/* g */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
|
|
if (ssl->buffers.serverDH_G.buffer)
|
|
ssl->buffers.serverDH_G.length = length;
|
|
else
|
|
return MEMORY_ERROR;
|
|
|
|
XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
|
|
/* pub */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
|
|
if (ssl->buffers.serverDH_Pub.buffer)
|
|
ssl->buffers.serverDH_Pub.length = length;
|
|
else
|
|
return MEMORY_ERROR;
|
|
|
|
XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
} /* dh_kea */
|
|
#endif /* NO_DH */
|
|
|
|
#ifdef HAVE_ECC
|
|
if (ssl->specs.kea == ecc_diffie_hellman_kea)
|
|
{
|
|
byte b;
|
|
|
|
if ((*inOutIdx - begin) + ENUM_LEN + OPAQUE16_LEN + OPAQUE8_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
b = input[(*inOutIdx)++];
|
|
|
|
if (b != named_curve)
|
|
return ECC_CURVETYPE_ERROR;
|
|
|
|
*inOutIdx += 1; /* curve type, eat leading 0 */
|
|
b = input[(*inOutIdx)++];
|
|
|
|
if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b !=
|
|
secp160r1 && b != secp192r1 && b != secp224r1)
|
|
return ECC_CURVE_ERROR;
|
|
|
|
length = input[(*inOutIdx)++];
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
if (ssl->peerEccKeyPresent) { /* don't leak on reuse */
|
|
ecc_free(ssl->peerEccKey);
|
|
ssl->peerEccKeyPresent = 0;
|
|
ecc_init(ssl->peerEccKey);
|
|
}
|
|
|
|
if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0)
|
|
return ECC_PEERKEY_ERROR;
|
|
|
|
*inOutIdx += length;
|
|
ssl->peerEccKeyPresent = 1;
|
|
}
|
|
#endif /* HAVE_ECC */
|
|
|
|
#if !defined(NO_DH) && !defined(NO_PSK)
|
|
if (ssl->specs.kea == dhe_psk_kea) {
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx,
|
|
min(length, MAX_PSK_ID_LEN));
|
|
|
|
ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0;
|
|
*inOutIdx += length;
|
|
|
|
/* p */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
|
|
if (ssl->buffers.serverDH_P.buffer)
|
|
ssl->buffers.serverDH_P.length = length;
|
|
else
|
|
return MEMORY_ERROR;
|
|
|
|
XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
|
|
/* g */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
|
|
if (ssl->buffers.serverDH_G.buffer)
|
|
ssl->buffers.serverDH_G.length = length;
|
|
else
|
|
return MEMORY_ERROR;
|
|
|
|
XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
|
|
/* pub */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
|
|
if (ssl->buffers.serverDH_Pub.buffer)
|
|
ssl->buffers.serverDH_Pub.length = length;
|
|
else
|
|
return MEMORY_ERROR;
|
|
|
|
XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
}
|
|
#endif /* !NO_DH || !NO_PSK */
|
|
|
|
#if !defined(NO_DH) || defined(HAVE_ECC)
|
|
if (!ssl->options.usingAnon_cipher &&
|
|
(ssl->specs.kea == ecc_diffie_hellman_kea ||
|
|
ssl->specs.kea == diffie_hellman_kea))
|
|
{
|
|
#ifndef NO_OLD_TLS
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Md5* md5 = NULL;
|
|
Sha* sha = NULL;
|
|
#else
|
|
Md5 md5[1];
|
|
Sha sha[1];
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Sha256* sha256 = NULL;
|
|
byte* hash256 = NULL;
|
|
#else
|
|
Sha256 sha256[1];
|
|
byte hash256[SHA256_DIGEST_SIZE];
|
|
#endif
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Sha384* sha384 = NULL;
|
|
byte* hash384 = NULL;
|
|
#else
|
|
Sha384 sha384[1];
|
|
byte hash384[SHA384_DIGEST_SIZE];
|
|
#endif
|
|
#endif
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* hash = NULL;
|
|
byte* messageVerify = NULL;
|
|
#else
|
|
byte hash[FINISHED_SZ];
|
|
byte messageVerify[MAX_DH_SZ];
|
|
#endif
|
|
byte hashAlgo = sha_mac;
|
|
byte sigAlgo = ssl->specs.sig_algo;
|
|
word16 verifySz = (word16) (*inOutIdx - begin);
|
|
|
|
/* save message for hash verify */
|
|
if (verifySz > MAX_DH_SZ)
|
|
ERROR_OUT(BUFFER_ERROR, done);
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
messageVerify = (byte*)XMALLOC(MAX_DH_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (messageVerify == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
|
|
XMEMCPY(messageVerify, input + begin, verifySz);
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
|
|
ERROR_OUT(BUFFER_ERROR, done);
|
|
|
|
hashAlgo = input[(*inOutIdx)++];
|
|
sigAlgo = input[(*inOutIdx)++];
|
|
}
|
|
|
|
/* signature */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
ERROR_OUT(BUFFER_ERROR, done);
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
ERROR_OUT(BUFFER_ERROR, done);
|
|
|
|
/* inOutIdx updated at the end of the function */
|
|
|
|
/* verify signature */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
hash = (byte*)XMALLOC(FINISHED_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (hash == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
|
|
#ifndef NO_OLD_TLS
|
|
/* md5 */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (md5 == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
InitMd5(md5);
|
|
Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN);
|
|
Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN);
|
|
Md5Update(md5, messageVerify, verifySz);
|
|
Md5Final(md5, hash);
|
|
|
|
/* sha */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
ret = InitSha(sha);
|
|
if (ret != 0)
|
|
goto done;
|
|
ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN);
|
|
ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN);
|
|
ShaUpdate(sha, messageVerify, verifySz);
|
|
ShaFinal(sha, hash + MD5_DIGEST_SIZE);
|
|
#endif
|
|
|
|
#ifndef NO_SHA256
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha256 == NULL || hash256 == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
if (!(ret = InitSha256(sha256))
|
|
&& !(ret = Sha256Update(sha256, ssl->arrays->clientRandom, RAN_LEN))
|
|
&& !(ret = Sha256Update(sha256, ssl->arrays->serverRandom, RAN_LEN))
|
|
&& !(ret = Sha256Update(sha256, messageVerify, verifySz)))
|
|
ret = Sha256Final(sha256, hash256);
|
|
if (ret != 0)
|
|
goto done;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SHA384
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha384 == NULL || hash384 == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
if (!(ret = InitSha384(sha384))
|
|
&& !(ret = Sha384Update(sha384, ssl->arrays->clientRandom, RAN_LEN))
|
|
&& !(ret = Sha384Update(sha384, ssl->arrays->serverRandom, RAN_LEN))
|
|
&& !(ret = Sha384Update(sha384, messageVerify, verifySz)))
|
|
ret = Sha384Final(sha384, hash384);
|
|
if (ret != 0)
|
|
goto done;
|
|
#endif
|
|
|
|
#ifndef NO_RSA
|
|
/* rsa */
|
|
if (sigAlgo == rsa_sa_algo)
|
|
{
|
|
byte* out = NULL;
|
|
byte doUserRsa = 0;
|
|
word32 verifiedSz = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->RsaVerifyCb)
|
|
doUserRsa = 1;
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
|
|
if (!ssl->peerRsaKeyPresent)
|
|
ERROR_OUT(NO_PEER_KEY, done);
|
|
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
verifiedSz = ssl->ctx->RsaVerifyCb(ssl,
|
|
(byte *)input + *inOutIdx,
|
|
length, &out,
|
|
ssl->buffers.peerRsaKey.buffer,
|
|
ssl->buffers.peerRsaKey.length,
|
|
ssl->RsaVerifyCtx);
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
else
|
|
verifiedSz = RsaSSL_VerifyInline((byte *)input + *inOutIdx,
|
|
length, &out, ssl->peerRsaKey);
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
word32 encSigSz;
|
|
#ifndef NO_OLD_TLS
|
|
byte* digest = &hash[MD5_DIGEST_SIZE];
|
|
int typeH = SHAh;
|
|
int digestSz = SHA_DIGEST_SIZE;
|
|
#else
|
|
byte* digest = hash256;
|
|
int typeH = SHA256h;
|
|
int digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* encodedSig = NULL;
|
|
#else
|
|
byte encodedSig[MAX_ENCODED_SIG_SZ];
|
|
#endif
|
|
|
|
if (hashAlgo == sha_mac) {
|
|
#ifndef NO_SHA
|
|
digest = &hash[MD5_DIGEST_SIZE];
|
|
typeH = SHAh;
|
|
digestSz = SHA_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = hash256;
|
|
typeH = SHA256h;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = hash384;
|
|
typeH = SHA384h;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (encodedSig == NULL)
|
|
ERROR_OUT(MEMORY_E, done);
|
|
#endif
|
|
|
|
encSigSz = EncodeSignature(encodedSig, digest, digestSz, typeH);
|
|
|
|
if (encSigSz != verifiedSz || !out || XMEMCMP(out, encodedSig,
|
|
min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0)
|
|
ret = VERIFY_SIGN_ERROR;
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
if (ret != 0)
|
|
goto done;
|
|
}
|
|
else if (verifiedSz != FINISHED_SZ || !out || XMEMCMP(out,
|
|
hash, FINISHED_SZ) != 0)
|
|
ERROR_OUT(VERIFY_SIGN_ERROR, done);
|
|
} else
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
/* ecdsa */
|
|
if (sigAlgo == ecc_dsa_sa_algo) {
|
|
int verify = 0;
|
|
#ifndef NO_OLD_TLS
|
|
byte* digest = &hash[MD5_DIGEST_SIZE];
|
|
word32 digestSz = SHA_DIGEST_SIZE;
|
|
#else
|
|
byte* digest = hash256;
|
|
word32 digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
byte doUserEcc = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->EccVerifyCb)
|
|
doUserEcc = 1;
|
|
#endif
|
|
|
|
if (!ssl->peerEccDsaKeyPresent)
|
|
ERROR_OUT(NO_PEER_KEY, done);
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if (hashAlgo == sha_mac) {
|
|
#ifndef NO_SHA
|
|
digest = &hash[MD5_DIGEST_SIZE];
|
|
digestSz = SHA_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = hash256;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = hash384;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
if (doUserEcc) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length,
|
|
digest, digestSz,
|
|
ssl->buffers.peerEccDsaKey.buffer,
|
|
ssl->buffers.peerEccDsaKey.length,
|
|
&verify, ssl->EccVerifyCtx);
|
|
#endif
|
|
}
|
|
else {
|
|
ret = ecc_verify_hash(input + *inOutIdx, length,
|
|
digest, digestSz, &verify, ssl->peerEccDsaKey);
|
|
}
|
|
if (ret != 0 || verify == 0)
|
|
ERROR_OUT(VERIFY_SIGN_ERROR, done);
|
|
}
|
|
else
|
|
#endif /* HAVE_ECC */
|
|
ERROR_OUT(ALGO_ID_E, done);
|
|
|
|
/* signature length */
|
|
*inOutIdx += length;
|
|
|
|
ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
|
|
|
|
done:
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
#ifndef NO_OLD_TLS
|
|
XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(messageVerify, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
|
|
return 0;
|
|
#else /* !NO_DH or HAVE_ECC */
|
|
return NOT_COMPILED_IN; /* not supported by build */
|
|
#endif /* !NO_DH or HAVE_ECC */
|
|
|
|
#undef ERROR_OUT
|
|
}
|
|
|
|
|
|
int SendClientKeyExchange(WOLFSSL* ssl)
|
|
{
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* encSecret = NULL;
|
|
#else
|
|
byte encSecret[MAX_ENCRYPT_SZ];
|
|
#endif
|
|
word32 encSz = 0;
|
|
word32 idx = 0;
|
|
int ret = 0;
|
|
byte doUserRsa = 0;
|
|
|
|
(void)doUserRsa;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifndef NO_RSA
|
|
if (ssl->ctx->RsaEncCb)
|
|
doUserRsa = 1;
|
|
#endif /* NO_RSA */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
encSecret = (byte*)XMALLOC(MAX_ENCRYPT_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (encSecret == NULL)
|
|
return MEMORY_E;
|
|
#endif
|
|
|
|
switch (ssl->specs.kea) {
|
|
#ifndef NO_RSA
|
|
case rsa_kea:
|
|
ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret,
|
|
SECRET_LEN);
|
|
if (ret != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
ssl->arrays->preMasterSecret[0] = ssl->chVersion.major;
|
|
ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor;
|
|
ssl->arrays->preMasterSz = SECRET_LEN;
|
|
|
|
if (ssl->peerRsaKeyPresent == 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifndef NO_RSA
|
|
encSz = MAX_ENCRYPT_SZ;
|
|
ret = ssl->ctx->RsaEncCb(ssl,
|
|
ssl->arrays->preMasterSecret,
|
|
SECRET_LEN,
|
|
encSecret, &encSz,
|
|
ssl->buffers.peerRsaKey.buffer,
|
|
ssl->buffers.peerRsaKey.length,
|
|
ssl->RsaEncCtx);
|
|
#endif /* NO_RSA */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
else {
|
|
ret = RsaPublicEncrypt(ssl->arrays->preMasterSecret,
|
|
SECRET_LEN, encSecret, MAX_ENCRYPT_SZ,
|
|
ssl->peerRsaKey, ssl->rng);
|
|
if (ret > 0) {
|
|
encSz = ret;
|
|
ret = 0; /* set success to 0 */
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
#ifndef NO_DH
|
|
case diffie_hellman_kea:
|
|
{
|
|
buffer serverP = ssl->buffers.serverDH_P;
|
|
buffer serverG = ssl->buffers.serverDH_G;
|
|
buffer serverPub = ssl->buffers.serverDH_Pub;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* priv = NULL;
|
|
#else
|
|
byte priv[ENCRYPT_LEN];
|
|
#endif
|
|
word32 privSz = 0;
|
|
DhKey key;
|
|
|
|
if (serverP.buffer == 0 || serverG.buffer == 0 ||
|
|
serverPub.buffer == 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
priv = (byte*)XMALLOC(ENCRYPT_LEN, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (priv == NULL) {
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
return MEMORY_E;
|
|
}
|
|
#endif
|
|
|
|
InitDhKey(&key);
|
|
ret = DhSetKey(&key, serverP.buffer, serverP.length,
|
|
serverG.buffer, serverG.length);
|
|
if (ret == 0)
|
|
/* for DH, encSecret is Yc, agree is pre-master */
|
|
ret = DhGenerateKeyPair(&key, ssl->rng, priv, &privSz,
|
|
encSecret, &encSz);
|
|
if (ret == 0)
|
|
ret = DhAgree(&key, ssl->arrays->preMasterSecret,
|
|
&ssl->arrays->preMasterSz, priv, privSz,
|
|
serverPub.buffer, serverPub.length);
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
FreeDhKey(&key);
|
|
}
|
|
break;
|
|
#endif /* NO_DH */
|
|
#ifndef NO_PSK
|
|
case psk_kea:
|
|
{
|
|
byte* pms = ssl->arrays->preMasterSecret;
|
|
|
|
ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
|
|
ssl->arrays->server_hint, ssl->arrays->client_identity,
|
|
MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
|
|
if (ssl->arrays->psk_keySz == 0 ||
|
|
ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return PSK_KEY_ERROR;
|
|
}
|
|
encSz = (word32)XSTRLEN(ssl->arrays->client_identity);
|
|
if (encSz > MAX_PSK_ID_LEN) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return CLIENT_ID_ERROR;
|
|
}
|
|
XMEMCPY(encSecret, ssl->arrays->client_identity, encSz);
|
|
|
|
/* make psk pre master secret */
|
|
/* length of key + length 0s + length of key + key */
|
|
c16toa((word16)ssl->arrays->psk_keySz, pms);
|
|
pms += 2;
|
|
XMEMSET(pms, 0, ssl->arrays->psk_keySz);
|
|
pms += ssl->arrays->psk_keySz;
|
|
c16toa((word16)ssl->arrays->psk_keySz, pms);
|
|
pms += 2;
|
|
XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
|
|
ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4;
|
|
XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
|
|
ssl->arrays->psk_keySz = 0; /* No further need */
|
|
}
|
|
break;
|
|
#endif /* NO_PSK */
|
|
#if !defined(NO_DH) && !defined(NO_PSK)
|
|
case dhe_psk_kea:
|
|
{
|
|
byte* pms = ssl->arrays->preMasterSecret;
|
|
byte* es = encSecret;
|
|
buffer serverP = ssl->buffers.serverDH_P;
|
|
buffer serverG = ssl->buffers.serverDH_G;
|
|
buffer serverPub = ssl->buffers.serverDH_Pub;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* priv = NULL;
|
|
#else
|
|
byte priv[ENCRYPT_LEN];
|
|
#endif
|
|
word32 privSz = 0;
|
|
word32 pubSz = 0;
|
|
word32 esSz = 0;
|
|
DhKey key;
|
|
|
|
if (serverP.buffer == 0 || serverG.buffer == 0 ||
|
|
serverPub.buffer == 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
|
|
ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
|
|
ssl->arrays->server_hint, ssl->arrays->client_identity,
|
|
MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
|
|
if (ssl->arrays->psk_keySz == 0 ||
|
|
ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return PSK_KEY_ERROR;
|
|
}
|
|
esSz = (word32)XSTRLEN(ssl->arrays->client_identity);
|
|
|
|
if (esSz > MAX_PSK_ID_LEN) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return CLIENT_ID_ERROR;
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
priv = (byte*)XMALLOC(ENCRYPT_LEN, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (priv == NULL) {
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
return MEMORY_E;
|
|
}
|
|
#endif
|
|
c16toa((word16)esSz, es);
|
|
es += OPAQUE16_LEN;
|
|
XMEMCPY(es, ssl->arrays->client_identity, esSz);
|
|
es += esSz;
|
|
encSz = esSz + OPAQUE16_LEN;
|
|
|
|
InitDhKey(&key);
|
|
ret = DhSetKey(&key, serverP.buffer, serverP.length,
|
|
serverG.buffer, serverG.length);
|
|
if (ret == 0)
|
|
/* for DH, encSecret is Yc, agree is pre-master */
|
|
ret = DhGenerateKeyPair(&key, ssl->rng, priv, &privSz,
|
|
es + OPAQUE16_LEN, &pubSz);
|
|
if (ret == 0)
|
|
ret = DhAgree(&key, pms + OPAQUE16_LEN,
|
|
&ssl->arrays->preMasterSz, priv, privSz,
|
|
serverPub.buffer, serverPub.length);
|
|
FreeDhKey(&key);
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
if (ret != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
c16toa((word16)pubSz, es);
|
|
encSz += pubSz + OPAQUE16_LEN;
|
|
c16toa((word16)ssl->arrays->preMasterSz, pms);
|
|
ssl->arrays->preMasterSz += OPAQUE16_LEN;
|
|
pms += ssl->arrays->preMasterSz;
|
|
|
|
/* make psk pre master secret */
|
|
/* length of key + length 0s + length of key + key */
|
|
c16toa((word16)ssl->arrays->psk_keySz, pms);
|
|
pms += OPAQUE16_LEN;
|
|
XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
|
|
ssl->arrays->preMasterSz +=
|
|
ssl->arrays->psk_keySz + OPAQUE16_LEN;
|
|
XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
|
|
ssl->arrays->psk_keySz = 0; /* No further need */
|
|
}
|
|
break;
|
|
#endif /* !NO_DH && !NO_PSK */
|
|
#ifdef HAVE_NTRU
|
|
case ntru_kea:
|
|
{
|
|
word32 rc;
|
|
word16 cipherLen = MAX_ENCRYPT_SZ;
|
|
DRBG_HANDLE drbg;
|
|
static uint8_t const wolfsslStr[] = {
|
|
'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U'
|
|
};
|
|
|
|
ret = RNG_GenerateBlock(ssl->rng,
|
|
ssl->arrays->preMasterSecret, SECRET_LEN);
|
|
if (ret != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
ssl->arrays->preMasterSz = SECRET_LEN;
|
|
|
|
if (ssl->peerNtruKeyPresent == 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
|
|
rc = ntru_crypto_drbg_instantiate(MAX_NTRU_BITS, wolfsslStr,
|
|
sizeof(wolfsslStr), GetEntropy,
|
|
&drbg);
|
|
if (rc != DRBG_OK) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NTRU_DRBG_ERROR;
|
|
}
|
|
|
|
rc = ntru_crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen,
|
|
ssl->peerNtruKey,
|
|
ssl->arrays->preMasterSz,
|
|
ssl->arrays->preMasterSecret,
|
|
&cipherLen, encSecret);
|
|
ntru_crypto_drbg_uninstantiate(drbg);
|
|
if (rc != NTRU_OK) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NTRU_ENCRYPT_ERROR;
|
|
}
|
|
|
|
encSz = cipherLen;
|
|
ret = 0;
|
|
}
|
|
break;
|
|
#endif /* HAVE_NTRU */
|
|
#ifdef HAVE_ECC
|
|
case ecc_diffie_hellman_kea:
|
|
{
|
|
ecc_key myKey;
|
|
ecc_key* peerKey = NULL;
|
|
word32 size = MAX_ENCRYPT_SZ;
|
|
|
|
if (ssl->specs.static_ecdh) {
|
|
/* TODO: EccDsa is really fixed Ecc change naming */
|
|
if (!ssl->peerEccDsaKeyPresent ||
|
|
!ssl->peerEccDsaKey->dp) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
peerKey = ssl->peerEccDsaKey;
|
|
}
|
|
else {
|
|
if (!ssl->peerEccKeyPresent || !ssl->peerEccKey->dp) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
peerKey = ssl->peerEccKey;
|
|
}
|
|
|
|
if (peerKey == NULL) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return NO_PEER_KEY;
|
|
}
|
|
|
|
ecc_init(&myKey);
|
|
ret = ecc_make_key(ssl->rng, peerKey->dp->size, &myKey);
|
|
if (ret != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ECC_MAKEKEY_ERROR;
|
|
}
|
|
|
|
/* precede export with 1 byte length */
|
|
ret = ecc_export_x963(&myKey, encSecret + 1, &size);
|
|
encSecret[0] = (byte)size;
|
|
encSz = size + 1;
|
|
|
|
if (ret != 0)
|
|
ret = ECC_EXPORT_ERROR;
|
|
else {
|
|
size = sizeof(ssl->arrays->preMasterSecret);
|
|
ret = ecc_shared_secret(&myKey, peerKey,
|
|
ssl->arrays->preMasterSecret, &size);
|
|
if (ret != 0)
|
|
ret = ECC_SHARED_ERROR;
|
|
}
|
|
|
|
ssl->arrays->preMasterSz = size;
|
|
ecc_free(&myKey);
|
|
}
|
|
break;
|
|
#endif /* HAVE_ECC */
|
|
default:
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ALGO_ID_E; /* unsupported kea */
|
|
}
|
|
|
|
if (ret == 0) {
|
|
byte *output;
|
|
int sendSz;
|
|
word32 tlsSz = 0;
|
|
|
|
if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea)
|
|
tlsSz = 2;
|
|
|
|
if (ssl->specs.kea == ecc_diffie_hellman_kea ||
|
|
ssl->specs.kea == dhe_psk_kea) /* always off */
|
|
tlsSz = 0;
|
|
|
|
sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
|
|
idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn)
|
|
sendSz += MAX_MSG_EXTRA;
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl);
|
|
|
|
if (tlsSz) {
|
|
c16toa((word16)encSz, &output[idx]);
|
|
idx += 2;
|
|
}
|
|
XMEMCPY(output + idx, encSecret, encSz);
|
|
idx += encSz;
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
byte* input;
|
|
int inputSz = idx-RECORD_HEADER_SZ; /* buildmsg adds rechdr */
|
|
|
|
input = (byte*)XMALLOC(inputSz, ssl->heap,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (input == NULL) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return MEMORY_E;
|
|
}
|
|
|
|
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
|
|
sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
|
|
handshake);
|
|
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sendSz < 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return sendSz;
|
|
}
|
|
} else {
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo,
|
|
output, sendSz, ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
if (ssl->options.groupMessages)
|
|
ret = 0;
|
|
else
|
|
ret = SendBuffered(ssl);
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
|
|
if (ret == 0 || ret == WANT_WRITE) {
|
|
int tmpRet = MakeMasterSecret(ssl);
|
|
if (tmpRet != 0)
|
|
ret = tmpRet; /* save WANT_WRITE unless more serious */
|
|
ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
|
|
}
|
|
/* No further need for PMS */
|
|
XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz);
|
|
ssl->arrays->preMasterSz = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifndef NO_CERTS
|
|
int SendCertificateVerify(WOLFSSL* ssl)
|
|
{
|
|
byte *output;
|
|
int sendSz = MAX_CERT_VERIFY_SZ, length, ret;
|
|
word32 idx = 0;
|
|
word32 sigOutSz = 0;
|
|
#ifndef NO_RSA
|
|
RsaKey key;
|
|
int initRsaKey = 0;
|
|
#endif
|
|
int usingEcc = 0;
|
|
#ifdef HAVE_ECC
|
|
ecc_key eccKey;
|
|
#endif
|
|
|
|
(void)idx;
|
|
|
|
if (ssl->options.sendVerify == SEND_BLANK_CERT)
|
|
return 0; /* sent blank cert, can't verify */
|
|
|
|
if (ssl->keys.encryptionOn)
|
|
sendSz += MAX_MSG_EXTRA;
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
ret = BuildCertHashes(ssl, &ssl->certHashes);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef HAVE_ECC
|
|
ecc_init(&eccKey);
|
|
#endif
|
|
#ifndef NO_RSA
|
|
ret = InitRsaKey(&key, ssl->heap);
|
|
if (ret == 0) initRsaKey = 1;
|
|
if (ret == 0)
|
|
ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
|
|
ssl->buffers.key.length);
|
|
if (ret == 0)
|
|
sigOutSz = RsaEncryptSize(&key);
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef HAVE_ECC
|
|
WOLFSSL_MSG("Trying ECC client cert, RSA didn't work");
|
|
|
|
idx = 0;
|
|
ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &eccKey,
|
|
ssl->buffers.key.length);
|
|
if (ret == 0) {
|
|
WOLFSSL_MSG("Using ECC client cert");
|
|
usingEcc = 1;
|
|
sigOutSz = MAX_ENCODED_SIG_SZ;
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("Bad client cert type");
|
|
}
|
|
#endif
|
|
}
|
|
if (ret == 0) {
|
|
byte* verify = (byte*)&output[RECORD_HEADER_SZ +
|
|
HANDSHAKE_HEADER_SZ];
|
|
#ifndef NO_OLD_TLS
|
|
byte* signBuffer = ssl->certHashes.md5;
|
|
#else
|
|
byte* signBuffer = NULL;
|
|
#endif
|
|
word32 signSz = FINISHED_SZ;
|
|
word32 extraSz = 0; /* tls 1.2 hash/sig */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* encodedSig = NULL;
|
|
#else
|
|
byte encodedSig[MAX_ENCODED_SIG_SZ];
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (encodedSig == NULL) {
|
|
#ifndef NO_RSA
|
|
if (initRsaKey)
|
|
FreeRsaKey(&key);
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
ecc_free(&eccKey);
|
|
#endif
|
|
return MEMORY_E;
|
|
}
|
|
#endif
|
|
|
|
(void)encodedSig;
|
|
(void)signSz;
|
|
(void)signBuffer;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
#endif
|
|
length = sigOutSz;
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
verify[0] = ssl->suites->hashAlgo;
|
|
verify[1] = usingEcc ? ecc_dsa_sa_algo : rsa_sa_algo;
|
|
extraSz = HASH_SIG_SIZE;
|
|
}
|
|
|
|
if (usingEcc) {
|
|
#ifdef HAVE_ECC
|
|
word32 localSz = MAX_ENCODED_SIG_SZ;
|
|
word32 digestSz;
|
|
byte* digest;
|
|
byte doUserEcc = 0;
|
|
#ifndef NO_OLD_TLS
|
|
/* old tls default */
|
|
digestSz = SHA_DIGEST_SIZE;
|
|
digest = ssl->certHashes.sha;
|
|
#else
|
|
/* new tls default */
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
digest = ssl->certHashes.sha256;
|
|
#endif
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
if (ssl->ctx->EccSignCb)
|
|
doUserEcc = 1;
|
|
#endif /* HAVE_ECC */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if (ssl->suites->hashAlgo == sha_mac) {
|
|
#ifndef NO_SHA
|
|
digest = ssl->certHashes.sha;
|
|
digestSz = SHA_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = ssl->certHashes.sha256;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = ssl->certHashes.sha384;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (doUserEcc) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifdef HAVE_ECC
|
|
ret = ssl->ctx->EccSignCb(ssl, digest, digestSz,
|
|
encodedSig, &localSz,
|
|
ssl->buffers.key.buffer,
|
|
ssl->buffers.key.length,
|
|
ssl->EccSignCtx);
|
|
#endif /* HAVE_ECC */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
else {
|
|
ret = ecc_sign_hash(digest, digestSz, encodedSig,
|
|
&localSz, ssl->rng, &eccKey);
|
|
}
|
|
if (ret == 0) {
|
|
length = localSz;
|
|
c16toa((word16)length, verify + extraSz); /* prepend hdr */
|
|
XMEMCPY(verify + extraSz + VERIFY_HEADER,encodedSig,length);
|
|
}
|
|
#endif
|
|
}
|
|
#ifndef NO_RSA
|
|
else {
|
|
byte doUserRsa = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->RsaSignCb)
|
|
doUserRsa = 1;
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
#ifndef NO_OLD_TLS
|
|
byte* digest = ssl->certHashes.sha;
|
|
int digestSz = SHA_DIGEST_SIZE;
|
|
int typeH = SHAh;
|
|
#else
|
|
byte* digest = ssl->certHashes.sha256;
|
|
int digestSz = SHA256_DIGEST_SIZE;
|
|
int typeH = SHA256h;
|
|
#endif
|
|
|
|
if (ssl->suites->hashAlgo == sha_mac) {
|
|
#ifndef NO_SHA
|
|
digest = ssl->certHashes.sha;
|
|
typeH = SHAh;
|
|
digestSz = SHA_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = ssl->certHashes.sha256;
|
|
typeH = SHA256h;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = ssl->certHashes.sha384;
|
|
typeH = SHA384h;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
|
|
signSz = EncodeSignature(encodedSig, digest,digestSz,typeH);
|
|
signBuffer = encodedSig;
|
|
}
|
|
|
|
c16toa((word16)length, verify + extraSz); /* prepend hdr */
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
#ifndef NO_RSA
|
|
word32 ioLen = ENCRYPT_LEN;
|
|
ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
|
|
verify + extraSz + VERIFY_HEADER,
|
|
&ioLen,
|
|
ssl->buffers.key.buffer,
|
|
ssl->buffers.key.length,
|
|
ssl->RsaSignCtx);
|
|
#endif /* NO_RSA */
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
else {
|
|
ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz +
|
|
VERIFY_HEADER, ENCRYPT_LEN, &key, ssl->rng);
|
|
}
|
|
|
|
if (ret > 0)
|
|
ret = 0; /* RSA reset */
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
AddHeaders(output, length + extraSz + VERIFY_HEADER,
|
|
certificate_verify, ssl);
|
|
|
|
sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length +
|
|
extraSz + VERIFY_HEADER;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
byte* input;
|
|
int inputSz = sendSz - RECORD_HEADER_SZ;
|
|
/* build msg adds rec hdr */
|
|
input = (byte*)XMALLOC(inputSz, ssl->heap,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (input == NULL)
|
|
ret = MEMORY_E;
|
|
else {
|
|
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
|
|
sendSz = BuildMessage(ssl, output,
|
|
MAX_CERT_VERIFY_SZ +MAX_MSG_EXTRA,
|
|
input, inputSz, handshake);
|
|
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
|
|
if (sendSz < 0)
|
|
ret = sendSz;
|
|
}
|
|
} else {
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#ifndef NO_RSA
|
|
if (initRsaKey)
|
|
FreeRsaKey(&key);
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
ecc_free(&eccKey);
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("CertificateVerify", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
|
|
output, sendSz, ssl->heap);
|
|
#endif
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
return 0;
|
|
else
|
|
return SendBuffered(ssl);
|
|
}
|
|
else
|
|
return ret;
|
|
}
|
|
#endif /* NO_CERTS */
|
|
|
|
#ifdef HAVE_SESSION_TICKET
|
|
int DoSessionTicket(WOLFSSL* ssl,
|
|
const byte* input, word32* inOutIdx, word32 size)
|
|
{
|
|
word32 begin = *inOutIdx;
|
|
word32 lifetime;
|
|
word16 length;
|
|
|
|
if (ssl->expect_session_ticket == 0) {
|
|
WOLFSSL_MSG("Unexpected session ticket");
|
|
return SESSION_TICKET_EXPECT_E;
|
|
}
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE32_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato32(input + *inOutIdx, &lifetime);
|
|
*inOutIdx += OPAQUE32_LEN;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &length);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if (length > sizeof(ssl->session.ticket))
|
|
return SESSION_TICKET_LEN_E;
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
/* If the received ticket including its length is greater than
|
|
* a length value, the save it. Otherwise, don't save it. */
|
|
if (length > 0) {
|
|
XMEMCPY(ssl->session.ticket, input + *inOutIdx, length);
|
|
*inOutIdx += length;
|
|
ssl->session.ticketLen = length;
|
|
ssl->timeout = lifetime;
|
|
if (ssl->session_ticket_cb != NULL) {
|
|
ssl->session_ticket_cb(ssl,
|
|
ssl->session.ticket, ssl->session.ticketLen,
|
|
ssl->session_ticket_ctx);
|
|
}
|
|
/* Create a fake sessionID based on the ticket, this will
|
|
* supercede the existing session cache info. */
|
|
ssl->options.haveSessionId = 1;
|
|
XMEMCPY(ssl->arrays->sessionID,
|
|
ssl->session.ticket + length - ID_LEN, ID_LEN);
|
|
#ifndef NO_SESSION_CACHE
|
|
AddSession(ssl);
|
|
#endif
|
|
|
|
}
|
|
else {
|
|
ssl->session.ticketLen = 0;
|
|
}
|
|
|
|
if (ssl->keys.encryptionOn) {
|
|
*inOutIdx += ssl->keys.padSz;
|
|
}
|
|
|
|
ssl->expect_session_ticket = 0;
|
|
|
|
return BuildFinished(ssl, &ssl->verifyHashes, server);
|
|
}
|
|
#endif /* HAVE_SESSION_TICKET */
|
|
|
|
#endif /* NO_WOLFSSL_CLIENT */
|
|
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
|
|
int SendServerHello(WOLFSSL* ssl)
|
|
{
|
|
byte *output;
|
|
word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
int sendSz;
|
|
int ret;
|
|
|
|
length = VERSION_SZ + RAN_LEN
|
|
+ ID_LEN + ENUM_LEN
|
|
+ SUITE_LEN
|
|
+ ENUM_LEN;
|
|
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
length += TLSX_GetResponseSize(ssl);
|
|
#endif
|
|
|
|
/* check for avalaible size */
|
|
if ((ret = CheckAvailableSize(ssl, MAX_HELLO_SZ)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
AddHeaders(output, length, server_hello, ssl);
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
/* now write to output */
|
|
/* first version */
|
|
output[idx++] = ssl->version.major;
|
|
output[idx++] = ssl->version.minor;
|
|
|
|
/* then random */
|
|
if (!ssl->options.resuming) {
|
|
ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
|
|
RAN_LEN);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
XMEMCPY(output + idx, ssl->arrays->serverRandom, RAN_LEN);
|
|
idx += RAN_LEN;
|
|
|
|
#ifdef SHOW_SECRETS
|
|
{
|
|
int j;
|
|
printf("server random: ");
|
|
for (j = 0; j < RAN_LEN; j++)
|
|
printf("%02x", ssl->arrays->serverRandom[j]);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
/* then session id */
|
|
output[idx++] = ID_LEN;
|
|
|
|
if (!ssl->options.resuming) {
|
|
ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, ID_LEN);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
XMEMCPY(output + idx, ssl->arrays->sessionID, ID_LEN);
|
|
idx += ID_LEN;
|
|
|
|
/* then cipher suite */
|
|
output[idx++] = ssl->options.cipherSuite0;
|
|
output[idx++] = ssl->options.cipherSuite;
|
|
|
|
/* then compression */
|
|
if (ssl->options.usingCompression)
|
|
output[idx++] = ZLIB_COMPRESSION;
|
|
else
|
|
output[idx++] = NO_COMPRESSION;
|
|
|
|
/* last, extensions */
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
TLSX_WriteResponse(ssl, output + idx);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerHello", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
|
|
ssl->heap);
|
|
#endif
|
|
|
|
ssl->options.serverState = SERVER_HELLO_COMPLETE;
|
|
|
|
if (ssl->options.groupMessages)
|
|
return 0;
|
|
else
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
|
|
#ifdef HAVE_ECC
|
|
|
|
static byte SetCurveId(int size)
|
|
{
|
|
switch(size) {
|
|
case 20:
|
|
return secp160r1;
|
|
case 24:
|
|
return secp192r1;
|
|
case 28:
|
|
return secp224r1;
|
|
case 32:
|
|
return secp256r1;
|
|
case 48:
|
|
return secp384r1;
|
|
case 66:
|
|
return secp521r1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#endif /* HAVE_ECC */
|
|
|
|
|
|
int SendServerKeyExchange(WOLFSSL* ssl)
|
|
{
|
|
int ret = 0;
|
|
(void)ssl;
|
|
#define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0)
|
|
|
|
#ifndef NO_PSK
|
|
if (ssl->specs.kea == psk_kea)
|
|
{
|
|
byte *output;
|
|
word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
int sendSz;
|
|
if (ssl->arrays->server_hint[0] == 0) return 0; /* don't send */
|
|
|
|
/* include size part */
|
|
length = (word32)XSTRLEN(ssl->arrays->server_hint);
|
|
if (length > MAX_PSK_ID_LEN)
|
|
return SERVER_HINT_ERROR;
|
|
|
|
length += HINT_LEN_SZ;
|
|
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, length, server_key_exchange, ssl);
|
|
|
|
/* key data */
|
|
c16toa((word16)(length - HINT_LEN_SZ), output + idx);
|
|
idx += HINT_LEN_SZ;
|
|
XMEMCPY(output + idx, ssl->arrays->server_hint,length -HINT_LEN_SZ);
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
#endif
|
|
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output,
|
|
sendSz, ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
ret = 0;
|
|
else
|
|
ret = SendBuffered(ssl);
|
|
ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
|
|
}
|
|
#endif /*NO_PSK */
|
|
|
|
#if !defined(NO_DH) && !defined(NO_PSK)
|
|
if (ssl->specs.kea == dhe_psk_kea) {
|
|
byte *output;
|
|
word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
word32 hintLen;
|
|
int sendSz;
|
|
DhKey dhKey;
|
|
|
|
if (ssl->buffers.serverDH_P.buffer == NULL ||
|
|
ssl->buffers.serverDH_G.buffer == NULL)
|
|
return NO_DH_PARAMS;
|
|
|
|
if (ssl->buffers.serverDH_Pub.buffer == NULL) {
|
|
ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC(
|
|
ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
if (ssl->buffers.serverDH_Pub.buffer == NULL)
|
|
return MEMORY_E;
|
|
}
|
|
|
|
if (ssl->buffers.serverDH_Priv.buffer == NULL) {
|
|
ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC(
|
|
ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
if (ssl->buffers.serverDH_Priv.buffer == NULL)
|
|
return MEMORY_E;
|
|
}
|
|
|
|
InitDhKey(&dhKey);
|
|
ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
|
|
ssl->buffers.serverDH_P.length,
|
|
ssl->buffers.serverDH_G.buffer,
|
|
ssl->buffers.serverDH_G.length);
|
|
if (ret == 0)
|
|
ret = DhGenerateKeyPair(&dhKey, ssl->rng,
|
|
ssl->buffers.serverDH_Priv.buffer,
|
|
&ssl->buffers.serverDH_Priv.length,
|
|
ssl->buffers.serverDH_Pub.buffer,
|
|
&ssl->buffers.serverDH_Pub.length);
|
|
FreeDhKey(&dhKey);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
length = LENGTH_SZ * 3 + /* p, g, pub */
|
|
ssl->buffers.serverDH_P.length +
|
|
ssl->buffers.serverDH_G.length +
|
|
ssl->buffers.serverDH_Pub.length;
|
|
|
|
/* include size part */
|
|
hintLen = (word32)XSTRLEN(ssl->arrays->server_hint);
|
|
if (hintLen > MAX_PSK_ID_LEN)
|
|
return SERVER_HINT_ERROR;
|
|
length += hintLen + HINT_LEN_SZ;
|
|
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
}
|
|
#endif
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, length, server_key_exchange, ssl);
|
|
|
|
/* key data */
|
|
c16toa((word16)hintLen, output + idx);
|
|
idx += HINT_LEN_SZ;
|
|
XMEMCPY(output + idx, ssl->arrays->server_hint, hintLen);
|
|
idx += hintLen;
|
|
|
|
/* add p, g, pub */
|
|
c16toa((word16)ssl->buffers.serverDH_P.length, output + idx);
|
|
idx += LENGTH_SZ;
|
|
XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer,
|
|
ssl->buffers.serverDH_P.length);
|
|
idx += ssl->buffers.serverDH_P.length;
|
|
|
|
/* g */
|
|
c16toa((word16)ssl->buffers.serverDH_G.length, output + idx);
|
|
idx += LENGTH_SZ;
|
|
XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer,
|
|
ssl->buffers.serverDH_G.length);
|
|
idx += ssl->buffers.serverDH_G.length;
|
|
|
|
/* pub */
|
|
c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx);
|
|
idx += LENGTH_SZ;
|
|
XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer,
|
|
ssl->buffers.serverDH_Pub.length);
|
|
idx += ssl->buffers.serverDH_Pub.length;
|
|
(void)idx; /* suppress analyzer warning, and keep idx current */
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
#endif
|
|
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output,
|
|
sendSz, ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
ret = 0;
|
|
else
|
|
ret = SendBuffered(ssl);
|
|
ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
|
|
}
|
|
#endif /* !NO_DH && !NO_PSK */
|
|
|
|
#ifdef HAVE_ECC
|
|
if (ssl->specs.kea == ecc_diffie_hellman_kea)
|
|
{
|
|
byte *output;
|
|
word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
int sendSz;
|
|
word32 sigSz;
|
|
word32 preSigSz, preSigIdx;
|
|
#ifndef NO_RSA
|
|
RsaKey rsaKey;
|
|
#endif
|
|
ecc_key dsaKey;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* exportBuf = NULL;
|
|
#else
|
|
byte exportBuf[MAX_EXPORT_ECC_SZ];
|
|
#endif
|
|
word32 expSz = MAX_EXPORT_ECC_SZ;
|
|
|
|
if (ssl->specs.static_ecdh) {
|
|
WOLFSSL_MSG("Using Static ECDH, not sending ServerKeyExchagne");
|
|
return 0;
|
|
}
|
|
|
|
/* curve type, named curve, length(1) */
|
|
length = ENUM_LEN + CURVE_LEN + ENUM_LEN;
|
|
/* pub key size */
|
|
WOLFSSL_MSG("Using ephemeral ECDH");
|
|
|
|
/* need ephemeral key now, create it if missing */
|
|
if (ssl->eccTempKeyPresent == 0) {
|
|
if (ecc_make_key(ssl->rng, ssl->eccTempKeySz,
|
|
ssl->eccTempKey) != 0) {
|
|
return ECC_MAKEKEY_ERROR;
|
|
}
|
|
ssl->eccTempKeyPresent = 1;
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
exportBuf = (byte*)XMALLOC(MAX_EXPORT_ECC_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (exportBuf == NULL)
|
|
return MEMORY_E;
|
|
#endif
|
|
|
|
if (ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0)
|
|
ERROR_OUT(ECC_EXPORT_ERROR, done_a);
|
|
length += expSz;
|
|
|
|
preSigSz = length;
|
|
preSigIdx = idx;
|
|
|
|
#ifndef NO_RSA
|
|
ret = InitRsaKey(&rsaKey, ssl->heap);
|
|
if (ret != 0)
|
|
goto done_a;
|
|
#endif
|
|
|
|
ecc_init(&dsaKey);
|
|
|
|
/* sig length */
|
|
length += LENGTH_SZ;
|
|
|
|
if (!ssl->buffers.key.buffer) {
|
|
#ifndef NO_RSA
|
|
FreeRsaKey(&rsaKey);
|
|
#endif
|
|
ecc_free(&dsaKey);
|
|
ERROR_OUT(NO_PRIVATE_KEY, done_a);
|
|
}
|
|
|
|
#ifndef NO_RSA
|
|
if (ssl->specs.sig_algo == rsa_sa_algo) {
|
|
/* rsa sig size */
|
|
word32 i = 0;
|
|
ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i,
|
|
&rsaKey, ssl->buffers.key.length);
|
|
if (ret != 0)
|
|
goto done_a;
|
|
sigSz = RsaEncryptSize(&rsaKey);
|
|
} else
|
|
#endif
|
|
|
|
if (ssl->specs.sig_algo == ecc_dsa_sa_algo) {
|
|
/* ecdsa sig size */
|
|
word32 i = 0;
|
|
ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
|
|
&dsaKey, ssl->buffers.key.length);
|
|
if (ret != 0)
|
|
goto done_a;
|
|
sigSz = ecc_sig_size(&dsaKey); /* worst case estimate */
|
|
}
|
|
else {
|
|
#ifndef NO_RSA
|
|
FreeRsaKey(&rsaKey);
|
|
#endif
|
|
ecc_free(&dsaKey);
|
|
ERROR_OUT(ALGO_ID_E, done_a); /* unsupported type */
|
|
}
|
|
length += sigSz;
|
|
|
|
if (IsAtLeastTLSv1_2(ssl))
|
|
length += HASH_SIG_SIZE;
|
|
|
|
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
preSigIdx = idx;
|
|
}
|
|
#endif
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
|
|
#ifndef NO_RSA
|
|
FreeRsaKey(&rsaKey);
|
|
#endif
|
|
ecc_free(&dsaKey);
|
|
goto done_a;
|
|
}
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
/* record and message headers will be added below, when we're sure
|
|
of the sig length */
|
|
|
|
/* key exchange data */
|
|
output[idx++] = named_curve;
|
|
output[idx++] = 0x00; /* leading zero */
|
|
output[idx++] = SetCurveId(ecc_size(ssl->eccTempKey));
|
|
output[idx++] = (byte)expSz;
|
|
XMEMCPY(output + idx, exportBuf, expSz);
|
|
idx += expSz;
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
output[idx++] = ssl->suites->hashAlgo;
|
|
output[idx++] = ssl->suites->sigAlgo;
|
|
}
|
|
|
|
/* Signtaure length will be written later, when we're sure what it
|
|
is */
|
|
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, FUZZ_SIGNATURE,
|
|
ssl->fuzzerCtx);
|
|
#endif
|
|
|
|
/* do signature */
|
|
{
|
|
#ifndef NO_OLD_TLS
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Md5* md5 = NULL;
|
|
Sha* sha = NULL;
|
|
#else
|
|
Md5 md5[1];
|
|
Sha sha[1];
|
|
#endif
|
|
#endif
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* hash = NULL;
|
|
#else
|
|
byte hash[FINISHED_SZ];
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Sha256* sha256 = NULL;
|
|
byte* hash256 = NULL;
|
|
#else
|
|
Sha256 sha256[1];
|
|
byte hash256[SHA256_DIGEST_SIZE];
|
|
#endif
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Sha384* sha384 = NULL;
|
|
byte* hash384 = NULL;
|
|
#else
|
|
Sha384 sha384[1];
|
|
byte hash384[SHA384_DIGEST_SIZE];
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
hash = (byte*)XMALLOC(FINISHED_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (hash == NULL)
|
|
ERROR_OUT(MEMORY_E, done_a);
|
|
#endif
|
|
|
|
#ifndef NO_OLD_TLS
|
|
/* md5 */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (md5 == NULL)
|
|
ERROR_OUT(MEMORY_E, done_a2);
|
|
#endif
|
|
InitMd5(md5);
|
|
Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN);
|
|
Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN);
|
|
Md5Update(md5, output + preSigIdx, preSigSz);
|
|
Md5Final(md5, hash);
|
|
|
|
/* sha */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha == NULL)
|
|
ERROR_OUT(MEMORY_E, done_a2);
|
|
#endif
|
|
ret = InitSha(sha);
|
|
if (ret != 0)
|
|
goto done_a2;
|
|
ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN);
|
|
ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN);
|
|
ShaUpdate(sha, output + preSigIdx, preSigSz);
|
|
ShaFinal(sha, &hash[MD5_DIGEST_SIZE]);
|
|
#endif
|
|
|
|
#ifndef NO_SHA256
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha256 == NULL || hash256 == NULL)
|
|
ERROR_OUT(MEMORY_E, done_a2);
|
|
#endif
|
|
|
|
if (!(ret = InitSha256(sha256))
|
|
&& !(ret = Sha256Update(sha256, ssl->arrays->clientRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha256Update(sha256, ssl->arrays->serverRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha256Update(sha256, output + preSigIdx, preSigSz)))
|
|
ret = Sha256Final(sha256, hash256);
|
|
|
|
if (ret != 0)
|
|
goto done_a2;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SHA384
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha384 == NULL || hash384 == NULL)
|
|
ERROR_OUT(MEMORY_E, done_a2);
|
|
#endif
|
|
|
|
if (!(ret = InitSha384(sha384))
|
|
&& !(ret = Sha384Update(sha384, ssl->arrays->clientRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha384Update(sha384, ssl->arrays->serverRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha384Update(sha384, output + preSigIdx, preSigSz)))
|
|
ret = Sha384Final(sha384, hash384);
|
|
|
|
if (ret != 0)
|
|
goto done_a2;
|
|
#endif
|
|
|
|
#ifndef NO_RSA
|
|
if (ssl->suites->sigAlgo == rsa_sa_algo) {
|
|
byte* signBuffer = hash;
|
|
word32 signSz = FINISHED_SZ;
|
|
byte doUserRsa = 0;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* encodedSig = NULL;
|
|
#else
|
|
byte encodedSig[MAX_ENCODED_SIG_SZ];
|
|
#endif
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->RsaSignCb)
|
|
doUserRsa = 1;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (encodedSig == NULL)
|
|
ERROR_OUT(MEMORY_E, done_a2);
|
|
#endif
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
byte* digest = &hash[MD5_DIGEST_SIZE];
|
|
int typeH = SHAh;
|
|
int digestSz = SHA_DIGEST_SIZE;
|
|
|
|
if (ssl->suites->hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = hash256;
|
|
typeH = SHA256h;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = hash384;
|
|
typeH = SHA384h;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
|
|
signSz = EncodeSignature(encodedSig, digest, digestSz,
|
|
typeH);
|
|
signBuffer = encodedSig;
|
|
}
|
|
/* write sig size here */
|
|
c16toa((word16)sigSz, output + idx);
|
|
idx += LENGTH_SZ;
|
|
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
word32 ioLen = sigSz;
|
|
ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
|
|
output + idx, &ioLen,
|
|
ssl->buffers.key.buffer,
|
|
ssl->buffers.key.length,
|
|
ssl->RsaSignCtx);
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
else
|
|
ret = RsaSSL_Sign(signBuffer, signSz, output + idx,
|
|
sigSz, &rsaKey, ssl->rng);
|
|
|
|
FreeRsaKey(&rsaKey);
|
|
ecc_free(&dsaKey);
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
|
|
if (ret < 0)
|
|
goto done_a2;
|
|
} else
|
|
#endif
|
|
|
|
if (ssl->suites->sigAlgo == ecc_dsa_sa_algo) {
|
|
#ifndef NO_OLD_TLS
|
|
byte* digest = &hash[MD5_DIGEST_SIZE];
|
|
word32 digestSz = SHA_DIGEST_SIZE;
|
|
#else
|
|
byte* digest = hash256;
|
|
word32 digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
word32 sz = sigSz;
|
|
byte doUserEcc = 0;
|
|
|
|
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
|
|
if (ssl->ctx->EccSignCb)
|
|
doUserEcc = 1;
|
|
#endif
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if (ssl->suites->hashAlgo == sha_mac) {
|
|
#ifndef NO_SHA
|
|
digest = &hash[MD5_DIGEST_SIZE];
|
|
digestSz = SHA_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = hash256;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = hash384;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (doUserEcc) {
|
|
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
|
|
ret = ssl->ctx->EccSignCb(ssl, digest, digestSz,
|
|
output + LENGTH_SZ + idx, &sz,
|
|
ssl->buffers.key.buffer,
|
|
ssl->buffers.key.length,
|
|
ssl->EccSignCtx);
|
|
#endif
|
|
}
|
|
else {
|
|
ret = ecc_sign_hash(digest, digestSz,
|
|
output + LENGTH_SZ + idx, &sz, ssl->rng, &dsaKey);
|
|
}
|
|
#ifndef NO_RSA
|
|
FreeRsaKey(&rsaKey);
|
|
#endif
|
|
ecc_free(&dsaKey);
|
|
|
|
if (ret < 0)
|
|
goto done_a2;
|
|
|
|
/* Now that we know the real sig size, write it. */
|
|
c16toa((word16)sz, output + idx);
|
|
|
|
/* And adjust length and sendSz from estimates */
|
|
length += sz - sigSz;
|
|
sendSz += sz - sigSz;
|
|
}
|
|
|
|
done_a2:
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
#ifndef NO_OLD_TLS
|
|
XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#ifndef NO_SHA256
|
|
XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#endif
|
|
|
|
if (ret < 0)
|
|
goto done_a;
|
|
}
|
|
|
|
AddHeaders(output, length, server_key_exchange, ssl);
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
goto done_a;
|
|
#endif
|
|
|
|
if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0)
|
|
goto done_a;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
|
|
output, sendSz, ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
ret = 0;
|
|
else
|
|
ret = SendBuffered(ssl);
|
|
ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
|
|
|
|
done_a:
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_ECC */
|
|
|
|
#if !defined(NO_DH) && !defined(NO_RSA)
|
|
if (ssl->specs.kea == diffie_hellman_kea) {
|
|
byte *output;
|
|
word32 length = 0, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
int sendSz;
|
|
word32 sigSz = 0, i = 0;
|
|
word32 preSigSz = 0, preSigIdx = 0;
|
|
RsaKey rsaKey;
|
|
DhKey dhKey;
|
|
|
|
if (ssl->buffers.serverDH_P.buffer == NULL ||
|
|
ssl->buffers.serverDH_G.buffer == NULL)
|
|
return NO_DH_PARAMS;
|
|
|
|
if (ssl->buffers.serverDH_Pub.buffer == NULL) {
|
|
ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC(
|
|
ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
if (ssl->buffers.serverDH_Pub.buffer == NULL)
|
|
return MEMORY_E;
|
|
}
|
|
|
|
if (ssl->buffers.serverDH_Priv.buffer == NULL) {
|
|
ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC(
|
|
ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
|
|
DYNAMIC_TYPE_DH);
|
|
if (ssl->buffers.serverDH_Priv.buffer == NULL)
|
|
return MEMORY_E;
|
|
}
|
|
|
|
InitDhKey(&dhKey);
|
|
ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
|
|
ssl->buffers.serverDH_P.length,
|
|
ssl->buffers.serverDH_G.buffer,
|
|
ssl->buffers.serverDH_G.length);
|
|
if (ret == 0)
|
|
ret = DhGenerateKeyPair(&dhKey, ssl->rng,
|
|
ssl->buffers.serverDH_Priv.buffer,
|
|
&ssl->buffers.serverDH_Priv.length,
|
|
ssl->buffers.serverDH_Pub.buffer,
|
|
&ssl->buffers.serverDH_Pub.length);
|
|
FreeDhKey(&dhKey);
|
|
|
|
if (ret != 0) return ret;
|
|
|
|
length = LENGTH_SZ * 3; /* p, g, pub */
|
|
length += ssl->buffers.serverDH_P.length +
|
|
ssl->buffers.serverDH_G.length +
|
|
ssl->buffers.serverDH_Pub.length;
|
|
|
|
preSigIdx = idx;
|
|
preSigSz = length;
|
|
|
|
if (!ssl->options.usingAnon_cipher) {
|
|
ret = InitRsaKey(&rsaKey, ssl->heap);
|
|
if (ret != 0) return ret;
|
|
|
|
/* sig length */
|
|
length += LENGTH_SZ;
|
|
|
|
if (!ssl->buffers.key.buffer)
|
|
return NO_PRIVATE_KEY;
|
|
|
|
ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, &rsaKey,
|
|
ssl->buffers.key.length);
|
|
if (ret == 0) {
|
|
sigSz = RsaEncryptSize(&rsaKey);
|
|
length += sigSz;
|
|
}
|
|
else {
|
|
FreeRsaKey(&rsaKey);
|
|
return ret;
|
|
}
|
|
|
|
if (IsAtLeastTLSv1_2(ssl))
|
|
length += HASH_SIG_SIZE;
|
|
}
|
|
|
|
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
preSigIdx = idx;
|
|
}
|
|
#endif
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
|
|
if (!ssl->options.usingAnon_cipher)
|
|
FreeRsaKey(&rsaKey);
|
|
return ret;
|
|
}
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, length, server_key_exchange, ssl);
|
|
|
|
/* add p, g, pub */
|
|
c16toa((word16)ssl->buffers.serverDH_P.length, output + idx);
|
|
idx += LENGTH_SZ;
|
|
XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer,
|
|
ssl->buffers.serverDH_P.length);
|
|
idx += ssl->buffers.serverDH_P.length;
|
|
|
|
/* g */
|
|
c16toa((word16)ssl->buffers.serverDH_G.length, output + idx);
|
|
idx += LENGTH_SZ;
|
|
XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer,
|
|
ssl->buffers.serverDH_G.length);
|
|
idx += ssl->buffers.serverDH_G.length;
|
|
|
|
/* pub */
|
|
c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx);
|
|
idx += LENGTH_SZ;
|
|
XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer,
|
|
ssl->buffers.serverDH_Pub.length);
|
|
idx += ssl->buffers.serverDH_Pub.length;
|
|
|
|
#ifdef HAVE_FUZZER
|
|
if (ssl->fuzzerCb)
|
|
ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, FUZZ_SIGNATURE,
|
|
ssl->fuzzerCtx);
|
|
#endif
|
|
|
|
/* Add signature */
|
|
if (!ssl->options.usingAnon_cipher) {
|
|
#ifndef NO_OLD_TLS
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Md5* md5 = NULL;
|
|
Sha* sha = NULL;
|
|
#else
|
|
Md5 md5[1];
|
|
Sha sha[1];
|
|
#endif
|
|
#endif
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* hash = NULL;
|
|
#else
|
|
byte hash[FINISHED_SZ];
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Sha256* sha256 = NULL;
|
|
byte* hash256 = NULL;
|
|
#else
|
|
Sha256 sha256[1];
|
|
byte hash256[SHA256_DIGEST_SIZE];
|
|
#endif
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
Sha384* sha384 = NULL;
|
|
byte* hash384 = NULL;
|
|
#else
|
|
Sha384 sha384[1];
|
|
byte hash384[SHA384_DIGEST_SIZE];
|
|
#endif
|
|
#endif
|
|
|
|
/* Add hash/signature algo ID */
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
output[idx++] = ssl->suites->hashAlgo;
|
|
output[idx++] = ssl->suites->sigAlgo;
|
|
}
|
|
|
|
/* signature size */
|
|
c16toa((word16)sigSz, output + idx);
|
|
idx += LENGTH_SZ;
|
|
|
|
/* do signature */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
hash = (byte*)XMALLOC(FINISHED_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (hash == NULL)
|
|
return MEMORY_E; /* No heap commitment before this point,
|
|
from now on, the resources are freed
|
|
at done_b. */
|
|
#endif
|
|
|
|
#ifndef NO_OLD_TLS
|
|
/* md5 */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (md5 == NULL)
|
|
ERROR_OUT(MEMORY_E, done_b);
|
|
#endif
|
|
InitMd5(md5);
|
|
Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN);
|
|
Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN);
|
|
Md5Update(md5, output + preSigIdx, preSigSz);
|
|
Md5Final(md5, hash);
|
|
|
|
/* sha */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha == NULL)
|
|
ERROR_OUT(MEMORY_E, done_b);
|
|
#endif
|
|
|
|
if ((ret = InitSha(sha)) != 0)
|
|
goto done_b;
|
|
|
|
ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN);
|
|
ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN);
|
|
ShaUpdate(sha, output + preSigIdx, preSigSz);
|
|
ShaFinal(sha, &hash[MD5_DIGEST_SIZE]);
|
|
#endif
|
|
|
|
#ifndef NO_SHA256
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha256 == NULL || hash256 == NULL)
|
|
ERROR_OUT(MEMORY_E, done_b);
|
|
#endif
|
|
|
|
if (!(ret = InitSha256(sha256))
|
|
&& !(ret = Sha256Update(sha256, ssl->arrays->clientRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha256Update(sha256, ssl->arrays->serverRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha256Update(sha256, output + preSigIdx, preSigSz)))
|
|
ret = Sha256Final(sha256, hash256);
|
|
|
|
if (ret != 0)
|
|
goto done_b;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SHA384
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (sha384 == NULL || hash384 == NULL)
|
|
ERROR_OUT(MEMORY_E, done_b);
|
|
#endif
|
|
|
|
if (!(ret = InitSha384(sha384))
|
|
&& !(ret = Sha384Update(sha384, ssl->arrays->clientRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha384Update(sha384, ssl->arrays->serverRandom,
|
|
RAN_LEN))
|
|
&& !(ret = Sha384Update(sha384, output + preSigIdx, preSigSz)))
|
|
ret = Sha384Final(sha384, hash384);
|
|
|
|
if (ret != 0)
|
|
goto done_b;
|
|
#endif
|
|
|
|
#ifndef NO_RSA
|
|
if (ssl->suites->sigAlgo == rsa_sa_algo) {
|
|
byte* signBuffer = hash;
|
|
word32 signSz = FINISHED_SZ;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* encodedSig = NULL;
|
|
#else
|
|
byte encodedSig[MAX_ENCODED_SIG_SZ];
|
|
#endif
|
|
byte doUserRsa = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->RsaSignCb)
|
|
doUserRsa = 1;
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (encodedSig == NULL)
|
|
ERROR_OUT(MEMORY_E, done_b);
|
|
#endif
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
byte* digest = &hash[MD5_DIGEST_SIZE];
|
|
int typeH = SHAh;
|
|
int digestSz = SHA_DIGEST_SIZE;
|
|
|
|
if (ssl->suites->hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = hash256;
|
|
typeH = SHA256h;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (ssl->suites->hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = hash384;
|
|
typeH = SHA384h;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
|
|
signSz = EncodeSignature(encodedSig, digest, digestSz,
|
|
typeH);
|
|
signBuffer = encodedSig;
|
|
}
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
word32 ioLen = sigSz;
|
|
ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
|
|
output + idx, &ioLen,
|
|
ssl->buffers.key.buffer,
|
|
ssl->buffers.key.length,
|
|
ssl->RsaSignCtx);
|
|
#endif
|
|
}
|
|
else
|
|
ret = RsaSSL_Sign(signBuffer, signSz, output + idx,
|
|
sigSz, &rsaKey, ssl->rng);
|
|
|
|
FreeRsaKey(&rsaKey);
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
done_b:
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
#ifndef NO_OLD_TLS
|
|
XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#ifndef NO_SHA256
|
|
XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
#endif
|
|
|
|
if (ret < 0) return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return ret;
|
|
#endif
|
|
|
|
if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
|
|
output, sendSz, ssl->heap);
|
|
#endif
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
if (ssl->options.groupMessages)
|
|
ret = 0;
|
|
else
|
|
ret = SendBuffered(ssl);
|
|
ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
|
|
}
|
|
#endif /* NO_DH */
|
|
|
|
return ret;
|
|
#undef ERROR_OUT
|
|
}
|
|
|
|
|
|
/* Make sure server cert/key are valid for this suite, true on success */
|
|
static int VerifyServerSuite(WOLFSSL* ssl, word16 idx)
|
|
{
|
|
int haveRSA = !ssl->options.haveStaticECC;
|
|
int havePSK = 0;
|
|
byte first;
|
|
byte second;
|
|
|
|
WOLFSSL_ENTER("VerifyServerSuite");
|
|
|
|
if (ssl->suites == NULL) {
|
|
WOLFSSL_MSG("Suites pointer error");
|
|
return 0;
|
|
}
|
|
|
|
first = ssl->suites->suites[idx];
|
|
second = ssl->suites->suites[idx+1];
|
|
|
|
#ifndef NO_PSK
|
|
havePSK = ssl->options.havePSK;
|
|
#endif
|
|
|
|
if (ssl->options.haveNTRU)
|
|
haveRSA = 0;
|
|
|
|
if (CipherRequires(first, second, REQUIRES_RSA)) {
|
|
WOLFSSL_MSG("Requires RSA");
|
|
if (haveRSA == 0) {
|
|
WOLFSSL_MSG("Don't have RSA");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CipherRequires(first, second, REQUIRES_DHE)) {
|
|
WOLFSSL_MSG("Requires DHE");
|
|
if (ssl->options.haveDH == 0) {
|
|
WOLFSSL_MSG("Don't have DHE");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CipherRequires(first, second, REQUIRES_ECC_DSA)) {
|
|
WOLFSSL_MSG("Requires ECCDSA");
|
|
if (ssl->options.haveECDSAsig == 0) {
|
|
WOLFSSL_MSG("Don't have ECCDSA");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) {
|
|
WOLFSSL_MSG("Requires static ECC");
|
|
if (ssl->options.haveStaticECC == 0) {
|
|
WOLFSSL_MSG("Don't have static ECC");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CipherRequires(first, second, REQUIRES_PSK)) {
|
|
WOLFSSL_MSG("Requires PSK");
|
|
if (havePSK == 0) {
|
|
WOLFSSL_MSG("Don't have PSK");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CipherRequires(first, second, REQUIRES_NTRU)) {
|
|
WOLFSSL_MSG("Requires NTRU");
|
|
if (ssl->options.haveNTRU == 0) {
|
|
WOLFSSL_MSG("Don't have NTRU");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CipherRequires(first, second, REQUIRES_RSA_SIG)) {
|
|
WOLFSSL_MSG("Requires RSA Signature");
|
|
if (ssl->options.side == WOLFSSL_SERVER_END &&
|
|
ssl->options.haveECDSAsig == 1) {
|
|
WOLFSSL_MSG("Don't have RSA Signature");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_SUPPORTED_CURVES
|
|
if (!TLSX_ValidateEllipticCurves(ssl, first, second)) {
|
|
WOLFSSL_MSG("Don't have matching curves");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* ECCDHE is always supported if ECC on */
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int MatchSuite(WOLFSSL* ssl, Suites* peerSuites)
|
|
{
|
|
word16 i, j;
|
|
|
|
WOLFSSL_ENTER("MatchSuite");
|
|
|
|
/* & 0x1 equivalent % 2 */
|
|
if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1)
|
|
return MATCH_SUITE_ERROR;
|
|
|
|
if (ssl->suites == NULL)
|
|
return SUITES_ERROR;
|
|
/* start with best, if a match we are good */
|
|
for (i = 0; i < ssl->suites->suiteSz; i += 2)
|
|
for (j = 0; j < peerSuites->suiteSz; j += 2)
|
|
if (ssl->suites->suites[i] == peerSuites->suites[j] &&
|
|
ssl->suites->suites[i+1] == peerSuites->suites[j+1] ) {
|
|
|
|
if (VerifyServerSuite(ssl, i)) {
|
|
int result;
|
|
WOLFSSL_MSG("Verified suite validity");
|
|
ssl->options.cipherSuite0 = ssl->suites->suites[i];
|
|
ssl->options.cipherSuite = ssl->suites->suites[i+1];
|
|
result = SetCipherSpecs(ssl);
|
|
if (result == 0)
|
|
PickHashSigAlgo(ssl, peerSuites->hashSigAlgo,
|
|
peerSuites->hashSigAlgoSz);
|
|
return result;
|
|
}
|
|
else {
|
|
WOLFSSL_MSG("Could not verify suite validity, continue");
|
|
}
|
|
}
|
|
|
|
return MATCH_SUITE_ERROR;
|
|
}
|
|
|
|
|
|
#ifdef OLD_HELLO_ALLOWED
|
|
|
|
/* process old style client hello, deprecate? */
|
|
int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|
word32 inSz, word16 sz)
|
|
{
|
|
word32 idx = *inOutIdx;
|
|
word16 sessionSz;
|
|
word16 randomSz;
|
|
word16 i, j;
|
|
ProtocolVersion pv;
|
|
Suites clSuites;
|
|
|
|
(void)inSz;
|
|
WOLFSSL_MSG("Got old format client hello");
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ClientHello", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddLateName("ClientHello", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
/* manually hash input since different format */
|
|
#ifndef NO_OLD_TLS
|
|
#ifndef NO_MD5
|
|
Md5Update(&ssl->hashMd5, input + idx, sz);
|
|
#endif
|
|
#ifndef NO_SHA
|
|
ShaUpdate(&ssl->hashSha, input + idx, sz);
|
|
#endif
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
int shaRet = Sha256Update(&ssl->hashSha256, input + idx, sz);
|
|
|
|
if (shaRet != 0)
|
|
return shaRet;
|
|
}
|
|
#endif
|
|
|
|
/* does this value mean client_hello? */
|
|
idx++;
|
|
|
|
/* version */
|
|
pv.major = input[idx++];
|
|
pv.minor = input[idx++];
|
|
ssl->chVersion = pv; /* store */
|
|
|
|
if (ssl->version.minor > pv.minor) {
|
|
byte haveRSA = 0;
|
|
byte havePSK = 0;
|
|
if (!ssl->options.downgrade) {
|
|
WOLFSSL_MSG("Client trying to connect with lesser version");
|
|
return VERSION_ERROR;
|
|
}
|
|
if (pv.minor < ssl->options.minDowngrade) {
|
|
WOLFSSL_MSG(" version below minimum allowed, fatal error");
|
|
return VERSION_ERROR;
|
|
}
|
|
if (pv.minor == SSLv3_MINOR) {
|
|
/* turn off tls */
|
|
WOLFSSL_MSG(" downgrading to SSLv3");
|
|
ssl->options.tls = 0;
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->version.minor = SSLv3_MINOR;
|
|
}
|
|
else if (pv.minor == TLSv1_MINOR) {
|
|
WOLFSSL_MSG(" downgrading to TLSv1");
|
|
/* turn off tls 1.1+ */
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->version.minor = TLSv1_MINOR;
|
|
}
|
|
else if (pv.minor == TLSv1_1_MINOR) {
|
|
WOLFSSL_MSG(" downgrading to TLSv1.1");
|
|
ssl->version.minor = TLSv1_1_MINOR;
|
|
}
|
|
#ifndef NO_RSA
|
|
haveRSA = 1;
|
|
#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);
|
|
}
|
|
|
|
/* suite size */
|
|
ato16(&input[idx], &clSuites.suiteSz);
|
|
idx += 2;
|
|
|
|
if (clSuites.suiteSz > MAX_SUITE_SZ)
|
|
return BUFFER_ERROR;
|
|
clSuites.hashSigAlgoSz = 0;
|
|
|
|
/* session size */
|
|
ato16(&input[idx], &sessionSz);
|
|
idx += 2;
|
|
|
|
if (sessionSz > ID_LEN)
|
|
return BUFFER_ERROR;
|
|
|
|
/* random size */
|
|
ato16(&input[idx], &randomSz);
|
|
idx += 2;
|
|
|
|
if (randomSz > RAN_LEN)
|
|
return BUFFER_ERROR;
|
|
|
|
/* suites */
|
|
for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) {
|
|
byte first = input[idx++];
|
|
if (!first) { /* implicit: skip sslv2 type */
|
|
XMEMCPY(&clSuites.suites[j], &input[idx], 2);
|
|
j += 2;
|
|
}
|
|
idx += 2;
|
|
}
|
|
clSuites.suiteSz = j;
|
|
|
|
/* session id */
|
|
if (sessionSz) {
|
|
XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz);
|
|
idx += sessionSz;
|
|
ssl->options.resuming = 1;
|
|
}
|
|
|
|
/* random */
|
|
if (randomSz < RAN_LEN)
|
|
XMEMSET(ssl->arrays->clientRandom, 0, RAN_LEN - randomSz);
|
|
XMEMCPY(&ssl->arrays->clientRandom[RAN_LEN - randomSz], input + idx,
|
|
randomSz);
|
|
idx += randomSz;
|
|
|
|
if (ssl->options.usingCompression)
|
|
ssl->options.usingCompression = 0; /* turn off */
|
|
|
|
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
|
|
*inOutIdx = idx;
|
|
|
|
ssl->options.haveSessionId = 1;
|
|
/* DoClientHello uses same resume code */
|
|
if (ssl->options.resuming) { /* let's try */
|
|
int ret = -1;
|
|
WOLFSSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret);
|
|
if (!session) {
|
|
WOLFSSL_MSG("Session lookup for resume failed");
|
|
ssl->options.resuming = 0;
|
|
} else {
|
|
if (MatchSuite(ssl, &clSuites) < 0) {
|
|
WOLFSSL_MSG("Unsupported cipher suite, OldClientHello");
|
|
return UNSUPPORTED_SUITE;
|
|
}
|
|
#ifdef SESSION_CERTS
|
|
ssl->session = *session; /* restore session certs. */
|
|
#endif
|
|
|
|
ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
|
|
RAN_LEN);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef NO_OLD_TLS
|
|
ret = DeriveTlsKeys(ssl);
|
|
#else
|
|
#ifndef NO_TLS
|
|
if (ssl->options.tls)
|
|
ret = DeriveTlsKeys(ssl);
|
|
#endif
|
|
if (!ssl->options.tls)
|
|
ret = DeriveKeys(ssl);
|
|
#endif
|
|
ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return MatchSuite(ssl, &clSuites);
|
|
}
|
|
|
|
#endif /* OLD_HELLO_ALLOWED */
|
|
|
|
|
|
static int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|
word32 helloSz)
|
|
{
|
|
byte b;
|
|
ProtocolVersion pv;
|
|
Suites clSuites;
|
|
word32 i = *inOutIdx;
|
|
word32 begin = i;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
/* protocol version, random and session id length check */
|
|
if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
/* protocol version */
|
|
XMEMCPY(&pv, input + i, OPAQUE16_LEN);
|
|
ssl->chVersion = pv; /* store */
|
|
i += OPAQUE16_LEN;
|
|
|
|
if (ssl->version.minor > pv.minor) {
|
|
byte haveRSA = 0;
|
|
byte havePSK = 0;
|
|
|
|
if (!ssl->options.downgrade) {
|
|
WOLFSSL_MSG("Client trying to connect with lesser version");
|
|
return VERSION_ERROR;
|
|
}
|
|
if (pv.minor < ssl->options.minDowngrade) {
|
|
WOLFSSL_MSG(" version below minimum allowed, fatal error");
|
|
return VERSION_ERROR;
|
|
}
|
|
|
|
if (pv.minor == SSLv3_MINOR) {
|
|
/* turn off tls */
|
|
WOLFSSL_MSG(" downgrading to SSLv3");
|
|
ssl->options.tls = 0;
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->version.minor = SSLv3_MINOR;
|
|
}
|
|
else if (pv.minor == TLSv1_MINOR) {
|
|
/* turn off tls 1.1+ */
|
|
WOLFSSL_MSG(" downgrading to TLSv1");
|
|
ssl->options.tls1_1 = 0;
|
|
ssl->version.minor = TLSv1_MINOR;
|
|
}
|
|
else if (pv.minor == TLSv1_1_MINOR) {
|
|
WOLFSSL_MSG(" downgrading to TLSv1.1");
|
|
ssl->version.minor = TLSv1_1_MINOR;
|
|
}
|
|
#ifndef NO_RSA
|
|
haveRSA = 1;
|
|
#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);
|
|
}
|
|
|
|
/* random */
|
|
XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN);
|
|
i += RAN_LEN;
|
|
|
|
#ifdef SHOW_SECRETS
|
|
{
|
|
int j;
|
|
printf("client random: ");
|
|
for (j = 0; j < RAN_LEN; j++)
|
|
printf("%02x", ssl->arrays->clientRandom[j]);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
/* session id */
|
|
b = input[i++];
|
|
|
|
if (b == ID_LEN) {
|
|
if ((i - begin) + ID_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN);
|
|
i += ID_LEN;
|
|
ssl->options.resuming = 1; /* client wants to resume */
|
|
WOLFSSL_MSG("Client wants to resume session");
|
|
}
|
|
else if (b) {
|
|
WOLFSSL_MSG("Invalid session ID size");
|
|
return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
/* cookie */
|
|
if (ssl->options.dtls) {
|
|
|
|
if ((i - begin) + OPAQUE8_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
b = input[i++];
|
|
|
|
if (b) {
|
|
byte cookie[MAX_COOKIE_LEN];
|
|
|
|
if (b > MAX_COOKIE_LEN)
|
|
return BUFFER_ERROR;
|
|
|
|
if ((i - begin) + b > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
if (ssl->ctx->CBIOCookie == NULL) {
|
|
WOLFSSL_MSG("Your Cookie callback is null, please set");
|
|
return COOKIE_ERROR;
|
|
}
|
|
|
|
if ((ssl->ctx->CBIOCookie(ssl, cookie, COOKIE_SZ,
|
|
ssl->IOCB_CookieCtx) != COOKIE_SZ)
|
|
|| (b != COOKIE_SZ)
|
|
|| (XMEMCMP(cookie, input + i, b) != 0)) {
|
|
return COOKIE_ERROR;
|
|
}
|
|
|
|
i += b;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* suites */
|
|
if ((i - begin) + OPAQUE16_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(&input[i], &clSuites.suiteSz);
|
|
i += OPAQUE16_LEN;
|
|
|
|
/* suites and compression length check */
|
|
if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
if (clSuites.suiteSz > MAX_SUITE_SZ)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
|
|
i += clSuites.suiteSz;
|
|
clSuites.hashSigAlgoSz = 0;
|
|
|
|
/* compression length */
|
|
b = input[i++];
|
|
|
|
if ((i - begin) + b > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
if (ssl->options.usingCompression) {
|
|
int match = 0;
|
|
|
|
while (b--) {
|
|
byte comp = input[i++];
|
|
|
|
if (comp == ZLIB_COMPRESSION)
|
|
match = 1;
|
|
}
|
|
|
|
if (!match) {
|
|
WOLFSSL_MSG("Not matching compression, turning off");
|
|
ssl->options.usingCompression = 0; /* turn off */
|
|
}
|
|
}
|
|
else
|
|
i += b; /* ignore, since we're not on */
|
|
|
|
*inOutIdx = i;
|
|
|
|
/* tls extensions */
|
|
if ((i - begin) < helloSz) {
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
if (TLSX_SupportExtensions(ssl)) {
|
|
int ret = 0;
|
|
#else
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
#endif
|
|
/* Process the hello extension. Skip unsupported. */
|
|
word16 totalExtSz;
|
|
|
|
if ((i - begin) + OPAQUE16_LEN > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(&input[i], &totalExtSz);
|
|
i += OPAQUE16_LEN;
|
|
|
|
if ((i - begin) + totalExtSz > helloSz)
|
|
return BUFFER_ERROR;
|
|
|
|
#ifdef HAVE_TLS_EXTENSIONS
|
|
if ((ret = TLSX_Parse(ssl, (byte *) input + i,
|
|
totalExtSz, 1, &clSuites)))
|
|
return ret;
|
|
|
|
i += totalExtSz;
|
|
#else
|
|
while (totalExtSz) {
|
|
word16 extId, extSz;
|
|
|
|
if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(&input[i], &extId);
|
|
i += OPAQUE16_LEN;
|
|
ato16(&input[i], &extSz);
|
|
i += OPAQUE16_LEN;
|
|
|
|
if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz)
|
|
return BUFFER_ERROR;
|
|
|
|
if (extId == HELLO_EXT_SIG_ALGO) {
|
|
ato16(&input[i], &clSuites.hashSigAlgoSz);
|
|
i += OPAQUE16_LEN;
|
|
|
|
if (OPAQUE16_LEN + clSuites.hashSigAlgoSz > extSz)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(clSuites.hashSigAlgo, &input[i],
|
|
min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX));
|
|
i += clSuites.hashSigAlgoSz;
|
|
|
|
if (clSuites.hashSigAlgoSz > HELLO_EXT_SIGALGO_MAX)
|
|
clSuites.hashSigAlgoSz = HELLO_EXT_SIGALGO_MAX;
|
|
}
|
|
else
|
|
i += extSz;
|
|
|
|
totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz;
|
|
}
|
|
#endif
|
|
*inOutIdx = i;
|
|
}
|
|
else
|
|
*inOutIdx = begin + helloSz; /* skip extensions */
|
|
}
|
|
|
|
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
|
|
ssl->options.haveSessionId = 1;
|
|
|
|
/* ProcessOld uses same resume code */
|
|
if (ssl->options.resuming && (!ssl->options.dtls ||
|
|
ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */
|
|
int ret = -1;
|
|
WOLFSSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret);
|
|
|
|
if (!session) {
|
|
WOLFSSL_MSG("Session lookup for resume failed");
|
|
ssl->options.resuming = 0;
|
|
}
|
|
else {
|
|
if (MatchSuite(ssl, &clSuites) < 0) {
|
|
WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
|
|
return UNSUPPORTED_SUITE;
|
|
}
|
|
#ifdef SESSION_CERTS
|
|
ssl->session = *session; /* restore session certs. */
|
|
#endif
|
|
|
|
ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
|
|
RAN_LEN);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef NO_OLD_TLS
|
|
ret = DeriveTlsKeys(ssl);
|
|
#else
|
|
#ifndef NO_TLS
|
|
if (ssl->options.tls)
|
|
ret = DeriveTlsKeys(ssl);
|
|
#endif
|
|
if (!ssl->options.tls)
|
|
ret = DeriveKeys(ssl);
|
|
#endif
|
|
ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
return MatchSuite(ssl, &clSuites);
|
|
}
|
|
|
|
#if !defined(NO_RSA) || defined(HAVE_ECC)
|
|
static int DoCertificateVerify(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
|
word32 size)
|
|
{
|
|
word16 sz = 0;
|
|
int ret = VERIFY_CERT_ERROR; /* start in error state */
|
|
byte hashAlgo = sha_mac;
|
|
byte sigAlgo = anonymous_sa_algo;
|
|
word32 begin = *inOutIdx;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("CertificateVerify", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddLateName("CertificateVerify", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
hashAlgo = input[(*inOutIdx)++];
|
|
sigAlgo = input[(*inOutIdx)++];
|
|
}
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &sz);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + sz > size || sz > ENCRYPT_LEN)
|
|
return BUFFER_ERROR;
|
|
|
|
/* RSA */
|
|
#ifndef NO_RSA
|
|
if (ssl->peerRsaKeyPresent != 0) {
|
|
byte* out = NULL;
|
|
int outLen = 0;
|
|
byte doUserRsa = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->RsaVerifyCb)
|
|
doUserRsa = 1;
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
|
|
WOLFSSL_MSG("Doing RSA peer cert verify");
|
|
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
outLen = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, sz,
|
|
&out,
|
|
ssl->buffers.peerRsaKey.buffer,
|
|
ssl->buffers.peerRsaKey.length,
|
|
ssl->RsaVerifyCtx);
|
|
#endif /*HAVE_PK_CALLBACKS */
|
|
}
|
|
else {
|
|
outLen = RsaSSL_VerifyInline(input + *inOutIdx, sz, &out,
|
|
ssl->peerRsaKey);
|
|
}
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* encodedSig = NULL;
|
|
#else
|
|
byte encodedSig[MAX_ENCODED_SIG_SZ];
|
|
#endif
|
|
word32 sigSz;
|
|
byte* digest = ssl->certHashes.sha;
|
|
int typeH = SHAh;
|
|
int digestSz = SHA_DIGEST_SIZE;
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (encodedSig == NULL)
|
|
return MEMORY_E;
|
|
#endif
|
|
|
|
if (sigAlgo != rsa_sa_algo) {
|
|
WOLFSSL_MSG("Oops, peer sent RSA key but not in verify");
|
|
}
|
|
|
|
if (hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = ssl->certHashes.sha256;
|
|
typeH = SHA256h;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = ssl->certHashes.sha384;
|
|
typeH = SHA384h;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
|
|
sigSz = EncodeSignature(encodedSig, digest, digestSz, typeH);
|
|
|
|
if (outLen == (int)sigSz && out && XMEMCMP(out, encodedSig,
|
|
min(sigSz, MAX_ENCODED_SIG_SZ)) == 0)
|
|
ret = 0; /* verified */
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
}
|
|
else {
|
|
if (outLen == FINISHED_SZ && out && XMEMCMP(out,
|
|
&ssl->certHashes, FINISHED_SZ) == 0)
|
|
ret = 0; /* verified */
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
if (ssl->peerEccDsaKeyPresent) {
|
|
int verify = 0;
|
|
int err = -1;
|
|
byte* digest = ssl->certHashes.sha;
|
|
word32 digestSz = SHA_DIGEST_SIZE;
|
|
byte doUserEcc = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->EccVerifyCb)
|
|
doUserEcc = 1;
|
|
#endif
|
|
|
|
WOLFSSL_MSG("Doing ECC peer cert verify");
|
|
|
|
if (IsAtLeastTLSv1_2(ssl)) {
|
|
if (sigAlgo != ecc_dsa_sa_algo) {
|
|
WOLFSSL_MSG("Oops, peer sent ECC key but not in verify");
|
|
}
|
|
|
|
if (hashAlgo == sha256_mac) {
|
|
#ifndef NO_SHA256
|
|
digest = ssl->certHashes.sha256;
|
|
digestSz = SHA256_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
else if (hashAlgo == sha384_mac) {
|
|
#ifdef WOLFSSL_SHA384
|
|
digest = ssl->certHashes.sha384;
|
|
digestSz = SHA384_DIGEST_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (doUserEcc) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, sz, digest,
|
|
digestSz,
|
|
ssl->buffers.peerEccDsaKey.buffer,
|
|
ssl->buffers.peerEccDsaKey.length,
|
|
&verify, ssl->EccVerifyCtx);
|
|
#endif
|
|
}
|
|
else {
|
|
err = ecc_verify_hash(input + *inOutIdx, sz, digest, digestSz,
|
|
&verify, ssl->peerEccDsaKey);
|
|
}
|
|
|
|
if (err == 0 && verify == 1)
|
|
ret = 0; /* verified */
|
|
}
|
|
#endif
|
|
*inOutIdx += sz;
|
|
|
|
if (ret == 0)
|
|
ssl->options.havePeerVerify = 1;
|
|
|
|
return ret;
|
|
}
|
|
#endif /* !NO_RSA || HAVE_ECC */
|
|
|
|
int SendServerHelloDone(WOLFSSL* ssl)
|
|
{
|
|
byte *output;
|
|
int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
|
int ret;
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls)
|
|
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
|
|
#endif
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, 0, server_hello_done, ssl);
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
if (ssl->options.dtls) {
|
|
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz,
|
|
ssl->heap);
|
|
#endif
|
|
ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
return SendBuffered(ssl);
|
|
}
|
|
|
|
#ifdef WOLFSSL_DTLS
|
|
int SendHelloVerifyRequest(WOLFSSL* ssl)
|
|
{
|
|
byte* output;
|
|
byte cookieSz = COOKIE_SZ;
|
|
int length = VERSION_SZ + ENUM_LEN + cookieSz;
|
|
int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ;
|
|
int sendSz = length + idx;
|
|
int ret;
|
|
|
|
/* check for available size */
|
|
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
|
|
return ret;
|
|
|
|
/* get ouput buffer */
|
|
output = ssl->buffers.outputBuffer.buffer +
|
|
ssl->buffers.outputBuffer.length;
|
|
|
|
AddHeaders(output, length, hello_verify_request, ssl);
|
|
|
|
output[idx++] = ssl->chVersion.major;
|
|
output[idx++] = ssl->chVersion.minor;
|
|
|
|
output[idx++] = cookieSz;
|
|
if (ssl->ctx->CBIOCookie == NULL) {
|
|
WOLFSSL_MSG("Your Cookie callback is null, please set");
|
|
return COOKIE_ERROR;
|
|
}
|
|
if ((ret = ssl->ctx->CBIOCookie(ssl, output + idx, cookieSz,
|
|
ssl->IOCB_CookieCtx)) < 0)
|
|
return ret;
|
|
|
|
ret = HashOutput(ssl, output, sendSz, 0);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output,
|
|
sendSz, ssl->heap);
|
|
#endif
|
|
ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
|
|
|
|
ssl->buffers.outputBuffer.length += sendSz;
|
|
|
|
return SendBuffered(ssl);
|
|
}
|
|
#endif
|
|
|
|
static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
|
word32 size)
|
|
{
|
|
int ret = 0;
|
|
word32 length = 0;
|
|
byte* out = NULL;
|
|
word32 begin = *inOutIdx;
|
|
|
|
(void)length; /* shut up compiler warnings */
|
|
(void)out;
|
|
(void)input;
|
|
(void)size;
|
|
(void)begin;
|
|
|
|
if (ssl->options.side != WOLFSSL_SERVER_END) {
|
|
WOLFSSL_MSG("Client received client keyexchange, attack?");
|
|
WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
|
|
return SSL_FATAL_ERROR;
|
|
}
|
|
|
|
if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
|
|
WOLFSSL_MSG("Client sending keyexchange at wrong time");
|
|
SendAlert(ssl, alert_fatal, unexpected_message);
|
|
return OUT_OF_ORDER_E;
|
|
}
|
|
|
|
#ifndef NO_CERTS
|
|
if (ssl->options.verifyPeer && ssl->options.failNoCert)
|
|
if (!ssl->options.havePeerCert) {
|
|
WOLFSSL_MSG("client didn't present peer cert");
|
|
return NO_PEER_CERT;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_CALLBACKS
|
|
if (ssl->hsInfoOn)
|
|
AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
|
|
if (ssl->toInfoOn)
|
|
AddLateName("ClientKeyExchange", &ssl->timeoutInfo);
|
|
#endif
|
|
|
|
switch (ssl->specs.kea) {
|
|
#ifndef NO_RSA
|
|
case rsa_kea:
|
|
{
|
|
word32 idx = 0;
|
|
RsaKey key;
|
|
byte doUserRsa = 0;
|
|
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
if (ssl->ctx->RsaDecCb)
|
|
doUserRsa = 1;
|
|
#endif
|
|
|
|
ret = InitRsaKey(&key, ssl->heap);
|
|
if (ret != 0) return ret;
|
|
|
|
if (ssl->buffers.key.buffer)
|
|
ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx,
|
|
&key, ssl->buffers.key.length);
|
|
else
|
|
return NO_PRIVATE_KEY;
|
|
|
|
if (ret == 0) {
|
|
length = RsaEncryptSize(&key);
|
|
ssl->arrays->preMasterSz = SECRET_LEN;
|
|
|
|
if (ssl->options.tls) {
|
|
word16 check;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &check);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((word32) check != length) {
|
|
WOLFSSL_MSG("RSA explicit size doesn't match");
|
|
FreeRsaKey(&key);
|
|
return RSA_PRIVATE_ERROR;
|
|
}
|
|
}
|
|
|
|
if ((*inOutIdx - begin) + length > size) {
|
|
WOLFSSL_MSG("RSA message too big");
|
|
FreeRsaKey(&key);
|
|
return BUFFER_ERROR;
|
|
}
|
|
|
|
if (doUserRsa) {
|
|
#ifdef HAVE_PK_CALLBACKS
|
|
ret = ssl->ctx->RsaDecCb(ssl,
|
|
input + *inOutIdx, length, &out,
|
|
ssl->buffers.key.buffer,
|
|
ssl->buffers.key.length,
|
|
ssl->RsaDecCtx);
|
|
#endif
|
|
}
|
|
else {
|
|
ret = RsaPrivateDecryptInline(input + *inOutIdx, length,
|
|
&out, &key);
|
|
}
|
|
|
|
*inOutIdx += length;
|
|
|
|
if (ret == SECRET_LEN) {
|
|
XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN);
|
|
if (ssl->arrays->preMasterSecret[0] !=
|
|
ssl->chVersion.major
|
|
|| ssl->arrays->preMasterSecret[1] !=
|
|
ssl->chVersion.minor)
|
|
ret = PMS_VERSION_ERROR;
|
|
else
|
|
ret = MakeMasterSecret(ssl);
|
|
}
|
|
else {
|
|
ret = RSA_PRIVATE_ERROR;
|
|
}
|
|
}
|
|
|
|
FreeRsaKey(&key);
|
|
}
|
|
break;
|
|
#endif
|
|
#ifndef NO_PSK
|
|
case psk_kea:
|
|
{
|
|
byte* pms = ssl->arrays->preMasterSecret;
|
|
word16 ci_sz;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &ci_sz);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if (ci_sz > MAX_PSK_ID_LEN)
|
|
return CLIENT_ID_ERROR;
|
|
|
|
if ((*inOutIdx - begin) + ci_sz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz);
|
|
*inOutIdx += ci_sz;
|
|
|
|
ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0;
|
|
ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
|
|
ssl->arrays->client_identity, ssl->arrays->psk_key,
|
|
MAX_PSK_KEY_LEN);
|
|
|
|
if (ssl->arrays->psk_keySz == 0 ||
|
|
ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN)
|
|
return PSK_KEY_ERROR;
|
|
|
|
/* make psk pre master secret */
|
|
/* length of key + length 0s + length of key + key */
|
|
c16toa((word16) ssl->arrays->psk_keySz, pms);
|
|
pms += OPAQUE16_LEN;
|
|
|
|
XMEMSET(pms, 0, ssl->arrays->psk_keySz);
|
|
pms += ssl->arrays->psk_keySz;
|
|
|
|
c16toa((word16) ssl->arrays->psk_keySz, pms);
|
|
pms += OPAQUE16_LEN;
|
|
|
|
XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
|
|
ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4;
|
|
|
|
ret = MakeMasterSecret(ssl);
|
|
|
|
/* No further need for PSK */
|
|
XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
|
|
ssl->arrays->psk_keySz = 0;
|
|
}
|
|
break;
|
|
#endif /* NO_PSK */
|
|
#ifdef HAVE_NTRU
|
|
case ntru_kea:
|
|
{
|
|
word16 cipherLen;
|
|
word16 plainLen = sizeof(ssl->arrays->preMasterSecret);
|
|
|
|
if (!ssl->buffers.key.buffer)
|
|
return NO_PRIVATE_KEY;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &cipherLen);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
|
|
return NTRU_KEY_ERROR;
|
|
|
|
if ((*inOutIdx - begin) + cipherLen > size)
|
|
return BUFFER_ERROR;
|
|
|
|
if (NTRU_OK != ntru_crypto_ntru_decrypt(
|
|
(word16) ssl->buffers.key.length,
|
|
ssl->buffers.key.buffer, cipherLen,
|
|
input + *inOutIdx, &plainLen,
|
|
ssl->arrays->preMasterSecret))
|
|
return NTRU_DECRYPT_ERROR;
|
|
|
|
if (plainLen != SECRET_LEN)
|
|
return NTRU_DECRYPT_ERROR;
|
|
|
|
*inOutIdx += cipherLen;
|
|
|
|
ssl->arrays->preMasterSz = plainLen;
|
|
ret = MakeMasterSecret(ssl);
|
|
}
|
|
break;
|
|
#endif /* HAVE_NTRU */
|
|
#ifdef HAVE_ECC
|
|
case ecc_diffie_hellman_kea:
|
|
{
|
|
if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
length = input[(*inOutIdx)++];
|
|
|
|
if ((*inOutIdx - begin) + length > size)
|
|
return BUFFER_ERROR;
|
|
|
|
if (ssl->peerEccKeyPresent) { /* don't leak on reuse */
|
|
ecc_free(ssl->peerEccKey);
|
|
ssl->peerEccKeyPresent = 0;
|
|
ecc_init(ssl->peerEccKey);
|
|
}
|
|
|
|
if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey))
|
|
return ECC_PEERKEY_ERROR;
|
|
|
|
*inOutIdx += length;
|
|
ssl->peerEccKeyPresent = 1;
|
|
|
|
length = sizeof(ssl->arrays->preMasterSecret);
|
|
|
|
if (ssl->specs.static_ecdh) {
|
|
ecc_key staticKey;
|
|
word32 i = 0;
|
|
|
|
ecc_init(&staticKey);
|
|
ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
|
|
&staticKey, ssl->buffers.key.length);
|
|
|
|
if (ret == 0)
|
|
ret = ecc_shared_secret(&staticKey, ssl->peerEccKey,
|
|
ssl->arrays->preMasterSecret, &length);
|
|
|
|
ecc_free(&staticKey);
|
|
}
|
|
else {
|
|
if (ssl->eccTempKeyPresent == 0) {
|
|
WOLFSSL_MSG("Ecc ephemeral key not made correctly");
|
|
ret = ECC_MAKEKEY_ERROR;
|
|
} else {
|
|
ret = ecc_shared_secret(ssl->eccTempKey,ssl->peerEccKey,
|
|
ssl->arrays->preMasterSecret, &length);
|
|
}
|
|
}
|
|
|
|
if (ret != 0)
|
|
return ECC_SHARED_ERROR;
|
|
|
|
ssl->arrays->preMasterSz = length;
|
|
ret = MakeMasterSecret(ssl);
|
|
}
|
|
break;
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_DH
|
|
case diffie_hellman_kea:
|
|
{
|
|
word16 clientPubSz;
|
|
DhKey dhKey;
|
|
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &clientPubSz);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + clientPubSz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
InitDhKey(&dhKey);
|
|
ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
|
|
ssl->buffers.serverDH_P.length,
|
|
ssl->buffers.serverDH_G.buffer,
|
|
ssl->buffers.serverDH_G.length);
|
|
if (ret == 0)
|
|
ret = DhAgree(&dhKey, ssl->arrays->preMasterSecret,
|
|
&ssl->arrays->preMasterSz,
|
|
ssl->buffers.serverDH_Priv.buffer,
|
|
ssl->buffers.serverDH_Priv.length,
|
|
input + *inOutIdx, clientPubSz);
|
|
FreeDhKey(&dhKey);
|
|
|
|
*inOutIdx += clientPubSz;
|
|
|
|
if (ret == 0)
|
|
ret = MakeMasterSecret(ssl);
|
|
}
|
|
break;
|
|
#endif /* NO_DH */
|
|
#if !defined(NO_DH) && !defined(NO_PSK)
|
|
case dhe_psk_kea:
|
|
{
|
|
byte* pms = ssl->arrays->preMasterSecret;
|
|
word16 clientSz;
|
|
DhKey dhKey;
|
|
|
|
/* Read in the PSK hint */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &clientSz);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
if (clientSz > MAX_PSK_ID_LEN)
|
|
return CLIENT_ID_ERROR;
|
|
|
|
if ((*inOutIdx - begin) + clientSz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
XMEMCPY(ssl->arrays->client_identity,
|
|
input + *inOutIdx, clientSz);
|
|
*inOutIdx += clientSz;
|
|
ssl->arrays->client_identity[min(clientSz, MAX_PSK_ID_LEN-1)] =
|
|
0;
|
|
|
|
/* Read in the DHE business */
|
|
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
|
|
return BUFFER_ERROR;
|
|
|
|
ato16(input + *inOutIdx, &clientSz);
|
|
*inOutIdx += OPAQUE16_LEN;
|
|
|
|
if ((*inOutIdx - begin) + clientSz > size)
|
|
return BUFFER_ERROR;
|
|
|
|
InitDhKey(&dhKey);
|
|
ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
|
|
ssl->buffers.serverDH_P.length,
|
|
ssl->buffers.serverDH_G.buffer,
|
|
ssl->buffers.serverDH_G.length);
|
|
if (ret == 0)
|
|
ret = DhAgree(&dhKey, pms + OPAQUE16_LEN,
|
|
&ssl->arrays->preMasterSz,
|
|
ssl->buffers.serverDH_Priv.buffer,
|
|
ssl->buffers.serverDH_Priv.length,
|
|
input + *inOutIdx, clientSz);
|
|
FreeDhKey(&dhKey);
|
|
|
|
*inOutIdx += clientSz;
|
|
c16toa((word16)ssl->arrays->preMasterSz, pms);
|
|
ssl->arrays->preMasterSz += OPAQUE16_LEN;
|
|
pms += ssl->arrays->preMasterSz;
|
|
|
|
/* Use the PSK hint to look up the PSK and add it to the
|
|
* preMasterSecret here. */
|
|
ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
|
|
ssl->arrays->client_identity, ssl->arrays->psk_key,
|
|
MAX_PSK_KEY_LEN);
|
|
|
|
if (ssl->arrays->psk_keySz == 0 ||
|
|
ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN)
|
|
return PSK_KEY_ERROR;
|
|
|
|
c16toa((word16) ssl->arrays->psk_keySz, pms);
|
|
pms += OPAQUE16_LEN;
|
|
|
|
XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
|
|
ssl->arrays->preMasterSz +=
|
|
ssl->arrays->psk_keySz + OPAQUE16_LEN;
|
|
if (ret == 0)
|
|
ret = MakeMasterSecret(ssl);
|
|
|
|
/* No further need for PSK */
|
|
XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
|
|
ssl->arrays->psk_keySz = 0;
|
|
}
|
|
break;
|
|
#endif /* !NO_DH && !NO_PSK */
|
|
default:
|
|
{
|
|
WOLFSSL_MSG("Bad kea type");
|
|
ret = BAD_KEA_TYPE_E;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* No further need for PMS */
|
|
XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz);
|
|
ssl->arrays->preMasterSz = 0;
|
|
|
|
if (ret == 0) {
|
|
ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
|
|
#ifndef NO_CERTS
|
|
if (ssl->options.verifyPeer)
|
|
ret = BuildCertHashes(ssl, &ssl->certHashes);
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* NO_WOLFSSL_SERVER */
|