CyaSSL changed for NucleoF401RE board: implemented random and time functions for build. (Has trouble with wildcard domains like *.google.com, *.yahoo.com)
Fork of CyaSSL by
Diff: src/internal.c
- Revision:
- 4:e505054279ed
- Parent:
- 0:1239e9b70ca2
--- a/src/internal.c Wed Dec 03 05:24:18 2014 +0000 +++ b/src/internal.c Wed Jan 14 22:07:14 2015 +0000 @@ -1,11301 +1,11301 @@ -/* internal.c - * - * Copyright (C) 2006-2014 wolfSSL Inc. - * - * This file is part of CyaSSL. - * - * CyaSSL 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. - * - * CyaSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <cyassl/ctaocrypt/settings.h> - -#include <cyassl/internal.h> -#include <cyassl/error-ssl.h> -#include <cyassl/ctaocrypt/asn.h> - -#ifdef HAVE_LIBZ - #include "zlib.h" -#endif - -#ifdef HAVE_NTRU - #include "crypto_ntru.h" -#endif - -#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) - #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(OPENSSL_EXTRA) && defined(NO_DH) - #error OPENSSL_EXTRA needs DH, please remove NO_DH -#endif - -#if defined(CYASSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS) - #error \ -CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS -#endif - - -#ifndef NO_CYASSL_CLIENT - static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*, - word32); - static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); - static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*, - word32); - #ifndef NO_CERTS - static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*, - word32); - #endif -#endif - - -#ifndef NO_CYASSL_SERVER - static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32); - static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32*, word32); - #if !defined(NO_RSA) || defined(HAVE_ECC) - static int DoCertificateVerify(CYASSL* ssl, byte*, word32*, word32); - #endif -#endif - - -#ifdef CYASSL_DTLS - static INLINE int DtlsCheckWindow(DtlsState* state); - static INLINE int DtlsUpdateWindow(DtlsState* state); -#endif - - -typedef enum { - doProcessInit = 0, -#ifndef NO_CYASSL_SERVER - runProcessOldClientHello, -#endif - getRecordLayerHeader, - getData, - runProcessingOneMessage -} processReply; - -#ifndef NO_OLD_TLS -static int SSL_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz, - int content, int verify); - -#endif - -#ifndef NO_CERTS -static int BuildCertHashes(CYASSL* ssl, Hashes* hashes); -#endif - -static void PickHashSigAlgo(CYASSL* 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 CYASSL* ssl) -{ - if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR) - return 1; - - return 0; -} - - -int IsAtLeastTLSv1_2(const CYASSL* 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 CYASSL_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 /* CYASSL_DTLS */ - - -/* convert 16 bit integer to opaque */ -static INLINE void c16toa(word16 u16, byte* c) -{ - c[0] = (u16 >> 8) & 0xff; - c[1] = u16 & 0xff; -} - - -/* 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; -} - - -/* 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])); -} - - -#ifdef CYASSL_DTLS - -/* 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 /* CYASSL_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(CYASSL* 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(CYASSL* ssl) - { - if (ssl->didStreamInit) { - deflateEnd(&ssl->c_stream); - inflateEnd(&ssl->d_stream); - } - } - - - /* compress in to out, return out size or error */ - static int myCompress(CYASSL* 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(CYASSL* 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(CYASSL_METHOD* method, ProtocolVersion pv) -{ - method->version = pv; - method->side = CYASSL_CLIENT_END; - method->downgrade = 0; -} - - -/* Initialze SSL context, return 0 on success */ -int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_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_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 = DEFAULT_TIMEOUT; - -#ifndef CYASSL_USER_IO - ctx->CBIORecv = EmbedReceive; - ctx->CBIOSend = EmbedSend; - #ifdef CYASSL_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 CYASSL_DTLS - ctx->CBIOCookie = NULL; - #endif -#endif /* CYASSL_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 = CyaSSL_CertManagerNew(); -#endif -#ifdef HAVE_NTRU - if (method->side == CYASSL_CLIENT_END) - ctx->haveNTRU = 1; /* always on cliet side */ - /* server can turn on by loading key */ -#endif -#ifdef HAVE_ECC - if (method->side == CYASSL_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) { - CYASSL_MSG("Mutex error on CTX init"); - return BAD_MUTEX_E; - } -#ifndef NO_CERTS - if (ctx->cm == NULL) { - CYASSL_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(CYASSL_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); - CyaSSL_CertManagerFree(ctx->cm); -#endif -#ifdef HAVE_TLS_EXTENSIONS - TLSX_FreeAll(ctx->extensions); -#endif -} - - -void FreeSSL_Ctx(CYASSL_CTX* ctx) -{ - int doFree = 0; - - if (LockMutex(&ctx->countMutex) != 0) { - CYASSL_MSG("Couldn't lock count mutex"); - return; - } - ctx->refCount--; - if (ctx->refCount == 0) - doFree = 1; - UnLockMutex(&ctx->countMutex); - - if (doFree) { - CYASSL_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; - CYASSL_MSG("CTX ref count not 0 yet, no free"); - } -} - - -/* Set cipher pointers to null */ -void InitCiphers(CYASSL* 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 - ssl->encrypt.setup = 0; - ssl->decrypt.setup = 0; -} - - -/* Free ciphers */ -void FreeCiphers(CYASSL* ssl) -{ - (void)ssl; -#ifdef BUILD_ARC4 - #ifdef HAVE_CAVIUM - if (ssl->devId != NO_CAVIUM_DEVICE) { - Arc4FreeCavium(ssl->encrypt.arc4); - 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) { - AesFreeCavium(ssl->encrypt.aes); - 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 -} - - -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; -} - - -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) { - CYASSL_MSG("InitSuites pointer error"); - return; - } - - if (suites->setSuites) - return; /* trust user settings, don't override */ - - if (side == CYASSL_SERVER_END && haveStaticECC) { - haveRSA = 0; /* can't do RSA with ECDSA key */ - (void)haveRSA; /* some builds won't read */ - } - - if (side == CYASSL_SERVER_END && haveECDSAsig) { - haveRSAsig = 0; /* can't have RSA sig if signed by ECDSA */ - (void)haveRSAsig; /* non ecc builds won't read */ - } - -#ifdef CYASSL_DTLS - if (pv.major == DTLS_MAJOR) { - tls = 1; - tls1_2 = pv.minor <= DTLSv1_2_MINOR; - } -#endif - -#ifdef HAVE_RENEGOTIATION_INDICATION - if (side == CYASSL_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_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_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_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_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_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; - - { - idx = 0; - - if (haveECDSAsig) { - #ifdef CYASSL_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 CYASSL_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 - } - - suites->hashSigAlgoSz = idx; - } -} - - -#ifndef NO_CERTS - - -void InitX509Name(CYASSL_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(CYASSL_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 CyaSSL X509 type */ -void InitX509(CYASSL_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 CYASSL_SEP - x509->certPolicySet = 0; - x509->certPolicyCrit = 0; - #endif /* CYASSL_SEP */ -#endif /* OPENSSL_EXTRA */ -} - - -/* Free CyaSSL X509 type */ -void FreeX509(CYASSL_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(CYASSL* ssl, CYASSL_CTX* ctx) -{ - int ret; - byte haveRSA = 0; - byte havePSK = 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 CYASSL_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 - -#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 CYASSL_SHA384 - ret = InitSha384(&ssl->hashSha384); - if (ret != 0) { - return ret; - } -#endif -#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->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 == CYASSL_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.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 */ - - ssl->options.serverState = NULL_STATE; - ssl->options.clientState = NULL_STATE; - ssl->options.connectState = CONNECT_BEGIN; - ssl->options.acceptState = ACCEPT_BEGIN; - ssl->options.handShakeState = NULL_STATE; - ssl->options.processReply = doProcessInit; - -#ifdef CYASSL_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; - -#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 == CYASSL_SERVER_END) { - ssl->buffers.serverDH_P = ctx->serverDH_P; - ssl->buffers.serverDH_G = ctx->serverDH_G; - } -#endif - ssl->buffers.weOwnCert = 0; - ssl->buffers.weOwnKey = 0; - ssl->buffers.weOwnDH = 0; - -#ifdef CYASSL_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 - - ssl->cipher.ssl = ssl; - -#ifdef FORTRESS - ssl->ex_data[0] = 0; - ssl->ex_data[1] = 0; - ssl->ex_data[2] = 0; -#endif - -#ifdef CYASSL_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 -#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_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 */ - - /* increment CTX reference count */ - if (LockMutex(&ctx->countMutex) != 0) { - CYASSL_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) { - CYASSL_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 CYASSL_DTLS - ssl->arrays->cookieSz = 0; -#endif - - /* RNG */ - ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG); - if (ssl->rng == NULL) { - CYASSL_MSG("RNG Memory error"); - return MEMORY_E; - } - - if ( (ret = InitRng(ssl->rng)) != 0) { - CYASSL_MSG("RNG Init error"); - return ret; - } - - /* suites */ - ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, - DYNAMIC_TYPE_SUITES); - if (ssl->suites == NULL) { - CYASSL_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) { - CYASSL_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 */ - if (ssl->options.side == CYASSL_SERVER_END && !havePSK) - if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) { - CYASSL_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) { - CYASSL_MSG("PeerEccKey Memory error"); - return MEMORY_E; - } - ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccDsaKey == NULL) { - CYASSL_MSG("PeerEccDsaKey Memory error"); - return MEMORY_E; - } - ssl->eccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->eccDsaKey == NULL) { - CYASSL_MSG("EccDsaKey Memory error"); - return MEMORY_E; - } - ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->eccTempKey == NULL) { - CYASSL_MSG("EccTempKey Memory error"); - return MEMORY_E; - } - ecc_init(ssl->peerEccKey); - ecc_init(ssl->peerEccDsaKey); - ecc_init(ssl->eccDsaKey); - ecc_init(ssl->eccTempKey); -#endif - - /* make sure server has DH parms, and add PSK if there, add NTRU too */ - if (ssl->options.side == CYASSL_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(CYASSL* ssl, int keep) -{ - if (ssl->arrays && keep) { - /* keeps session id for user retrieval */ - XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN); - } - 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(CYASSL* ssl) -{ - FreeCiphers(ssl); - FreeArrays(ssl, 0); - 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 == CYASSL_CLIENT_END) { - XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH); - XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH); - } - - /* CYASSL_CTX always owns certChain */ - if (ssl->buffers.weOwnCert) - XFREE(ssl->buffers.certificate.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 CYASSL_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) - CyaSSL_BIO_free(ssl->biord); - if (ssl->biord != ssl->biowr) /* in case same as write */ - CyaSSL_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(CYASSL* ssl) -{ - /* 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) { - XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); - ssl->rng = NULL; - } - -#ifdef CYASSL_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(CYASSL* ssl) -{ - FreeSSL_Ctx(ssl->ctx); /* will decrement and free underyling CTX if 0 */ - SSL_ResourceFree(ssl); - XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL); -} - - -#ifdef CYASSL_DTLS - -int DtlsPoolInit(CYASSL* ssl) -{ - if (ssl->dtls_pool == NULL) { - DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool), - ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - if (pool == NULL) { - CYASSL_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(CYASSL* 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_OUT_BUFFER); - if (pBuf->buffer == NULL) { - CYASSL_MSG("DTLS Buffer Memory error"); - return MEMORY_ERROR; - } - XMEMCPY(pBuf->buffer, src, sz); - pBuf->length = (word32)sz; - pool->used++; - } - return 0; -} - - -void DtlsPoolReset(CYASSL* 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_OUT_BUFFER); - pBuf->buffer = NULL; - pBuf->length = 0; - } - pool->used = 0; - } - ssl->dtls_timeout = ssl->dtls_timeout_init; -} - - -int DtlsPoolTimeout(CYASSL* ssl) -{ - int result = -1; - if (ssl->dtls_timeout < ssl->dtls_timeout_max) { - ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; - result = 0; - } - return result; -} - - -int DtlsPoolSend(CYASSL* 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) { - 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 /* CYASSL_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 CYASSL_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 /* CYASSL_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(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(CYASSL* ssl, const byte* output, int sz, int ivSz) -{ - const byte* adj = output + RECORD_HEADER_SZ + ivSz; - sz -= RECORD_HEADER_SZ; - -#ifdef CYASSL_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 CYASSL_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(CYASSL* ssl, const byte* input, int sz) -{ - const byte* adj = input - HANDSHAKE_HEADER_SZ; - sz += HANDSHAKE_HEADER_SZ; - -#ifdef CYASSL_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 CYASSL_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, CYASSL* 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 CYASSL_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, - CYASSL* ssl) -{ - HandShakeHeader* hs; - (void)ssl; - - /* handshake header */ - hs = (HandShakeHeader*)output; - hs->type = type; - c32to24(length, hs->length); /* type and length same for each */ -#ifdef CYASSL_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, CYASSL* ssl) -{ - if (!ssl->options.dtls) { - AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl); - AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl); - } -#ifdef CYASSL_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(CYASSL* ssl, byte* buf, word32 sz) -{ - int recvd; - - if (ssl->ctx->CBIORecv == NULL) { - CYASSL_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 CYASSL_CBIO_ERR_GENERAL: /* general/unknown error */ - return -1; - - case CYASSL_CBIO_ERR_WANT_READ: /* want read, would block */ - return WANT_READ; - - case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ - #ifdef USE_WINDOWS_API - if (ssl->options.dtls) { - goto retry; - } - #endif - ssl->options.connReset = 1; - return -1; - - case CYASSL_CBIO_ERR_ISR: /* interrupt */ - /* see if we got our timeout */ - #ifdef CYASSL_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); - CYASSL_MSG("Got our timeout"); - return WANT_READ; - } - } - #endif - goto retry; - - case CYASSL_CBIO_ERR_CONN_CLOSE: /* peer closed connection */ - ssl->options.isClosed = 1; - return -1; - - case CYASSL_CBIO_ERR_TIMEOUT: -#ifdef CYASSL_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(CYASSL* ssl) -{ - CYASSL_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(CYASSL* ssl, int forcedFree) -{ - int usedLength = ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx; - if (!forcedFree && usedLength > STATIC_BUFFER_LEN) - return; - - CYASSL_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(CYASSL* ssl) -{ - if (ssl->ctx->CBIOSend == NULL) { - CYASSL_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 CYASSL_CBIO_ERR_WANT_WRITE: /* would block */ - return WANT_WRITE; - - case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ - ssl->options.connReset = 1; - break; - - case CYASSL_CBIO_ERR_ISR: /* interrupt */ - /* see if we got our timeout */ - #ifdef CYASSL_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); - CYASSL_MSG("Got our timeout"); - return WANT_WRITE; - } - } - #endif - continue; - - case CYASSL_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; - } - - 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(CYASSL* ssl, int size) -{ - byte* tmp; - byte hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ : - RECORD_HEADER_SZ; - byte align = CYASSL_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); - CYASSL_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(CYASSL* ssl, int size, int usedLength) -{ - byte* tmp; - byte hdrSz = DTLS_RECORD_HEADER_SZ; - byte align = ssl->options.dtls ? CYASSL_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); - CYASSL_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(CYASSL *ssl, int size) -{ - 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(CYASSL* ssl, const byte* input, word32* inOutIdx, - RecordLayerHeader* rh, word16 *size) -{ - if (!ssl->options.dtls) { - XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ); - *inOutIdx += RECORD_HEADER_SZ; - ato16(rh->length, size); - } - else { -#ifdef CYASSL_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; -#endif - } - - /* catch version mismatch */ - if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){ - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.acceptState == ACCEPT_BEGIN) - CYASSL_MSG("Client attempting to connect with different version"); - else if (ssl->options.side == CYASSL_CLIENT_END && - ssl->options.downgrade && - ssl->options.connectState < FIRST_REPLY_DONE) - CYASSL_MSG("Server attempting to accept with different version"); - else { - CYASSL_MSG("SSL version error"); - return VERSION_ERROR; /* only use requested version */ - } - } - -#ifdef CYASSL_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)) - 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: - CYASSL_MSG("Unknown Record Type"); - return UNKNOWN_RECORD_TYPE; - } - - /* haven't decrypted this record yet */ - ssl->keys.decryptedCur = 0; - - return 0; -} - - -static int GetHandShakeHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, - byte *type, word32 *size) -{ - const byte *ptr = input + *inOutIdx; - (void)ssl; - *inOutIdx += HANDSHAKE_HEADER_SZ; - - *type = ptr[0]; - c24to32(&ptr[1], size); - - return 0; -} - - -#ifdef CYASSL_DTLS -static int GetDtlsHandShakeHeader(CYASSL* ssl, const byte* input, - word32* inOutIdx, byte *type, word32 *size, - word32 *fragOffset, word32 *fragSz) -{ - word32 idx = *inOutIdx; - - *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; - - *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(CYASSL* 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(CYASSL* 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(CYASSL* ssl, Hashes* hashes, const byte* sender) -{ - /* store current states, building requires get_digest which resets state */ -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - Md5 md5 = ssl->hashMd5; -#endif -#ifndef NO_SHA - Sha sha = ssl->hashSha; -#endif -#endif -#ifndef NO_SHA256 - Sha256 sha256 = ssl->hashSha256; -#endif -#ifdef CYASSL_SHA384 - Sha384 sha384 = ssl->hashSha384; -#endif - - int ret = 0; - -#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; - #endif - #ifndef NO_SHA - ssl->hashSha = sha; - #endif -#endif - if (IsAtLeastTLSv1_2(ssl)) { - #ifndef NO_SHA256 - ssl->hashSha256 = sha256; - #endif - #ifdef CYASSL_SHA384 - ssl->hashSha384 = sha384; - #endif - } - - return ret; -} - - -#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; - - CYASSL_MSG("Checking AltNames"); - - if (dCert) - altName = dCert->altNames; - - while (altName) { - CYASSL_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(CYASSL_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 CYASSL_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 /* CYASSL_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 CYASSL_SEP - x509->certPolicySet = dCert->extCertPolicySet; - x509->certPolicyCrit = dCert->extCertPolicyCrit; - #endif /* CYASSL_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(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 size) -{ - word32 listSz, begin = *inOutIdx; - int ret = 0; - int anyError = 0; - int totalCerts = 0; /* number of certs in certs buffer */ - int count; - char domain[ASN_NAME_MAX]; - buffer certs[MAX_CHAIN_DEPTH]; - - #ifdef CYASSL_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) - return BUFFER_E; -#else - if (listSz > MAX_RECORD_SIZE) - return BUFFER_E; -#endif - - if ((*inOutIdx - begin) + listSz != size) - return BUFFER_ERROR; - - CYASSL_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 { - CYASSL_MSG("Couldn't store chain cert for session"); - } -#endif - - *inOutIdx += certSz; - listSz -= certSz + CERT_HEADER_SZ; - - totalCerts++; - CYASSL_MSG(" Put another cert into chain"); - } - - count = totalCerts; - - /* verify up to peer's first */ - while (count > 1) { - buffer myCert = certs[count - 1]; - DecodedCert dCert; - 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) { - CYASSL_MSG("Chain cert is not a CA, not adding as one"); - } - else if (ret == 0 && ssl->options.verifyNone) { - CYASSL_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); - CYASSL_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, CYASSL_CHAIN_CA, - ssl->ctx->verifyPeer); - if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ - } - else if (ret != 0) { - CYASSL_MSG("Failed to verify CA from chain"); - } - else { - CYASSL_MSG("Verified CA from chain and already had it"); - } - -#ifdef HAVE_CRL - if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) { - CYASSL_MSG("Doing Non Leaf CRL check"); - ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); - - if (ret != 0) { - CYASSL_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]; - DecodedCert dCert; - int fatal = 0; - - CYASSL_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) { - CYASSL_MSG("Verified Peer's cert"); - fatal = 0; - } - else if (ret == ASN_PARSE_E) { - CYASSL_MSG("Got Peer cert ASN PARSE ERROR, fatal"); - fatal = 1; - } - else { - CYASSL_MSG("Failed to verify Peer's cert"); - if (ssl->verifyCallback) { - CYASSL_MSG("\tCallback override available, will continue"); - fatal = 0; - } - else { - CYASSL_MSG("\tNo callback override available, fatal"); - fatal = 1; - } - } - -#ifdef HAVE_OCSP - if (fatal == 0 && ssl->ctx->cm->ocspEnabled) { - ret = CheckCertOCSP(ssl->ctx->cm->ocsp, &dCert); - if (ret != 0) { - CYASSL_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) { - CYASSL_MSG("Doing Leaf CRL check"); - ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); - - if (ret != 0) { - CYASSL_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) && - (dCert.extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { - CYASSL_MSG("KeyUse Digital Sig not set"); - ret = KEYUSE_SIGNATURE_E; - } - } - - if (dCert.extExtKeyUsageSet) { - if (ssl->options.side == CYASSL_CLIENT_END) { - if ((dCert.extExtKeyUsage & - (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { - CYASSL_MSG("ExtKeyUse Server Auth not set"); - ret = EXTKEYUSE_AUTH_E; - } - } - else { - if ((dCert.extExtKeyUsage & - (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { - CYASSL_MSG("ExtKeyUse Client Auth not set"); - ret = EXTKEYUSE_AUTH_E; - } - } - } -#endif /* IGNORE_KEY_EXTENSIONS */ - - if (fatal) { - FreeDecodedCert(&dCert); - ssl->error = ret; - return ret; - } - ssl->options.havePeerCert = 1; - - /* 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) { - CYASSL_MSG("DomainName match on common name failed"); - if (CheckAltNames(&dCert, - (char*)ssl->buffers.domainName.buffer) == 0 ) { - CYASSL_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; - if (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 = - 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 (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 = - 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); - } - - if (anyError != 0 && ret == 0) - ret = anyError; - - if (ret == 0 && ssl->options.side == CYASSL_CLIENT_END) - ssl->options.serverState = SERVER_CERT_COMPLETE; - - 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; - CYASSL_X509_STORE_CTX store; - - 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) { - CYASSL_MSG("Verify callback overriding error!"); - ret = 0; - } - #ifdef SESSION_CERTS - if (store.discardSessionCerts) { - CYASSL_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 CYASSL_ALWAYS_VERIFY_CB - else { - if (ssl->verifyCallback) { - int ok; - CYASSL_X509_STORE_CTX store; - - 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) { - CYASSL_MSG("Verify callback overriding valid certificate!"); - ret = -1; - SendAlert(ssl, alert_fatal, bad_certificate); - ssl->options.isClosed = 1; - } - #ifdef SESSION_CERTS - if (store.discardSessionCerts) { - CYASSL_MSG("Verify callback requested discard sess certs"); - ssl->session.chain.count = 0; - } - #endif - } - } -#endif - - return ret; -} - -#endif /* !NO_CERTS */ - - -static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 size, word32 totalSz) -{ - int ret = 0; - - if (size) /* must be 0 */ - return BUFFER_ERROR; - - if (ssl->keys.encryptionOn) { - byte verify[MAX_DIGEST_SIZE]; - int padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - - ssl->specs.hash_size; - - ret = ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ, - HANDSHAKE_HEADER_SZ, handshake, 1); - if (ret != 0) - return ret; - - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) - padSz -= ssl->specs.block_size; - - /* access beyond input + size should be checked against totalSz */ - if ((word32) (*inOutIdx + ssl->specs.hash_size + padSz) > totalSz) - return INCOMPLETE_DATA; - - /* verify */ - if (XMEMCMP(input + *inOutIdx, verify, ssl->specs.hash_size) != 0) { - CYASSL_MSG(" hello_request verify mac error"); - return VERIFY_MAC_ERROR; - } - - *inOutIdx += ssl->specs.hash_size + padSz; - } - - if (ssl->options.side == CYASSL_SERVER_END) { - SendAlert(ssl, alert_fatal, unexpected_message); /* try */ - return FATAL_ERROR; - } - else - return SendAlert(ssl, alert_warning, no_renegotiation); -} - - -int DoFinished(CYASSL* 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; - - #ifdef CYASSL_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) { - CYASSL_MSG("Verify finished error on hashes"); - return VERIFY_FINISHED_ERROR; - } - } - - /* increment beyond input + size should be checked against totalSz */ - if (*inOutIdx + size + ssl->keys.padSz > totalSz) - return INCOMPLETE_DATA; - - /* force input exhaustion at ProcessReply consuming padSz */ - *inOutIdx += size + ssl->keys.padSz; - - if (ssl->options.side == CYASSL_CLIENT_END) { - ssl->options.serverState = SERVER_FINISHED_COMPLETE; - if (!ssl->options.resuming) { - ssl->options.handShakeState = HANDSHAKE_DONE; - -#ifdef CYASSL_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; - -#ifdef CYASSL_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; -} - - -static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, - byte type, word32 size, word32 totalSz) -{ - int ret = 0; - (void)totalSz; - - CYASSL_ENTER("DoHandShakeMsgType"); - - /* make sure can read the message */ - if (*inOutIdx + size > totalSz) - return INCOMPLETE_DATA; - - ret = HashInput(ssl, input + *inOutIdx, size); - if (ret != 0) - return ret; - -#ifdef CYASSL_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){ - CYASSL_MSG("HandShake message after handshake complete"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls == 0 && - ssl->options.serverState == NULL_STATE && type != server_hello) { - CYASSL_MSG("First server message not server hello"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls && - type == server_hello_done && - ssl->options.serverState < SERVER_HELLO_COMPLETE) { - CYASSL_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 == CYASSL_SERVER_END && - ssl->options.clientState == NULL_STATE && type != client_hello) { - CYASSL_MSG("First client message not client hello"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - - switch (type) { - - case hello_request: - CYASSL_MSG("processing hello request"); - ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz); - break; - -#ifndef NO_CYASSL_CLIENT - case hello_verify_request: - CYASSL_MSG("processing hello verify request"); - ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size); - break; - - case server_hello: - CYASSL_MSG("processing server hello"); - ret = DoServerHello(ssl, input, inOutIdx, size); - break; - -#ifndef NO_CERTS - case certificate_request: - CYASSL_MSG("processing certificate request"); - ret = DoCertificateRequest(ssl, input, inOutIdx, size); - break; -#endif - - case server_key_exchange: - CYASSL_MSG("processing server key exchange"); - ret = DoServerKeyExchange(ssl, input, inOutIdx, size); - break; -#endif - -#ifndef NO_CERTS - case certificate: - CYASSL_MSG("processing certificate"); - ret = DoCertificate(ssl, input, inOutIdx, size); - break; -#endif - - case server_hello_done: - CYASSL_MSG("processing server hello done"); - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerHelloDone", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("ServerHelloDone", &ssl->timeoutInfo); - #endif - ssl->options.serverState = SERVER_HELLODONE_COMPLETE; - break; - - case finished: - CYASSL_MSG("processing finished"); - ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); - break; - -#ifndef NO_CYASSL_SERVER - case client_hello: - CYASSL_MSG("processing client hello"); - ret = DoClientHello(ssl, input, inOutIdx, size); - break; - - case client_key_exchange: - CYASSL_MSG("processing client key exchange"); - ret = DoClientKeyExchange(ssl, input, inOutIdx, size); - break; - -#if !defined(NO_RSA) || defined(HAVE_ECC) - case certificate_verify: - CYASSL_MSG("processing certificate verify"); - ret = DoCertificateVerify(ssl, input, inOutIdx, size); - break; -#endif /* !NO_RSA || HAVE_ECC */ - -#endif /* !NO_CYASSL_SERVER */ - - default: - CYASSL_MSG("Unknown handshake message type"); - ret = UNKNOWN_HANDSHAKE_TYPE; - break; - } - - CYASSL_LEAVE("DoHandShakeMsgType()", ret); - return ret; -} - - -static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 totalSz) -{ - byte type; - word32 size; - int ret = 0; - - CYASSL_ENTER("DoHandShakeMsg()"); - - if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0) - return PARSE_ERROR; - - ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); - - CYASSL_LEAVE("DoHandShakeMsg()", ret); - return ret; -} - - -#ifdef CYASSL_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 & (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 |= (1 << (*next - cur - 1)); - } - else { - *window <<= (1 + cur - *next); - *window |= 1; - *next = cur + 1; - } - - return 1; -} - - -static int DtlsMsgDrain(CYASSL* 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(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 totalSz) -{ - byte type; - word32 size; - word32 fragOffset, fragSz; - int ret = 0; - - CYASSL_ENTER("DoDtlsHandShakeMsg()"); - if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, - &size, &fragOffset, &fragSz) != 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); - } - - CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret); - return ret; -} -#endif - - -static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) -{ - if (verify) - return ssl->keys.peer_sequence_number++; - else - return ssl->keys.sequence_number++; -} - - -#ifdef HAVE_AEAD -static INLINE void AeadIncrementExpIV(CYASSL* ssl) -{ - int i; - for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) { - if (++ssl->keys.aead_exp_IV[i]) return; - } -} -#endif - - -static INLINE int Encrypt(CYASSL* ssl, byte* out, const byte* input, word16 sz) -{ - (void)out; - (void)input; - (void)sz; - - if (ssl->encrypt.setup == 0) { - CYASSL_MSG("Encrypt ciphers not setup"); - return ENCRYPT_ERROR; - } - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_ARC4 - case cyassl_rc4: - Arc4Process(ssl->encrypt.arc4, out, input, sz); - break; - #endif - - #ifdef BUILD_DES3 - case cyassl_triple_des: - return Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz); - #endif - - #ifdef BUILD_AES - case cyassl_aes: - return AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); - #endif - - #ifdef BUILD_AESGCM - case cyassl_aes_gcm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - const byte* additionalSrc = input - 5; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* 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 CYASSL_DTLS - if (ssl->options.dtls) - 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); - 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); - AeadIncrementExpIV(ssl); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - } - break; - #endif - - #ifdef HAVE_AESCCM - case cyassl_aes_ccm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - const byte* additionalSrc = input - 5; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* 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 CYASSL_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); - 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 cyassl_camellia: - CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz); - break; - #endif - - #ifdef HAVE_HC128 - case cyassl_hc128: - return Hc128_Process(ssl->encrypt.hc128, out, input, sz); - #endif - - #ifdef BUILD_RABBIT - case cyassl_rabbit: - return RabbitProcess(ssl->encrypt.rabbit, out, input, sz); - #endif - - #ifdef HAVE_NULL_CIPHER - case cyassl_cipher_null: - if (input != out) { - XMEMMOVE(out, input, sz); - } - break; - #endif - - default: - CYASSL_MSG("CyaSSL Encrypt programming error"); - return ENCRYPT_ERROR; - } - - return 0; -} - - - -static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, - word16 sz) -{ - (void)plain; - (void)input; - (void)sz; - - if (ssl->decrypt.setup == 0) { - CYASSL_MSG("Decrypt ciphers not setup"); - return DECRYPT_ERROR; - } - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_ARC4 - case cyassl_rc4: - Arc4Process(ssl->decrypt.arc4, plain, input, sz); - break; - #endif - - #ifdef BUILD_DES3 - case cyassl_triple_des: - return Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz); - #endif - - #ifdef BUILD_AES - case cyassl_aes: - return AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); - #endif - - #ifdef BUILD_AESGCM - case cyassl_aes_gcm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); - - 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 (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 cyassl_aes_ccm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); - - #ifdef CYASSL_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 (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 cyassl_camellia: - CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz); - break; - #endif - - #ifdef HAVE_HC128 - case cyassl_hc128: - return Hc128_Process(ssl->decrypt.hc128, plain, input, sz); - #endif - - #ifdef BUILD_RABBIT - case cyassl_rabbit: - return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); - #endif - - #ifdef HAVE_NULL_CIPHER - case cyassl_cipher_null: - if (input != plain) { - XMEMMOVE(plain, input, sz); - } - break; - #endif - - default: - CYASSL_MSG("CyaSSL Decrypt programming error"); - return DECRYPT_ERROR; - } - return 0; -} - - -/* check cipher text size for sanity */ -static int SanityCheckCipherText(CYASSL* 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) { - CYASSL_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 + AEAD_EXP_IV_SZ; - /* explicit IV + authTag size */ - } - - if (encryptSz < minLength) { - CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_SHA384 - case sha384_mac : - Sha384Rounds(rounds, data, sz); - break; -#endif - -#ifdef CYASSL_SHA512 - case sha512_mac : - Sha512Rounds(rounds, data, sz); - break; -#endif - -#ifdef CYASSL_RIPEMD - case rmd_mac : - RmdRounds(rounds, data, sz); - break; -#endif - - default: - CYASSL_MSG("Bad round type"); - break; - } -} - - -/* do number of compression rounds on dummy data */ -static INLINE void CompressRounds(CYASSL* 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(CYASSL* 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) { - CYASSL_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) { - CYASSL_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) { - CYASSL_MSG("Verify MAC compare failed"); - return VERIFY_MAC_ERROR; - } - - if (ret != 0) - return VERIFY_MAC_ERROR; - return 0; -} - - -int DoApplicationData(CYASSL* 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.handShakeState != HANDSHAKE_DONE) { - CYASSL_MSG("Received App data before handshake complete"); - 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) { - ivExtra = AEAD_EXP_IV_SZ; - } - - dataSz = msgSz - ivExtra - ssl->keys.padSz; - if (dataSz < 0) { - CYASSL_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(CYASSL* ssl, byte* input, word32* inOutIdx, int* type, - word32 totalSz) -{ - byte level; - byte code; - - #ifdef CYASSL_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 */ - } - - CYASSL_MSG("Got alert"); - if (*type == close_notify) { - CYASSL_MSG(" close notify"); - ssl->options.closeNotify = 1; - } - CYASSL_ERROR(*type); - - if (ssl->keys.encryptionOn) { - if (*inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz; - } - - return level; -} - -static int GetInputData(CYASSL *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 CYASSL_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(CYASSL* 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)) { - CYASSL_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(CYASSL* ssl) -{ - int ret = 0, type, readSz; - int atomicUser = 0; - word32 startIdx = 0; -#ifndef NO_CYASSL_SERVER - byte b0, b1; -#endif -#ifdef CYASSL_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){ - CYASSL_MSG("ProcessReply retry in error state, not allowed"); - return ssl->error; - } - - for (;;) { - switch (ssl->options.processReply) { - - /* in the CYASSL_SERVER case, get the first byte for detecting - * old client hello */ - case doProcessInit: - - readSz = RECORD_HEADER_SZ; - - #ifdef CYASSL_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 CYASSL_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 - } - -#ifndef NO_CYASSL_SERVER - - /* see if sending SSLv2 client hello */ - if ( ssl->options.side == CYASSL_SERVER_END && - ssl->options.clientState == NULL_STATE && - ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx] - != handshake) { - ssl->options.processReply = runProcessOldClientHello; - - /* 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 CYASSL_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 CYASSL_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 /* CYASSL_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 /* NO_CYASSL_SERVER */ - - /* get the record layer header */ - case getRecordLayerHeader: - - ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, - &ssl->curRL, &ssl->curSize); -#ifdef CYASSL_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 CYASSL_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 CYASSL_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->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) { - CYASSL_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->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) { - CYASSL_ERROR(ret); - return DECRYPT_ERROR; - } - ssl->keys.encryptSz = ssl->curSize; - ssl->keys.decryptedCur = 1; - } - - if (ssl->options.dtls) { - #ifdef CYASSL_DTLS - DtlsUpdateWindow(&ssl->keys.dtls_state); - #endif /* CYASSL_DTLS */ - } - - CYASSL_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 CYASSL_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: - CYASSL_MSG("got CHANGE CIPHER SPEC"); - #ifdef CYASSL_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 - - if (ssl->curSize != 1) { - CYASSL_MSG("Malicious or corrupted ChangeCipher msg"); - return LENGTH_ERROR; - } - #ifndef NO_CERTS - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.verifyPeer && - ssl->options.havePeerCert) - if (!ssl->options.havePeerVerify) { - CYASSL_MSG("client didn't send cert verify"); - return NO_PEER_VERIFY; - } - #endif - - - ssl->buffers.inputBuffer.idx++; - ssl->keys.encryptionOn = 1; - - #ifdef CYASSL_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 == - CYASSL_CLIENT_END) - ret = BuildFinished(ssl, &ssl->verifyHashes, server); - else if (!ssl->options.resuming && ssl->options.side == - CYASSL_SERVER_END) - ret = BuildFinished(ssl, &ssl->verifyHashes, client); - if (ret != 0) - return ret; - break; - - case application_data: - CYASSL_MSG("got app DATA"); - if ((ret = DoApplicationData(ssl, - ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx)) - != 0) { - CYASSL_ERROR(ret); - return ret; - } - break; - - case alert: - CYASSL_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: - CYASSL_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) { - CYASSL_MSG("More messages in record"); - #ifdef CYASSL_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; - continue; - } - /* more records */ - else { - CYASSL_MSG("More records in input"); - ssl->options.processReply = doProcessInit; - continue; - } - - default: - CYASSL_MSG("Bad process input state, programming error"); - return INPUT_CASE_ERROR; - } - } -} - - -int SendChangeCipher(CYASSL* ssl) -{ - byte *output; - int sendSz = RECORD_HEADER_SZ + ENUM_LEN; - int idx = RECORD_HEADER_SZ; - int ret; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA; - idx += DTLS_RECORD_EXTRA; - } - #endif - - /* 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 */ - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - #ifdef CYASSL_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 CYASSL_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(CYASSL* 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 = CyaSSL_GetMacSecret(ssl, verify); - - 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(CYASSL* 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(CYASSL* 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(CYASSL* 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 CYASSL_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 CYASSL_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 CYASSL_SHA384 - ssl->hashSha384 = sha384; - #endif - } - - return 0; -} - -#endif /* CYASSL_LEANPSK */ - -/* Build SSL Message, encrypted */ -static int BuildMessage(CYASSL* ssl, byte* output, 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 CYASSL_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; - - 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) { - 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 - 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) { - byte hmac[MAX_DIGEST_SIZE]; - - ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz, - type, 0); - XMEMCPY(output + idx, hmac, digestSz); - } 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(CYASSL* 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; - - #ifdef CYASSL_DTLS - word32 sequence_number = ssl->keys.dtls_sequence_number; - word16 epoch = ssl->keys.dtls_epoch; - #endif - - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0) - return ret; - - #ifdef CYASSL_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 == CYASSL_CLIENT_END ? client : server); - if (ret != 0) return ret; - - sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake); - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - ssl->keys.dtls_epoch = epoch; - ssl->keys.dtls_sequence_number = sequence_number; - } - #endif - - if (sendSz < 0) - return BUILD_MSG_ERROR; - - if (!ssl->options.resuming) { -#ifndef NO_SESSION_CACHE - AddSession(ssl); /* just try */ -#endif - if (ssl->options.side == CYASSL_CLIENT_END) { - ret = BuildFinished(ssl, &ssl->verifyHashes, server); - if (ret != 0) return ret; - } - else { - ssl->options.handShakeState = HANDSHAKE_DONE; - #ifdef CYASSL_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 == CYASSL_CLIENT_END) { - ssl->options.handShakeState = HANDSHAKE_DONE; - #ifdef CYASSL_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 CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - #ifdef CYASSL_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(CYASSL* 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) 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 CYASSL_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, 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); - /* if add more to output adjust i - i += ssl->buffers.certChain.length; */ - } - } - #ifdef CYASSL_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 CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, - ssl->heap); - #endif - - if (ssl->options.side == CYASSL_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(CYASSL* ssl) -{ - byte *output; - int ret; - int sendSz; - word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - - int typeTotal = 1; /* only rsa 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) return 0; /* not needed */ - - sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; - - #ifdef CYASSL_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 */ - 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 CYASSL_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 CYASSL_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(CYASSL* ssl, const void* data, int sz) -{ - int sent = 0, /* plainText size */ - sendSz, - ret; - - if (ssl->error == WANT_WRITE) - ssl->error = 0; - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - int err; - CYASSL_MSG("handshake not complete, trying to finish"); - if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) - return err; - } - - /* last time system socket output buffer was full, try again to send */ - if (ssl->buffers.outputBuffer.length > 0) { - CYASSL_MSG("output buffer was full, trying to send again"); - if ( (ssl->error = SendBuffered(ssl)) < 0) { - CYASSL_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; - CYASSL_MSG("sent write buffered data"); - } - } - - 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 */ -#ifdef HAVE_LIBZ - byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; -#endif - - if (sent == sz) break; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - len = min(len, MAX_UDP_SIZE); - buffSz = len; - } -#endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, len + COMP_EXTRA + - MAX_MSG_EXTRA)) != 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, sendBuffer, buffSz, - application_data); - - ssl->buffers.outputBuffer.length += sendSz; - - if ( (ret = SendBuffered(ssl)) < 0) { - CYASSL_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) { - CYASSL_MSG("Paritial Write on, only sending one record"); - break; - } - } - - return sent; -} - -/* process input data */ -int ReceiveData(CYASSL* ssl, byte* output, int sz, int peek) -{ - int size; - - CYASSL_ENTER("ReceiveData()"); - - if (ssl->error == WANT_READ) - ssl->error = 0; - - if (ssl->error != 0 && ssl->error != WANT_WRITE) { - CYASSL_MSG("User calling CyaSSL_read in error state, not allowed"); - return ssl->error; - } - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - int err; - CYASSL_MSG("Handshake not complete, trying to finish"); - if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) - return err; - } - - while (ssl->buffers.clearOutputBuffer.length == 0) - if ( (ssl->error = ProcessReply(ssl)) < 0) { - CYASSL_ERROR(ssl->error); - if (ssl->error == ZERO_RETURN) { - CYASSL_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) { - CYASSL_MSG("Peer reset or closed, connection done"); - return 0; /* peer reset or closed */ - } - } - return ssl->error; - } - - 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); - - CYASSL_LEAVE("ReceiveData()", size); - return size; -} - - -/* send alert message */ -int SendAlert(CYASSL* ssl, int severity, int type) -{ - byte input[ALERT_SIZE]; - byte *output; - int sendSz; - int ret; - 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 CYASSL_DTLS - if (ssl->options.dtls) - dtlsExtra = DTLS_RECORD_EXTRA; - #endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, - ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra)) != 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.handShakeState == HANDSHAKE_DONE) - sendSz = BuildMessage(ssl, output, input, ALERT_SIZE, alert); - else { - - AddRecordHeader(output, ALERT_SIZE, alert, ssl); - output += RECORD_HEADER_SZ; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - output += DTLS_RECORD_EXTRA; - #endif - XMEMCPY(output, input, ALERT_SIZE); - - sendSz = RECORD_HEADER_SZ + ALERT_SIZE; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - sendSz += DTLS_RECORD_EXTRA; - #endif - } - - #ifdef CYASSL_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); -} - - - -void SetErrorString(int error, char* str) -{ - const int max = CYASSL_MAX_ERROR_SZ; /* shorthand */ - -#ifdef NO_ERROR_STRINGS - - (void)error; - XSTRNCPY(str, "no support for error strings built in", max); - -#else - - /* pass to CTaoCrypt */ - if (error < MAX_CODE_E && error > MIN_CODE_E) { - CTaoCryptErrorString(error, str); - return; - } - - switch (error) { - - case UNSUPPORTED_SUITE : - XSTRNCPY(str, "unsupported cipher suite", max); - break; - - case INPUT_CASE_ERROR : - XSTRNCPY(str, "input state error", max); - break; - - case PREFIX_ERROR : - XSTRNCPY(str, "bad index to key rounds", max); - break; - - case MEMORY_ERROR : - XSTRNCPY(str, "out of memory", max); - break; - - case VERIFY_FINISHED_ERROR : - XSTRNCPY(str, "verify problem on finished", max); - break; - - case VERIFY_MAC_ERROR : - XSTRNCPY(str, "verify mac problem", max); - break; - - case PARSE_ERROR : - XSTRNCPY(str, "parse error on header", max); - break; - - case SIDE_ERROR : - XSTRNCPY(str, "wrong client/server type", max); - break; - - case NO_PEER_CERT : - XSTRNCPY(str, "peer didn't send cert", max); - break; - - case UNKNOWN_HANDSHAKE_TYPE : - XSTRNCPY(str, "weird handshake type", max); - break; - - case SOCKET_ERROR_E : - XSTRNCPY(str, "error state on socket", max); - break; - - case SOCKET_NODATA : - XSTRNCPY(str, "expected data, not there", max); - break; - - case INCOMPLETE_DATA : - XSTRNCPY(str, "don't have enough data to complete task", max); - break; - - case UNKNOWN_RECORD_TYPE : - XSTRNCPY(str, "unknown type in record hdr", max); - break; - - case DECRYPT_ERROR : - XSTRNCPY(str, "error during decryption", max); - break; - - case FATAL_ERROR : - XSTRNCPY(str, "revcd alert fatal error", max); - break; - - case ENCRYPT_ERROR : - XSTRNCPY(str, "error during encryption", max); - break; - - case FREAD_ERROR : - XSTRNCPY(str, "fread problem", max); - break; - - case NO_PEER_KEY : - XSTRNCPY(str, "need peer's key", max); - break; - - case NO_PRIVATE_KEY : - XSTRNCPY(str, "need the private key", max); - break; - - case NO_DH_PARAMS : - XSTRNCPY(str, "server missing DH params", max); - break; - - case RSA_PRIVATE_ERROR : - XSTRNCPY(str, "error during rsa priv op", max); - break; - - case MATCH_SUITE_ERROR : - XSTRNCPY(str, "can't match cipher suite", max); - break; - - case BUILD_MSG_ERROR : - XSTRNCPY(str, "build message failure", max); - break; - - case BAD_HELLO : - XSTRNCPY(str, "client hello malformed", max); - break; - - case DOMAIN_NAME_MISMATCH : - XSTRNCPY(str, "peer subject name mismatch", max); - break; - - case WANT_READ : - case SSL_ERROR_WANT_READ : - XSTRNCPY(str, "non-blocking socket wants data to be read", max); - break; - - case NOT_READY_ERROR : - XSTRNCPY(str, "handshake layer not ready yet, complete first", max); - break; - - case PMS_VERSION_ERROR : - XSTRNCPY(str, "premaster secret version mismatch error", max); - break; - - case VERSION_ERROR : - XSTRNCPY(str, "record layer version error", max); - break; - - case WANT_WRITE : - case SSL_ERROR_WANT_WRITE : - XSTRNCPY(str, "non-blocking socket write buffer full", max); - break; - - case BUFFER_ERROR : - XSTRNCPY(str, "malformed buffer input error", max); - break; - - case VERIFY_CERT_ERROR : - XSTRNCPY(str, "verify problem on certificate", max); - break; - - case VERIFY_SIGN_ERROR : - XSTRNCPY(str, "verify problem based on signature", max); - break; - - case CLIENT_ID_ERROR : - XSTRNCPY(str, "psk client identity error", max); - break; - - case SERVER_HINT_ERROR: - XSTRNCPY(str, "psk server hint error", max); - break; - - case PSK_KEY_ERROR: - XSTRNCPY(str, "psk key callback error", max); - break; - - case NTRU_KEY_ERROR: - XSTRNCPY(str, "NTRU key error", max); - break; - - case NTRU_DRBG_ERROR: - XSTRNCPY(str, "NTRU drbg error", max); - break; - - case NTRU_ENCRYPT_ERROR: - XSTRNCPY(str, "NTRU encrypt error", max); - break; - - case NTRU_DECRYPT_ERROR: - XSTRNCPY(str, "NTRU decrypt error", max); - break; - - case ZLIB_INIT_ERROR: - XSTRNCPY(str, "zlib init error", max); - break; - - case ZLIB_COMPRESS_ERROR: - XSTRNCPY(str, "zlib compress error", max); - break; - - case ZLIB_DECOMPRESS_ERROR: - XSTRNCPY(str, "zlib decompress error", max); - break; - - case GETTIME_ERROR: - XSTRNCPY(str, "gettimeofday() error", max); - break; - - case GETITIMER_ERROR: - XSTRNCPY(str, "getitimer() error", max); - break; - - case SIGACT_ERROR: - XSTRNCPY(str, "sigaction() error", max); - break; - - case SETITIMER_ERROR: - XSTRNCPY(str, "setitimer() error", max); - break; - - case LENGTH_ERROR: - XSTRNCPY(str, "record layer length error", max); - break; - - case PEER_KEY_ERROR: - XSTRNCPY(str, "cant decode peer key", max); - break; - - case ZERO_RETURN: - case SSL_ERROR_ZERO_RETURN: - XSTRNCPY(str, "peer sent close notify alert", max); - break; - - case ECC_CURVETYPE_ERROR: - XSTRNCPY(str, "Bad ECC Curve Type or unsupported", max); - break; - - case ECC_CURVE_ERROR: - XSTRNCPY(str, "Bad ECC Curve or unsupported", max); - break; - - case ECC_PEERKEY_ERROR: - XSTRNCPY(str, "Bad ECC Peer Key", max); - break; - - case ECC_MAKEKEY_ERROR: - XSTRNCPY(str, "ECC Make Key failure", max); - break; - - case ECC_EXPORT_ERROR: - XSTRNCPY(str, "ECC Export Key failure", max); - break; - - case ECC_SHARED_ERROR: - XSTRNCPY(str, "ECC DHE shared failure", max); - break; - - case NOT_CA_ERROR: - XSTRNCPY(str, "Not a CA by basic constraint error", max); - break; - - case BAD_PATH_ERROR: - XSTRNCPY(str, "Bad path for opendir error", max); - break; - - case BAD_CERT_MANAGER_ERROR: - XSTRNCPY(str, "Bad Cert Manager error", max); - break; - - case OCSP_CERT_REVOKED: - XSTRNCPY(str, "OCSP Cert revoked", max); - break; - - case CRL_CERT_REVOKED: - XSTRNCPY(str, "CRL Cert revoked", max); - break; - - case CRL_MISSING: - XSTRNCPY(str, "CRL missing, not loaded", max); - break; - - case MONITOR_RUNNING_E: - XSTRNCPY(str, "CRL monitor already running", max); - break; - - case THREAD_CREATE_E: - XSTRNCPY(str, "Thread creation problem", max); - break; - - case OCSP_NEED_URL: - XSTRNCPY(str, "OCSP need URL", max); - break; - - case OCSP_CERT_UNKNOWN: - XSTRNCPY(str, "OCSP Cert unknown", max); - break; - - case OCSP_LOOKUP_FAIL: - XSTRNCPY(str, "OCSP Responder lookup fail", max); - break; - - case MAX_CHAIN_ERROR: - XSTRNCPY(str, "Maximum Chain Depth Exceeded", max); - break; - - case COOKIE_ERROR: - XSTRNCPY(str, "DTLS Cookie Error", max); - break; - - case SEQUENCE_ERROR: - XSTRNCPY(str, "DTLS Sequence Error", max); - break; - - case SUITES_ERROR: - XSTRNCPY(str, "Suites Pointer Error", max); - break; - - case SSL_NO_PEM_HEADER: - XSTRNCPY(str, "No PEM Header Error", max); - break; - - case OUT_OF_ORDER_E: - XSTRNCPY(str, "Out of order message, fatal", max); - break; - - case BAD_KEA_TYPE_E: - XSTRNCPY(str, "Bad KEA type found", max); - break; - - case SANITY_CIPHER_E: - XSTRNCPY(str, "Sanity check on ciphertext failed", max); - break; - - case RECV_OVERFLOW_E: - XSTRNCPY(str, "Receive callback returned more than requested", max); - break; - - case GEN_COOKIE_E: - XSTRNCPY(str, "Generate Cookie Error", max); - break; - - case NO_PEER_VERIFY: - XSTRNCPY(str, "Need peer certificate verify Error", max); - break; - - case FWRITE_ERROR: - XSTRNCPY(str, "fwrite Error", max); - break; - - case CACHE_MATCH_ERROR: - XSTRNCPY(str, "Cache restore header match Error", max); - break; - - case UNKNOWN_SNI_HOST_NAME_E: - XSTRNCPY(str, "Unrecognized host name Error", max); - break; - - case KEYUSE_SIGNATURE_E: - XSTRNCPY(str, "Key Use digitalSignature not set Error", max); - break; - - case KEYUSE_ENCIPHER_E: - XSTRNCPY(str, "Key Use keyEncipherment not set Error", max); - break; - - case EXTKEYUSE_AUTH_E: - XSTRNCPY(str, "Ext Key Use server/client auth not set Error", max); - break; - - default : - XSTRNCPY(str, "unknown error number", max); - } - -#endif /* NO_ERROR_STRINGS */ -} - - - -/* 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_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_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_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 - -}; - - - -/* 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_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_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_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 -}; - - -/* return true if set, else false */ -/* only supports full name from cipher_name[] delimited by : */ -int SetCipherList(Suites* s, const char* list) -{ - int ret = 0, i; - char name[MAX_SUITE_NAME]; - - char needle[] = ":"; - char* haystack = (char*)list; - char* prev; - - const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); - int idx = 0; - int haveRSA = 0, haveECDSA = 0; - - if (s == NULL) { - CYASSL_MSG("SetCipherList suite pointer error"); - return 0; - } - - if (!list) - return 0; - - if (*list == 0) return 1; /* CyaSSL default */ - - if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1; /* CyaSSL defualt */ - - for(;;) { - word32 len; - prev = haystack; - haystack = XSTRSTR(haystack, needle); - - if (!haystack) /* last cipher */ - len = min(sizeof(name), (word32)XSTRLEN(prev)); - else - len = min(sizeof(name), (word32)(haystack - prev)); - - XSTRNCPY(name, prev, len); - name[(len == sizeof(name)) ? len - 1 : len] = 0; - - for (i = 0; i < suiteSz; i++) - if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { - if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM")) - s->suites[idx++] = ECC_BYTE; /* ECC suite */ - else - s->suites[idx++] = 0x00; /* normal */ - s->suites[idx++] = (byte)cipher_name_idx[i]; - - /* The suites are either ECDSA, RSA, or PSK. The RSA suites - * don't necessarily have RSA in the name. */ - if ((haveECDSA == 0) && XSTRSTR(name, "ECDSA")) { - haveECDSA = 1; - } - else if ((haveRSA == 0) && (XSTRSTR(name, "PSK") == NULL)) { - haveRSA = 1; - } - - if (!ret) ret = 1; /* found at least one */ - break; - } - if (!haystack) break; - haystack++; - } - - if (ret) { - s->setSuites = 1; - s->suiteSz = (word16)idx; - - idx = 0; - - if (haveECDSA) { - #ifdef CYASSL_SHA384 - s->hashSigAlgo[idx++] = sha384_mac; - s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - #ifndef NO_SHA256 - s->hashSigAlgo[idx++] = sha256_mac; - s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - s->hashSigAlgo[idx++] = sha_mac; - s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - } - - if (haveRSA) { - #ifdef CYASSL_SHA384 - s->hashSigAlgo[idx++] = sha384_mac; - s->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - #ifndef NO_SHA256 - s->hashSigAlgo[idx++] = sha256_mac; - s->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - s->hashSigAlgo[idx++] = sha_mac; - s->hashSigAlgo[idx++] = rsa_sa_algo; - } - - s->hashSigAlgoSz = (word16)idx; - } - - return ret; -} - - -static void PickHashSigAlgo(CYASSL* ssl, - const byte* hashSigAlgo, word32 hashSigAlgoSz) -{ - word32 i; - - ssl->suites->sigAlgo = ssl->specs.sig_algo; - ssl->suites->hashAlgo = sha_mac; - - for (i = 0; i < 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 CYASSL_SHA384 - else if (hashSigAlgo[i] == sha384_mac) { - ssl->suites->hashAlgo = sha384_mac; - break; - } - #endif - } - } -} - - -#ifdef CYASSL_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 CYASSL* 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 /* CYASSL_CALLBACKS */ - - - -/* client only parts */ -#ifndef NO_CYASSL_CLIENT - - int SendClientHello(CYASSL* ssl) - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - int idSz = ssl->options.resuming ? ID_LEN : 0; - int ret; - - if (ssl->suites == NULL) { - CYASSL_MSG("Bad suites pointer in SendClientHello"); - return SUITES_ERROR; - } - - 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 CYASSL_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 - - /* 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 CYASSL_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, ID_LEN); - idx += ID_LEN; - } - - /* then DTLS cookie */ -#ifdef CYASSL_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 - - #ifdef CYASSL_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; - - ssl->options.clientState = CLIENT_HELLO_COMPLETE; - -#ifdef CYASSL_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(CYASSL* ssl, const byte* input, - word32* inOutIdx, word32 size) - { - ProtocolVersion pv; - byte cookieSz; - word32 begin = *inOutIdx; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest", - &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); -#endif - -#ifdef CYASSL_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 CYASSL_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 int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 helloSz) - { - byte b; - ProtocolVersion pv; - byte compression; - word32 i = *inOutIdx; - word32 begin = i; - -#ifdef CYASSL_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) { - CYASSL_MSG("Server using higher version, fatal error"); - return VERSION_ERROR; - } - else if (pv.minor < ssl->version.minor) { - CYASSL_MSG("server using lower version"); - - if (!ssl->options.downgrade) { - CYASSL_MSG(" no downgrade allowed, fatal error"); - return VERSION_ERROR; - } - - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - CYASSL_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+ */ - CYASSL_MSG(" downgrading to TLSv1"); - ssl->options.tls1_1 = 0; - ssl->version.minor = TLSv1_MINOR; - } - else if (pv.minor == TLSv1_1_MINOR) { - CYASSL_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 */ - b = input[i++]; - - if (b == ID_LEN) { - if ((i - begin) + ID_LEN > helloSz) - return BUFFER_ERROR; - - XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN)); - i += ID_LEN; - ssl->options.haveSessionId = 1; - } - else if (b) { - CYASSL_MSG("Invalid session ID size"); - return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ - } - - /* suite and compression */ - if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - ssl->options.cipherSuite0 = input[i++]; - ssl->options.cipherSuite = input[i++]; - compression = input[i++]; - - if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) { - CYASSL_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 (IsTLS(ssl)) { - int ret = 0; - word16 totalExtSz; - Suites clSuites; /* just for compatibility right now */ - - 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, &clSuites))) - return ret; - - i += totalExtSz; - *inOutIdx = i; - } - else -#endif - *inOutIdx = begin + helloSz; /* skip extensions */ - } - - ssl->options.serverState = SERVER_HELLO_COMPLETE; - - if (ssl->options.resuming) { - if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, - ssl->session.sessionID, ID_LEN) == 0) { - 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 { - CYASSL_MSG("Unsupported cipher suite, DoServerHello"); - return UNSUPPORTED_SUITE; - } - } - else { - CYASSL_MSG("Server denied resumption attempt"); - ssl->options.resuming = 0; /* server denied resumption try */ - } - } - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - DtlsPoolReset(ssl); - } - #endif - - return SetCipherSpecs(ssl); - } - - -#ifndef NO_CERTS - /* just read in and ignore for now TODO: */ - static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32* - inOutIdx, word32 size) - { - word16 len; - word32 begin = *inOutIdx; - - #ifdef CYASSL_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; - - return 0; - } -#endif /* !NO_CERTS */ - - - static int DoServerKeyExchange(CYASSL* ssl, const byte* input, - word32* inOutIdx, word32 size) - { - word16 length = 0; - word32 begin = *inOutIdx; - int ret = 0; - - (void)length; /* shut up compiler warnings */ - (void)begin; - (void)ssl; - (void)input; - (void)size; - (void)ret; - - #ifdef CYASSL_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 - #ifdef OPENSSL_EXTRA - 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 /* OPENSSL_EXTRA */ - - #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 (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0) - return ECC_PEERKEY_ERROR; - - *inOutIdx += length; - ssl->peerEccKeyPresent = 1; - } - #endif /* HAVE_ECC */ - - #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) - { -#ifndef NO_OLD_TLS - Md5 md5; - Sha sha; -#endif -#ifndef NO_SHA256 - Sha256 sha256; - byte hash256[SHA256_DIGEST_SIZE]; -#endif -#ifdef CYASSL_SHA384 - Sha384 sha384; - byte hash384[SHA384_DIGEST_SIZE]; -#endif - byte hash[FINISHED_SZ]; - byte messageVerify[MAX_DH_SZ]; - byte hashAlgo = sha_mac; - byte sigAlgo = ssl->specs.sig_algo; - word16 verifySz = (word16) (*inOutIdx - begin); - - /* save message for hash verify */ - if (verifySz > sizeof(messageVerify)) - return BUFFER_ERROR; - - XMEMCPY(messageVerify, input + begin, verifySz); - - if (IsAtLeastTLSv1_2(ssl)) { - if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size) - return BUFFER_ERROR; - - hashAlgo = input[(*inOutIdx)++]; - sigAlgo = input[(*inOutIdx)++]; - } - - /* signature */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &length); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - /* inOutIdx updated at the end of the function */ - - /* verify signature */ -#ifndef NO_OLD_TLS - /* md5 */ - InitMd5(&md5); - Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); - Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); - Md5Update(&md5, messageVerify, verifySz); - Md5Final(&md5, hash); - - /* sha */ - ret = InitSha(&sha); - if (ret != 0) - return ret; - 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 - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, messageVerify, verifySz); - if (ret != 0) - return ret; - ret = Sha256Final(&sha256, hash256); - if (ret != 0) - return ret; -#endif - -#ifdef CYASSL_SHA384 - ret = InitSha384(&sha384); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, messageVerify, verifySz); - if (ret != 0) - return ret; - ret = Sha384Final(&sha384, hash384); - if (ret != 0) - return ret; -#endif - -#ifndef NO_RSA - /* rsa */ - if (sigAlgo == rsa_sa_algo) - { - byte* out = NULL; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaVerifyCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - if (!ssl->peerRsaKeyPresent) - return NO_PEER_KEY; - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->RsaVerifyCb(ssl, (byte *) input + *inOutIdx, - length, &out, - ssl->buffers.peerRsaKey.buffer, - ssl->buffers.peerRsaKey.length, - ssl->RsaVerifyCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaSSL_VerifyInline((byte *) input + *inOutIdx, length, - &out, ssl->peerRsaKey); - } - - if (IsAtLeastTLSv1_2(ssl)) { - byte encodedSig[MAX_ENCODED_SIG_SZ]; - 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 - - 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 CYASSL_SHA384 - digest = hash384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - - encSigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); - - if (encSigSz != (word32)ret || !out || XMEMCMP(out, encodedSig, - min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) - return VERIFY_SIGN_ERROR; - } - else { - if (ret != sizeof(hash) || !out || XMEMCMP(out, - hash, sizeof(hash)) != 0) - return VERIFY_SIGN_ERROR; - } - } 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) - return NO_PEER_KEY; - - 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 CYASSL_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) - return VERIFY_SIGN_ERROR; - } - else -#endif /* HAVE_ECC */ - return ALGO_ID_E; - - /* signature length */ - *inOutIdx += length; - - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - - return 0; - } -#else /* HAVE_OPENSSL or HAVE_ECC */ - return NOT_COMPILED_IN; /* not supported by build */ -#endif /* HAVE_OPENSSL or HAVE_ECC */ - } - - - int SendClientKeyExchange(CYASSL* ssl) - { - byte encSecret[MAX_ENCRYPT_SZ]; - 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 */ - - switch (ssl->specs.kea) { - #ifndef NO_RSA - case rsa_kea: - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, - SECRET_LEN); - if (ret != 0) - 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) - return NO_PEER_KEY; - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - encSz = sizeof(encSecret); - 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, sizeof(encSecret), - ssl->peerRsaKey, ssl->rng); - if (ret > 0) { - encSz = ret; - ret = 0; /* set success to 0 */ - } - } - break; - #endif - #ifdef OPENSSL_EXTRA - case diffie_hellman_kea: - { - buffer serverP = ssl->buffers.serverDH_P; - buffer serverG = ssl->buffers.serverDH_G; - buffer serverPub = ssl->buffers.serverDH_Pub; - byte priv[ENCRYPT_LEN]; - word32 privSz = 0; - DhKey key; - - if (serverP.buffer == 0 || serverG.buffer == 0 || - serverPub.buffer == 0) - return NO_PEER_KEY; - - 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); - FreeDhKey(&key); - } - break; - #endif /* OPENSSL_EXTRA */ - #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) - return PSK_KEY_ERROR; - encSz = (word32)XSTRLEN(ssl->arrays->client_identity); - if (encSz > MAX_PSK_ID_LEN) 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 */ - #ifdef HAVE_NTRU - case ntru_kea: - { - word32 rc; - word16 cipherLen = sizeof(encSecret); - DRBG_HANDLE drbg; - static uint8_t const cyasslStr[] = { - 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' - }; - - ret = RNG_GenerateBlock(ssl->rng, - ssl->arrays->preMasterSecret, SECRET_LEN); - if (ret != 0) - return ret; - - ssl->arrays->preMasterSz = SECRET_LEN; - - if (ssl->peerNtruKeyPresent == 0) - return NO_PEER_KEY; - - rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr, - sizeof(cyasslStr), GetEntropy, - &drbg); - if (rc != DRBG_OK) - return NTRU_DRBG_ERROR; - - rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen, - ssl->peerNtruKey, - ssl->arrays->preMasterSz, - ssl->arrays->preMasterSecret, - &cipherLen, encSecret); - crypto_drbg_uninstantiate(drbg); - if (rc != NTRU_OK) - 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 = sizeof(encSecret); - - if (ssl->specs.static_ecdh) { - /* TODO: EccDsa is really fixed Ecc change naming */ - if (!ssl->peerEccDsaKeyPresent || !ssl->peerEccDsaKey->dp) - return NO_PEER_KEY; - peerKey = ssl->peerEccDsaKey; - } - else { - if (!ssl->peerEccKeyPresent || !ssl->peerEccKey->dp) - return NO_PEER_KEY; - peerKey = ssl->peerEccKey; - } - - if (peerKey == NULL) - return NO_PEER_KEY; - - ecc_init(&myKey); - ret = ecc_make_key(ssl->rng, peerKey->dp->size, &myKey); - if (ret != 0) - 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: - 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) /* always off */ - tlsSz = 0; - - sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; - idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_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, encSz + tlsSz, client_key_exchange, ssl); - - if (tlsSz) { - c16toa((word16)encSz, &output[idx]); - idx += 2; - } - XMEMCPY(output + idx, encSecret, encSz); - /* if add more to output, adjust idx - idx += encSz; */ - #ifdef CYASSL_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 CYASSL_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); - } - - 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(CYASSL* ssl) - { - byte *output; - int sendSz = 0, 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 */ - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, MAX_CERT_VERIFY_SZ)) != 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 - CYASSL_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) { - CYASSL_MSG("Using ECC client cert"); - usingEcc = 1; - sigOutSz = MAX_ENCODED_SIG_SZ; - } - else { - CYASSL_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; - byte encodedSig[MAX_ENCODED_SIG_SZ]; - word32 extraSz = 0; /* tls 1.2 hash/sig */ - - (void)encodedSig; - (void)signSz; - (void)signBuffer; - - #ifdef CYASSL_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 CYASSL_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 CYASSL_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 - if (ret == 0) { - AddHeaders(output, length + extraSz + VERIFY_HEADER, - certificate_verify, ssl); - - sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + - extraSz + VERIFY_HEADER; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - } - } -#ifndef NO_RSA - if (initRsaKey) - FreeRsaKey(&key); -#endif -#ifdef HAVE_ECC - ecc_free(&eccKey); -#endif - - if (ret == 0) { - #ifdef CYASSL_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 */ - - -#endif /* NO_CYASSL_CLIENT */ - - -#ifndef NO_CYASSL_SERVER - - int SendServerHello(CYASSL* 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 CYASSL_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 - if (IsTLS(ssl)) - TLSX_WriteResponse(ssl, output + idx); -#endif - - ssl->buffers.outputBuffer.length += sendSz; - #ifdef CYASSL_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 CYASSL_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(CYASSL* ssl) - { - int ret = 0; - (void)ssl; - - #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 CYASSL_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); - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_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 */ - - #ifdef HAVE_ECC - if (ssl->specs.kea == ecc_diffie_hellman_kea) - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - byte exportBuf[MAX_EXPORT_ECC_SZ]; - word32 expSz = sizeof(exportBuf); - word32 sigSz; - word32 preSigSz, preSigIdx; -#ifndef NO_RSA - RsaKey rsaKey; -#endif - ecc_key dsaKey; - - if (ssl->specs.static_ecdh) { - CYASSL_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 */ - CYASSL_MSG("Using ephemeral ECDH"); - if (ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0) - return ECC_EXPORT_ERROR; - length += expSz; - - preSigSz = length; - preSigIdx = idx; - -#ifndef NO_RSA - ret = InitRsaKey(&rsaKey, ssl->heap); - if (ret != 0) return ret; -#endif - ecc_init(&dsaKey); - - /* sig length */ - length += LENGTH_SZ; - - if (!ssl->buffers.key.buffer) { -#ifndef NO_RSA - FreeRsaKey(&rsaKey); -#endif - ecc_free(&dsaKey); - return NO_PRIVATE_KEY; - } - -#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) return ret; - 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) return ret; - sigSz = ecc_sig_size(&dsaKey); /* worst case estimate */ - } - else { -#ifndef NO_RSA - FreeRsaKey(&rsaKey); -#endif - ecc_free(&dsaKey); - return ALGO_ID_E; /* unsupported type */ - } - length += sigSz; - - if (IsAtLeastTLSv1_2(ssl)) - length += HASH_SIG_SIZE; - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_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); - return ret; - } - - /* 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 */ - - /* do signature */ - { -#ifndef NO_OLD_TLS - Md5 md5; - Sha sha; -#endif - byte hash[FINISHED_SZ]; - #ifndef NO_SHA256 - Sha256 sha256; - byte hash256[SHA256_DIGEST_SIZE]; - #endif - #ifdef CYASSL_SHA384 - Sha384 sha384; - byte hash384[SHA384_DIGEST_SIZE]; - #endif - -#ifndef NO_OLD_TLS - /* md5 */ - 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 */ - ret = InitSha(&sha); - if (ret != 0) - return ret; - 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 - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha256Final(&sha256, hash256); - if (ret != 0) - return ret; - #endif - - #ifdef CYASSL_SHA384 - ret = InitSha384(&sha384); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha384Final(&sha384, hash384); - if (ret != 0) - return ret; - #endif -#ifndef NO_RSA - if (ssl->suites->sigAlgo == rsa_sa_algo) { - byte* signBuffer = hash; - word32 signSz = sizeof(hash); - byte encodedSig[MAX_ENCODED_SIG_SZ]; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - 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 CYASSL_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); - if (ret > 0) - ret = 0; /* reset on success */ - } - FreeRsaKey(&rsaKey); - ecc_free(&dsaKey); - if (ret < 0) - return ret; - } 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; - - #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 = &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 CYASSL_SHA384 - digest = hash384; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - } - - if (doUserEcc) { - #ifdef HAVE_PK_CALLBACKS - #ifdef 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 /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - } - 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) return ret; - - /* 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; - } - } - - AddHeaders(output, length, server_key_exchange, ssl); - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_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 /* HAVE_ECC */ - - #ifdef OPENSSL_EXTRA - 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) { - ret = InitRsaKey(&rsaKey, ssl->heap); - if (ret != 0) return ret; - } - if (ret == 0) { - 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; - - /* 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; - } - } - if (ret != 0) { - FreeRsaKey(&rsaKey); - return ret; - } - - if (IsAtLeastTLSv1_2(ssl)) - length += HASH_SIG_SIZE; - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_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) { - 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; - - /* Add signature */ - if (IsAtLeastTLSv1_2(ssl)) { - output[idx++] = ssl->suites->hashAlgo; - output[idx++] = ssl->suites->sigAlgo; - } - /* size */ - c16toa((word16)sigSz, output + idx); - idx += LENGTH_SZ; - - /* do signature */ - { -#ifndef NO_OLD_TLS - Md5 md5; - Sha sha; -#endif - byte hash[FINISHED_SZ]; - #ifndef NO_SHA256 - Sha256 sha256; - byte hash256[SHA256_DIGEST_SIZE]; - #endif - #ifdef CYASSL_SHA384 - Sha384 sha384; - byte hash384[SHA384_DIGEST_SIZE]; - #endif - -#ifndef NO_OLD_TLS - /* md5 */ - 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 */ - ret = InitSha(&sha); - if (ret != 0) - return ret; - 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 - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha256Final(&sha256, hash256); - if (ret != 0) - return ret; - #endif - - #ifdef CYASSL_SHA384 - ret = InitSha384(&sha384); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha384Final(&sha384, hash384); - if (ret != 0) - return ret; - #endif -#ifndef NO_RSA - if (ssl->suites->sigAlgo == rsa_sa_algo) { - byte* signBuffer = hash; - word32 signSz = sizeof(hash); - byte encodedSig[MAX_ENCODED_SIG_SZ]; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - 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 CYASSL_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 /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaSSL_Sign(signBuffer, signSz, output + idx, - sigSz, &rsaKey, ssl->rng); - } - FreeRsaKey(&rsaKey); - if (ret < 0) - return ret; - } -#endif - } - - #ifdef CYASSL_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 CYASSL_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 /* OPENSSL_EXTRA */ - - 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) - { - /* 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; - - default: - CYASSL_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_CBC_SHA256 : - case TLS_PSK_WITH_AES_128_CBC_SHA : - case TLS_PSK_WITH_AES_256_CBC_SHA : - case TLS_PSK_WITH_NULL_SHA256 : - case TLS_PSK_WITH_NULL_SHA : - 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 - - default: - CYASSL_MSG("Unsupported cipher suite, CipherRequires"); - return 0; - } /* switch */ - } /* if ECC / Normal suites else */ - - return 0; - } - - - /* Make sure client setup is valid for this suite, true on success */ - int VerifyClientSuite(CYASSL* ssl) - { - int havePSK = 0; - byte first = ssl->options.cipherSuite0; - byte second = ssl->options.cipherSuite; - - CYASSL_ENTER("VerifyClientSuite"); - - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #endif - - if (CipherRequires(first, second, REQUIRES_PSK)) { - CYASSL_MSG("Requires PSK"); - if (havePSK == 0) { - CYASSL_MSG("Don't have PSK"); - return 0; - } - } - - return 1; /* success */ - } - - - /* Make sure server cert/key are valid for this suite, true on success */ - static int VerifyServerSuite(CYASSL* ssl, word16 idx) - { - int haveRSA = !ssl->options.haveStaticECC; - int havePSK = 0; - byte first; - byte second; - - CYASSL_ENTER("VerifyServerSuite"); - - if (ssl->suites == NULL) { - CYASSL_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)) { - CYASSL_MSG("Requires RSA"); - if (haveRSA == 0) { - CYASSL_MSG("Don't have RSA"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_DHE)) { - CYASSL_MSG("Requires DHE"); - if (ssl->options.haveDH == 0) { - CYASSL_MSG("Don't have DHE"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_ECC_DSA)) { - CYASSL_MSG("Requires ECCDSA"); - if (ssl->options.haveECDSAsig == 0) { - CYASSL_MSG("Don't have ECCDSA"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) { - CYASSL_MSG("Requires static ECC"); - if (ssl->options.haveStaticECC == 0) { - CYASSL_MSG("Don't have static ECC"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_PSK)) { - CYASSL_MSG("Requires PSK"); - if (havePSK == 0) { - CYASSL_MSG("Don't have PSK"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_NTRU)) { - CYASSL_MSG("Requires NTRU"); - if (ssl->options.haveNTRU == 0) { - CYASSL_MSG("Don't have NTRU"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_RSA_SIG)) { - CYASSL_MSG("Requires RSA Signature"); - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.haveECDSAsig == 1) { - CYASSL_MSG("Don't have RSA Signature"); - return 0; - } - } - -#ifdef HAVE_SUPPORTED_CURVES - if (!TLSX_ValidateEllipticCurves(ssl, first, second)) { - CYASSL_MSG("Don't have matching curves"); - return 0; - } -#endif - - /* ECCDHE is always supported if ECC on */ - - return 1; - } - - - static int MatchSuite(CYASSL* ssl, Suites* peerSuites) - { - word16 i, j; - - CYASSL_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; - CYASSL_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 { - CYASSL_MSG("Could not verify suite validity, continue"); - } - } - - return MATCH_SUITE_ERROR; - } - - - /* process old style client hello, deprecate? */ - int ProcessOldClientHello(CYASSL* 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; - CYASSL_MSG("Got old format client hello"); -#ifdef CYASSL_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) { - CYASSL_MSG("Client trying to connect with lesser version"); - return VERSION_ERROR; - } - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - CYASSL_MSG(" downgrading to SSLv3"); - ssl->options.tls = 0; - ssl->options.tls1_1 = 0; - ssl->version.minor = SSLv3_MINOR; - } - else if (pv.minor == TLSv1_MINOR) { - CYASSL_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) { - CYASSL_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; - CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); - if (!session) { - CYASSL_MSG("Session lookup for resume failed"); - ssl->options.resuming = 0; - } else { - if (MatchSuite(ssl, &clSuites) < 0) { - CYASSL_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); - } - - - static int DoClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 helloSz) - { - byte b; - ProtocolVersion pv; - Suites clSuites; - word32 i = *inOutIdx; - word32 begin = i; - -#ifdef CYASSL_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) { - CYASSL_MSG("Client trying to connect with lesser version"); - return VERSION_ERROR; - } - - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - CYASSL_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+ */ - CYASSL_MSG(" downgrading to TLSv1"); - ssl->options.tls1_1 = 0; - ssl->version.minor = TLSv1_MINOR; - } - else if (pv.minor == TLSv1_1_MINOR) { - CYASSL_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 */ - CYASSL_MSG("Client wants to resume session"); - } - else if (b) { - CYASSL_MSG("Invalid session ID size"); - return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ - } - - #ifdef CYASSL_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) { - CYASSL_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) { - CYASSL_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 (IsTLS(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; - } - 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; - CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); - - if (!session) { - CYASSL_MSG("Session lookup for resume failed"); - ssl->options.resuming = 0; - } - else { - if (MatchSuite(ssl, &clSuites) < 0) { - CYASSL_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(CYASSL* 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 CYASSL_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 */ - - CYASSL_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)) { - byte encodedSig[MAX_ENCODED_SIG_SZ]; - word32 sigSz; - byte* digest = ssl->certHashes.sha; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; - - if (sigAlgo != rsa_sa_algo) { - CYASSL_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 CYASSL_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 */ - } - 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 - - CYASSL_MSG("Doing ECC peer cert verify"); - - if (IsAtLeastTLSv1_2(ssl)) { - if (sigAlgo != ecc_dsa_sa_algo) { - CYASSL_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 CYASSL_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(CYASSL* ssl) - { - byte *output; - int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int ret; - - #ifdef CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_DTLS - int SendHelloVerifyRequest(CYASSL* 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) { - CYASSL_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 CYASSL_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(CYASSL* 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; - - if (ssl->options.side != CYASSL_SERVER_END) { - CYASSL_MSG("Client received client keyexchange, attack?"); - CYASSL_ERROR(ssl->error = SIDE_ERROR); - return SSL_FATAL_ERROR; - } - - if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { - CYASSL_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) { - CYASSL_MSG("client didn't present peer cert"); - return NO_PEER_CERT; - } - #endif - - #ifdef CYASSL_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) { - CYASSL_MSG("RSA explicit size doesn't match"); - FreeRsaKey(&key); - return RSA_PRIVATE_ERROR; - } - } - - if ((*inOutIdx - begin) + length > size) { - CYASSL_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 != 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 (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 - 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 */ - #ifdef OPENSSL_EXTRA - 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 /* OPENSSL_EXTRA */ - default: - { - CYASSL_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_CYASSL_SERVER */ - +/* internal.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL 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. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <cyassl/ctaocrypt/settings.h> + +#include <cyassl/internal.h> +#include <cyassl/error-ssl.h> +#include <cyassl/ctaocrypt/asn.h> + +#ifdef HAVE_LIBZ + #include "zlib.h" +#endif + +#ifdef HAVE_NTRU + #include "crypto_ntru.h" +#endif + +#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) + #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(OPENSSL_EXTRA) && defined(NO_DH) + #error OPENSSL_EXTRA needs DH, please remove NO_DH +#endif + +#if defined(CYASSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS) + #error \ +CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS +#endif + + +#ifndef NO_CYASSL_CLIENT + static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*, + word32); + static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); + static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*, + word32); + #ifndef NO_CERTS + static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*, + word32); + #endif +#endif + + +#ifndef NO_CYASSL_SERVER + static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32); + static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32*, word32); + #if !defined(NO_RSA) || defined(HAVE_ECC) + static int DoCertificateVerify(CYASSL* ssl, byte*, word32*, word32); + #endif +#endif + + +#ifdef CYASSL_DTLS + static INLINE int DtlsCheckWindow(DtlsState* state); + static INLINE int DtlsUpdateWindow(DtlsState* state); +#endif + + +typedef enum { + doProcessInit = 0, +#ifndef NO_CYASSL_SERVER + runProcessOldClientHello, +#endif + getRecordLayerHeader, + getData, + runProcessingOneMessage +} processReply; + +#ifndef NO_OLD_TLS +static int SSL_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz, + int content, int verify); + +#endif + +#ifndef NO_CERTS +static int BuildCertHashes(CYASSL* ssl, Hashes* hashes); +#endif + +static void PickHashSigAlgo(CYASSL* 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 CYASSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR) + return 1; + + return 0; +} + + +int IsAtLeastTLSv1_2(const CYASSL* 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 CYASSL_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 /* CYASSL_DTLS */ + + +/* convert 16 bit integer to opaque */ +static INLINE void c16toa(word16 u16, byte* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + + +/* 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; +} + + +/* 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])); +} + + +#ifdef CYASSL_DTLS + +/* 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 /* CYASSL_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(CYASSL* 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(CYASSL* ssl) + { + if (ssl->didStreamInit) { + deflateEnd(&ssl->c_stream); + inflateEnd(&ssl->d_stream); + } + } + + + /* compress in to out, return out size or error */ + static int myCompress(CYASSL* 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(CYASSL* 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(CYASSL_METHOD* method, ProtocolVersion pv) +{ + method->version = pv; + method->side = CYASSL_CLIENT_END; + method->downgrade = 0; +} + + +/* Initialze SSL context, return 0 on success */ +int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_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_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 = DEFAULT_TIMEOUT; + +#ifndef CYASSL_USER_IO + ctx->CBIORecv = EmbedReceive; + ctx->CBIOSend = EmbedSend; + #ifdef CYASSL_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 CYASSL_DTLS + ctx->CBIOCookie = NULL; + #endif +#endif /* CYASSL_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 = CyaSSL_CertManagerNew(); +#endif +#ifdef HAVE_NTRU + if (method->side == CYASSL_CLIENT_END) + ctx->haveNTRU = 1; /* always on cliet side */ + /* server can turn on by loading key */ +#endif +#ifdef HAVE_ECC + if (method->side == CYASSL_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) { + CYASSL_MSG("Mutex error on CTX init"); + return BAD_MUTEX_E; + } +#ifndef NO_CERTS + if (ctx->cm == NULL) { + CYASSL_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(CYASSL_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); + CyaSSL_CertManagerFree(ctx->cm); +#endif +#ifdef HAVE_TLS_EXTENSIONS + TLSX_FreeAll(ctx->extensions); +#endif +} + + +void FreeSSL_Ctx(CYASSL_CTX* ctx) +{ + int doFree = 0; + + if (LockMutex(&ctx->countMutex) != 0) { + CYASSL_MSG("Couldn't lock count mutex"); + return; + } + ctx->refCount--; + if (ctx->refCount == 0) + doFree = 1; + UnLockMutex(&ctx->countMutex); + + if (doFree) { + CYASSL_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; + CYASSL_MSG("CTX ref count not 0 yet, no free"); + } +} + + +/* Set cipher pointers to null */ +void InitCiphers(CYASSL* 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 + ssl->encrypt.setup = 0; + ssl->decrypt.setup = 0; +} + + +/* Free ciphers */ +void FreeCiphers(CYASSL* ssl) +{ + (void)ssl; +#ifdef BUILD_ARC4 + #ifdef HAVE_CAVIUM + if (ssl->devId != NO_CAVIUM_DEVICE) { + Arc4FreeCavium(ssl->encrypt.arc4); + 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) { + AesFreeCavium(ssl->encrypt.aes); + 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 +} + + +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; +} + + +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) { + CYASSL_MSG("InitSuites pointer error"); + return; + } + + if (suites->setSuites) + return; /* trust user settings, don't override */ + + if (side == CYASSL_SERVER_END && haveStaticECC) { + haveRSA = 0; /* can't do RSA with ECDSA key */ + (void)haveRSA; /* some builds won't read */ + } + + if (side == CYASSL_SERVER_END && haveECDSAsig) { + haveRSAsig = 0; /* can't have RSA sig if signed by ECDSA */ + (void)haveRSAsig; /* non ecc builds won't read */ + } + +#ifdef CYASSL_DTLS + if (pv.major == DTLS_MAJOR) { + tls = 1; + tls1_2 = pv.minor <= DTLSv1_2_MINOR; + } +#endif + +#ifdef HAVE_RENEGOTIATION_INDICATION + if (side == CYASSL_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_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_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_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_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_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; + + { + idx = 0; + + if (haveECDSAsig) { + #ifdef CYASSL_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 CYASSL_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 + } + + suites->hashSigAlgoSz = idx; + } +} + + +#ifndef NO_CERTS + + +void InitX509Name(CYASSL_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(CYASSL_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 CyaSSL X509 type */ +void InitX509(CYASSL_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 CYASSL_SEP + x509->certPolicySet = 0; + x509->certPolicyCrit = 0; + #endif /* CYASSL_SEP */ +#endif /* OPENSSL_EXTRA */ +} + + +/* Free CyaSSL X509 type */ +void FreeX509(CYASSL_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(CYASSL* ssl, CYASSL_CTX* ctx) +{ + int ret; + byte haveRSA = 0; + byte havePSK = 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 CYASSL_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 + +#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 CYASSL_SHA384 + ret = InitSha384(&ssl->hashSha384); + if (ret != 0) { + return ret; + } +#endif +#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->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 == CYASSL_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.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 */ + + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = doProcessInit; + +#ifdef CYASSL_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; + +#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 == CYASSL_SERVER_END) { + ssl->buffers.serverDH_P = ctx->serverDH_P; + ssl->buffers.serverDH_G = ctx->serverDH_G; + } +#endif + ssl->buffers.weOwnCert = 0; + ssl->buffers.weOwnKey = 0; + ssl->buffers.weOwnDH = 0; + +#ifdef CYASSL_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 + + ssl->cipher.ssl = ssl; + +#ifdef FORTRESS + ssl->ex_data[0] = 0; + ssl->ex_data[1] = 0; + ssl->ex_data[2] = 0; +#endif + +#ifdef CYASSL_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 +#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_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 */ + + /* increment CTX reference count */ + if (LockMutex(&ctx->countMutex) != 0) { + CYASSL_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) { + CYASSL_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 CYASSL_DTLS + ssl->arrays->cookieSz = 0; +#endif + + /* RNG */ + ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG); + if (ssl->rng == NULL) { + CYASSL_MSG("RNG Memory error"); + return MEMORY_E; + } + + if ( (ret = InitRng(ssl->rng)) != 0) { + CYASSL_MSG("RNG Init error"); + return ret; + } + + /* suites */ + ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, + DYNAMIC_TYPE_SUITES); + if (ssl->suites == NULL) { + CYASSL_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) { + CYASSL_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 */ + if (ssl->options.side == CYASSL_SERVER_END && !havePSK) + if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) { + CYASSL_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) { + CYASSL_MSG("PeerEccKey Memory error"); + return MEMORY_E; + } + ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->peerEccDsaKey == NULL) { + CYASSL_MSG("PeerEccDsaKey Memory error"); + return MEMORY_E; + } + ssl->eccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->eccDsaKey == NULL) { + CYASSL_MSG("EccDsaKey Memory error"); + return MEMORY_E; + } + ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->eccTempKey == NULL) { + CYASSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + ecc_init(ssl->peerEccKey); + ecc_init(ssl->peerEccDsaKey); + ecc_init(ssl->eccDsaKey); + ecc_init(ssl->eccTempKey); +#endif + + /* make sure server has DH parms, and add PSK if there, add NTRU too */ + if (ssl->options.side == CYASSL_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(CYASSL* ssl, int keep) +{ + if (ssl->arrays && keep) { + /* keeps session id for user retrieval */ + XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN); + } + 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(CYASSL* ssl) +{ + FreeCiphers(ssl); + FreeArrays(ssl, 0); + 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 == CYASSL_CLIENT_END) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH); + } + + /* CYASSL_CTX always owns certChain */ + if (ssl->buffers.weOwnCert) + XFREE(ssl->buffers.certificate.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 CYASSL_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) + CyaSSL_BIO_free(ssl->biord); + if (ssl->biord != ssl->biowr) /* in case same as write */ + CyaSSL_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(CYASSL* ssl) +{ + /* 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) { + XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); + ssl->rng = NULL; + } + +#ifdef CYASSL_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(CYASSL* ssl) +{ + FreeSSL_Ctx(ssl->ctx); /* will decrement and free underyling CTX if 0 */ + SSL_ResourceFree(ssl); + XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL); +} + + +#ifdef CYASSL_DTLS + +int DtlsPoolInit(CYASSL* ssl) +{ + if (ssl->dtls_pool == NULL) { + DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool), + ssl->heap, DYNAMIC_TYPE_DTLS_POOL); + if (pool == NULL) { + CYASSL_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(CYASSL* 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_OUT_BUFFER); + if (pBuf->buffer == NULL) { + CYASSL_MSG("DTLS Buffer Memory error"); + return MEMORY_ERROR; + } + XMEMCPY(pBuf->buffer, src, sz); + pBuf->length = (word32)sz; + pool->used++; + } + return 0; +} + + +void DtlsPoolReset(CYASSL* 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_OUT_BUFFER); + pBuf->buffer = NULL; + pBuf->length = 0; + } + pool->used = 0; + } + ssl->dtls_timeout = ssl->dtls_timeout_init; +} + + +int DtlsPoolTimeout(CYASSL* ssl) +{ + int result = -1; + if (ssl->dtls_timeout < ssl->dtls_timeout_max) { + ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; + result = 0; + } + return result; +} + + +int DtlsPoolSend(CYASSL* 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) { + 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 /* CYASSL_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 CYASSL_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 /* CYASSL_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(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(CYASSL* ssl, const byte* output, int sz, int ivSz) +{ + const byte* adj = output + RECORD_HEADER_SZ + ivSz; + sz -= RECORD_HEADER_SZ; + +#ifdef CYASSL_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 CYASSL_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(CYASSL* ssl, const byte* input, int sz) +{ + const byte* adj = input - HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + +#ifdef CYASSL_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 CYASSL_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, CYASSL* 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 CYASSL_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, + CYASSL* ssl) +{ + HandShakeHeader* hs; + (void)ssl; + + /* handshake header */ + hs = (HandShakeHeader*)output; + hs->type = type; + c32to24(length, hs->length); /* type and length same for each */ +#ifdef CYASSL_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, CYASSL* ssl) +{ + if (!ssl->options.dtls) { + AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl); + AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl); + } +#ifdef CYASSL_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(CYASSL* ssl, byte* buf, word32 sz) +{ + int recvd; + + if (ssl->ctx->CBIORecv == NULL) { + CYASSL_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 CYASSL_CBIO_ERR_GENERAL: /* general/unknown error */ + return -1; + + case CYASSL_CBIO_ERR_WANT_READ: /* want read, would block */ + return WANT_READ; + + case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ + #ifdef USE_WINDOWS_API + if (ssl->options.dtls) { + goto retry; + } + #endif + ssl->options.connReset = 1; + return -1; + + case CYASSL_CBIO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef CYASSL_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); + CYASSL_MSG("Got our timeout"); + return WANT_READ; + } + } + #endif + goto retry; + + case CYASSL_CBIO_ERR_CONN_CLOSE: /* peer closed connection */ + ssl->options.isClosed = 1; + return -1; + + case CYASSL_CBIO_ERR_TIMEOUT: +#ifdef CYASSL_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(CYASSL* ssl) +{ + CYASSL_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(CYASSL* ssl, int forcedFree) +{ + int usedLength = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (!forcedFree && usedLength > STATIC_BUFFER_LEN) + return; + + CYASSL_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(CYASSL* ssl) +{ + if (ssl->ctx->CBIOSend == NULL) { + CYASSL_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 CYASSL_CBIO_ERR_WANT_WRITE: /* would block */ + return WANT_WRITE; + + case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ + ssl->options.connReset = 1; + break; + + case CYASSL_CBIO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef CYASSL_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); + CYASSL_MSG("Got our timeout"); + return WANT_WRITE; + } + } + #endif + continue; + + case CYASSL_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; + } + + 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(CYASSL* ssl, int size) +{ + byte* tmp; + byte hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ : + RECORD_HEADER_SZ; + byte align = CYASSL_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); + CYASSL_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(CYASSL* ssl, int size, int usedLength) +{ + byte* tmp; + byte hdrSz = DTLS_RECORD_HEADER_SZ; + byte align = ssl->options.dtls ? CYASSL_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); + CYASSL_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(CYASSL *ssl, int size) +{ + 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(CYASSL* ssl, const byte* input, word32* inOutIdx, + RecordLayerHeader* rh, word16 *size) +{ + if (!ssl->options.dtls) { + XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ); + *inOutIdx += RECORD_HEADER_SZ; + ato16(rh->length, size); + } + else { +#ifdef CYASSL_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; +#endif + } + + /* catch version mismatch */ + if ((rh->pvMajor != ssl->version.major) || (rh->pvMinor != ssl->version.minor)){ + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.acceptState == ACCEPT_BEGIN) + CYASSL_MSG("Client attempting to connect with different version"); + else if (ssl->options.side == CYASSL_CLIENT_END && + ssl->options.downgrade && + ssl->options.connectState < FIRST_REPLY_DONE) + CYASSL_MSG("Server attempting to accept with different version"); + else { + CYASSL_MSG("SSL version error"); + return VERSION_ERROR; /* only use requested version */ + } + } + +#ifdef CYASSL_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)) + 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: + CYASSL_MSG("Unknown Record Type"); + return UNKNOWN_RECORD_TYPE; + } + + /* haven't decrypted this record yet */ + ssl->keys.decryptedCur = 0; + + return 0; +} + + +static int GetHandShakeHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, + byte *type, word32 *size) +{ + const byte *ptr = input + *inOutIdx; + (void)ssl; + *inOutIdx += HANDSHAKE_HEADER_SZ; + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} + + +#ifdef CYASSL_DTLS +static int GetDtlsHandShakeHeader(CYASSL* ssl, const byte* input, + word32* inOutIdx, byte *type, word32 *size, + word32 *fragOffset, word32 *fragSz) +{ + word32 idx = *inOutIdx; + + *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; + + *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(CYASSL* 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(CYASSL* 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(CYASSL* ssl, Hashes* hashes, const byte* sender) +{ + /* store current states, building requires get_digest which resets state */ +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + Md5 md5 = ssl->hashMd5; +#endif +#ifndef NO_SHA + Sha sha = ssl->hashSha; +#endif +#endif +#ifndef NO_SHA256 + Sha256 sha256 = ssl->hashSha256; +#endif +#ifdef CYASSL_SHA384 + Sha384 sha384 = ssl->hashSha384; +#endif + + int ret = 0; + +#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; + #endif + #ifndef NO_SHA + ssl->hashSha = sha; + #endif +#endif + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ssl->hashSha256 = sha256; + #endif + #ifdef CYASSL_SHA384 + ssl->hashSha384 = sha384; + #endif + } + + return ret; +} + + +#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; + + CYASSL_MSG("Checking AltNames"); + + if (dCert) + altName = dCert->altNames; + + while (altName) { + CYASSL_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(CYASSL_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 CYASSL_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 /* CYASSL_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 CYASSL_SEP + x509->certPolicySet = dCert->extCertPolicySet; + x509->certPolicyCrit = dCert->extCertPolicyCrit; + #endif /* CYASSL_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(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 size) +{ + word32 listSz, begin = *inOutIdx; + int ret = 0; + int anyError = 0; + int totalCerts = 0; /* number of certs in certs buffer */ + int count; + char domain[ASN_NAME_MAX]; + buffer certs[MAX_CHAIN_DEPTH]; + + #ifdef CYASSL_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) + return BUFFER_E; +#else + if (listSz > MAX_RECORD_SIZE) + return BUFFER_E; +#endif + + if ((*inOutIdx - begin) + listSz != size) + return BUFFER_ERROR; + + CYASSL_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 { + CYASSL_MSG("Couldn't store chain cert for session"); + } +#endif + + *inOutIdx += certSz; + listSz -= certSz + CERT_HEADER_SZ; + + totalCerts++; + CYASSL_MSG(" Put another cert into chain"); + } + + count = totalCerts; + + /* verify up to peer's first */ + while (count > 1) { + buffer myCert = certs[count - 1]; + DecodedCert dCert; + 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) { + CYASSL_MSG("Chain cert is not a CA, not adding as one"); + } + else if (ret == 0 && ssl->options.verifyNone) { + CYASSL_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); + CYASSL_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, CYASSL_CHAIN_CA, + ssl->ctx->verifyPeer); + if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ + } + else if (ret != 0) { + CYASSL_MSG("Failed to verify CA from chain"); + } + else { + CYASSL_MSG("Verified CA from chain and already had it"); + } + +#ifdef HAVE_CRL + if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) { + CYASSL_MSG("Doing Non Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); + + if (ret != 0) { + CYASSL_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]; + DecodedCert dCert; + int fatal = 0; + + CYASSL_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) { + CYASSL_MSG("Verified Peer's cert"); + fatal = 0; + } + else if (ret == ASN_PARSE_E) { + CYASSL_MSG("Got Peer cert ASN PARSE ERROR, fatal"); + fatal = 1; + } + else { + CYASSL_MSG("Failed to verify Peer's cert"); + if (ssl->verifyCallback) { + CYASSL_MSG("\tCallback override available, will continue"); + fatal = 0; + } + else { + CYASSL_MSG("\tNo callback override available, fatal"); + fatal = 1; + } + } + +#ifdef HAVE_OCSP + if (fatal == 0 && ssl->ctx->cm->ocspEnabled) { + ret = CheckCertOCSP(ssl->ctx->cm->ocsp, &dCert); + if (ret != 0) { + CYASSL_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) { + CYASSL_MSG("Doing Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); + + if (ret != 0) { + CYASSL_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) && + (dCert.extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { + CYASSL_MSG("KeyUse Digital Sig not set"); + ret = KEYUSE_SIGNATURE_E; + } + } + + if (dCert.extExtKeyUsageSet) { + if (ssl->options.side == CYASSL_CLIENT_END) { + if ((dCert.extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { + CYASSL_MSG("ExtKeyUse Server Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + else { + if ((dCert.extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { + CYASSL_MSG("ExtKeyUse Client Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + } +#endif /* IGNORE_KEY_EXTENSIONS */ + + if (fatal) { + FreeDecodedCert(&dCert); + ssl->error = ret; + return ret; + } + ssl->options.havePeerCert = 1; + + /* 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) { + CYASSL_MSG("DomainName match on common name failed"); + if (CheckAltNames(&dCert, + (char*)ssl->buffers.domainName.buffer) == 0 ) { + CYASSL_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; + if (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 = + 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 (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 = + 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); + } + + if (anyError != 0 && ret == 0) + ret = anyError; + + if (ret == 0 && ssl->options.side == CYASSL_CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + + 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; + CYASSL_X509_STORE_CTX store; + + 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) { + CYASSL_MSG("Verify callback overriding error!"); + ret = 0; + } + #ifdef SESSION_CERTS + if (store.discardSessionCerts) { + CYASSL_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 CYASSL_ALWAYS_VERIFY_CB + else { + if (ssl->verifyCallback) { + int ok; + CYASSL_X509_STORE_CTX store; + + 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) { + CYASSL_MSG("Verify callback overriding valid certificate!"); + ret = -1; + SendAlert(ssl, alert_fatal, bad_certificate); + ssl->options.isClosed = 1; + } + #ifdef SESSION_CERTS + if (store.discardSessionCerts) { + CYASSL_MSG("Verify callback requested discard sess certs"); + ssl->session.chain.count = 0; + } + #endif + } + } +#endif + + return ret; +} + +#endif /* !NO_CERTS */ + + +static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz) +{ + int ret = 0; + + if (size) /* must be 0 */ + return BUFFER_ERROR; + + if (ssl->keys.encryptionOn) { + byte verify[MAX_DIGEST_SIZE]; + int padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - + ssl->specs.hash_size; + + ret = ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ, + HANDSHAKE_HEADER_SZ, handshake, 1); + if (ret != 0) + return ret; + + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + padSz -= ssl->specs.block_size; + + /* access beyond input + size should be checked against totalSz */ + if ((word32) (*inOutIdx + ssl->specs.hash_size + padSz) > totalSz) + return INCOMPLETE_DATA; + + /* verify */ + if (XMEMCMP(input + *inOutIdx, verify, ssl->specs.hash_size) != 0) { + CYASSL_MSG(" hello_request verify mac error"); + return VERIFY_MAC_ERROR; + } + + *inOutIdx += ssl->specs.hash_size + padSz; + } + + if (ssl->options.side == CYASSL_SERVER_END) { + SendAlert(ssl, alert_fatal, unexpected_message); /* try */ + return FATAL_ERROR; + } + else + return SendAlert(ssl, alert_warning, no_renegotiation); +} + + +int DoFinished(CYASSL* 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; + + #ifdef CYASSL_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) { + CYASSL_MSG("Verify finished error on hashes"); + return VERIFY_FINISHED_ERROR; + } + } + + /* increment beyond input + size should be checked against totalSz */ + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return INCOMPLETE_DATA; + + /* force input exhaustion at ProcessReply consuming padSz */ + *inOutIdx += size + ssl->keys.padSz; + + if (ssl->options.side == CYASSL_CLIENT_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + if (!ssl->options.resuming) { + ssl->options.handShakeState = HANDSHAKE_DONE; + +#ifdef CYASSL_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; + +#ifdef CYASSL_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; +} + + +static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, + byte type, word32 size, word32 totalSz) +{ + int ret = 0; + (void)totalSz; + + CYASSL_ENTER("DoHandShakeMsgType"); + + /* make sure can read the message */ + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + + ret = HashInput(ssl, input + *inOutIdx, size); + if (ret != 0) + return ret; + +#ifdef CYASSL_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){ + CYASSL_MSG("HandShake message after handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls == 0 && + ssl->options.serverState == NULL_STATE && type != server_hello) { + CYASSL_MSG("First server message not server hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls && + type == server_hello_done && + ssl->options.serverState < SERVER_HELLO_COMPLETE) { + CYASSL_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 == CYASSL_SERVER_END && + ssl->options.clientState == NULL_STATE && type != client_hello) { + CYASSL_MSG("First client message not client hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + + switch (type) { + + case hello_request: + CYASSL_MSG("processing hello request"); + ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz); + break; + +#ifndef NO_CYASSL_CLIENT + case hello_verify_request: + CYASSL_MSG("processing hello verify request"); + ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size); + break; + + case server_hello: + CYASSL_MSG("processing server hello"); + ret = DoServerHello(ssl, input, inOutIdx, size); + break; + +#ifndef NO_CERTS + case certificate_request: + CYASSL_MSG("processing certificate request"); + ret = DoCertificateRequest(ssl, input, inOutIdx, size); + break; +#endif + + case server_key_exchange: + CYASSL_MSG("processing server key exchange"); + ret = DoServerKeyExchange(ssl, input, inOutIdx, size); + break; +#endif + +#ifndef NO_CERTS + case certificate: + CYASSL_MSG("processing certificate"); + ret = DoCertificate(ssl, input, inOutIdx, size); + break; +#endif + + case server_hello_done: + CYASSL_MSG("processing server hello done"); + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHelloDone", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ServerHelloDone", &ssl->timeoutInfo); + #endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + break; + + case finished: + CYASSL_MSG("processing finished"); + ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); + break; + +#ifndef NO_CYASSL_SERVER + case client_hello: + CYASSL_MSG("processing client hello"); + ret = DoClientHello(ssl, input, inOutIdx, size); + break; + + case client_key_exchange: + CYASSL_MSG("processing client key exchange"); + ret = DoClientKeyExchange(ssl, input, inOutIdx, size); + break; + +#if !defined(NO_RSA) || defined(HAVE_ECC) + case certificate_verify: + CYASSL_MSG("processing certificate verify"); + ret = DoCertificateVerify(ssl, input, inOutIdx, size); + break; +#endif /* !NO_RSA || HAVE_ECC */ + +#endif /* !NO_CYASSL_SERVER */ + + default: + CYASSL_MSG("Unknown handshake message type"); + ret = UNKNOWN_HANDSHAKE_TYPE; + break; + } + + CYASSL_LEAVE("DoHandShakeMsgType()", ret); + return ret; +} + + +static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + byte type; + word32 size; + int ret = 0; + + CYASSL_ENTER("DoHandShakeMsg()"); + + if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0) + return PARSE_ERROR; + + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + + CYASSL_LEAVE("DoHandShakeMsg()", ret); + return ret; +} + + +#ifdef CYASSL_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 & (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 |= (1 << (*next - cur - 1)); + } + else { + *window <<= (1 + cur - *next); + *window |= 1; + *next = cur + 1; + } + + return 1; +} + + +static int DtlsMsgDrain(CYASSL* 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(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + byte type; + word32 size; + word32 fragOffset, fragSz; + int ret = 0; + + CYASSL_ENTER("DoDtlsHandShakeMsg()"); + if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, + &size, &fragOffset, &fragSz) != 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); + } + + CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret); + return ret; +} +#endif + + +static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) +{ + if (verify) + return ssl->keys.peer_sequence_number++; + else + return ssl->keys.sequence_number++; +} + + +#ifdef HAVE_AEAD +static INLINE void AeadIncrementExpIV(CYASSL* ssl) +{ + int i; + for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) { + if (++ssl->keys.aead_exp_IV[i]) return; + } +} +#endif + + +static INLINE int Encrypt(CYASSL* ssl, byte* out, const byte* input, word16 sz) +{ + (void)out; + (void)input; + (void)sz; + + if (ssl->encrypt.setup == 0) { + CYASSL_MSG("Encrypt ciphers not setup"); + return ENCRYPT_ERROR; + } + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case cyassl_rc4: + Arc4Process(ssl->encrypt.arc4, out, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case cyassl_triple_des: + return Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz); + #endif + + #ifdef BUILD_AES + case cyassl_aes: + return AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); + #endif + + #ifdef BUILD_AESGCM + case cyassl_aes_gcm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + const byte* additionalSrc = input - 5; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* 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 CYASSL_DTLS + if (ssl->options.dtls) + 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); + 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); + AeadIncrementExpIV(ssl); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + } + break; + #endif + + #ifdef HAVE_AESCCM + case cyassl_aes_ccm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + const byte* additionalSrc = input - 5; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* 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 CYASSL_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); + 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 cyassl_camellia: + CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case cyassl_hc128: + return Hc128_Process(ssl->encrypt.hc128, out, input, sz); + #endif + + #ifdef BUILD_RABBIT + case cyassl_rabbit: + return RabbitProcess(ssl->encrypt.rabbit, out, input, sz); + #endif + + #ifdef HAVE_NULL_CIPHER + case cyassl_cipher_null: + if (input != out) { + XMEMMOVE(out, input, sz); + } + break; + #endif + + default: + CYASSL_MSG("CyaSSL Encrypt programming error"); + return ENCRYPT_ERROR; + } + + return 0; +} + + + +static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, + word16 sz) +{ + (void)plain; + (void)input; + (void)sz; + + if (ssl->decrypt.setup == 0) { + CYASSL_MSG("Decrypt ciphers not setup"); + return DECRYPT_ERROR; + } + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case cyassl_rc4: + Arc4Process(ssl->decrypt.arc4, plain, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case cyassl_triple_des: + return Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz); + #endif + + #ifdef BUILD_AES + case cyassl_aes: + return AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); + #endif + + #ifdef BUILD_AESGCM + case cyassl_aes_gcm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + 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 (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 cyassl_aes_ccm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + #ifdef CYASSL_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 (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 cyassl_camellia: + CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case cyassl_hc128: + return Hc128_Process(ssl->decrypt.hc128, plain, input, sz); + #endif + + #ifdef BUILD_RABBIT + case cyassl_rabbit: + return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); + #endif + + #ifdef HAVE_NULL_CIPHER + case cyassl_cipher_null: + if (input != plain) { + XMEMMOVE(plain, input, sz); + } + break; + #endif + + default: + CYASSL_MSG("CyaSSL Decrypt programming error"); + return DECRYPT_ERROR; + } + return 0; +} + + +/* check cipher text size for sanity */ +static int SanityCheckCipherText(CYASSL* 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) { + CYASSL_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 + AEAD_EXP_IV_SZ; + /* explicit IV + authTag size */ + } + + if (encryptSz < minLength) { + CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_SHA384 + case sha384_mac : + Sha384Rounds(rounds, data, sz); + break; +#endif + +#ifdef CYASSL_SHA512 + case sha512_mac : + Sha512Rounds(rounds, data, sz); + break; +#endif + +#ifdef CYASSL_RIPEMD + case rmd_mac : + RmdRounds(rounds, data, sz); + break; +#endif + + default: + CYASSL_MSG("Bad round type"); + break; + } +} + + +/* do number of compression rounds on dummy data */ +static INLINE void CompressRounds(CYASSL* 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(CYASSL* 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) { + CYASSL_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) { + CYASSL_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) { + CYASSL_MSG("Verify MAC compare failed"); + return VERIFY_MAC_ERROR; + } + + if (ret != 0) + return VERIFY_MAC_ERROR; + return 0; +} + + +int DoApplicationData(CYASSL* 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.handShakeState != HANDSHAKE_DONE) { + CYASSL_MSG("Received App data before handshake complete"); + 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) { + ivExtra = AEAD_EXP_IV_SZ; + } + + dataSz = msgSz - ivExtra - ssl->keys.padSz; + if (dataSz < 0) { + CYASSL_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(CYASSL* ssl, byte* input, word32* inOutIdx, int* type, + word32 totalSz) +{ + byte level; + byte code; + + #ifdef CYASSL_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 */ + } + + CYASSL_MSG("Got alert"); + if (*type == close_notify) { + CYASSL_MSG(" close notify"); + ssl->options.closeNotify = 1; + } + CYASSL_ERROR(*type); + + if (ssl->keys.encryptionOn) { + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz; + } + + return level; +} + +static int GetInputData(CYASSL *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 CYASSL_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(CYASSL* 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)) { + CYASSL_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(CYASSL* ssl) +{ + int ret = 0, type, readSz; + int atomicUser = 0; + word32 startIdx = 0; +#ifndef NO_CYASSL_SERVER + byte b0, b1; +#endif +#ifdef CYASSL_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){ + CYASSL_MSG("ProcessReply retry in error state, not allowed"); + return ssl->error; + } + + for (;;) { + switch (ssl->options.processReply) { + + /* in the CYASSL_SERVER case, get the first byte for detecting + * old client hello */ + case doProcessInit: + + readSz = RECORD_HEADER_SZ; + + #ifdef CYASSL_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 CYASSL_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 + } + +#ifndef NO_CYASSL_SERVER + + /* see if sending SSLv2 client hello */ + if ( ssl->options.side == CYASSL_SERVER_END && + ssl->options.clientState == NULL_STATE && + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx] + != handshake) { + ssl->options.processReply = runProcessOldClientHello; + + /* 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 CYASSL_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 CYASSL_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 /* CYASSL_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 /* NO_CYASSL_SERVER */ + + /* get the record layer header */ + case getRecordLayerHeader: + + ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + &ssl->curRL, &ssl->curSize); +#ifdef CYASSL_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 CYASSL_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 CYASSL_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->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) { + CYASSL_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->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) { + CYASSL_ERROR(ret); + return DECRYPT_ERROR; + } + ssl->keys.encryptSz = ssl->curSize; + ssl->keys.decryptedCur = 1; + } + + if (ssl->options.dtls) { + #ifdef CYASSL_DTLS + DtlsUpdateWindow(&ssl->keys.dtls_state); + #endif /* CYASSL_DTLS */ + } + + CYASSL_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 CYASSL_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: + CYASSL_MSG("got CHANGE CIPHER SPEC"); + #ifdef CYASSL_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 + + if (ssl->curSize != 1) { + CYASSL_MSG("Malicious or corrupted ChangeCipher msg"); + return LENGTH_ERROR; + } + #ifndef NO_CERTS + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.verifyPeer && + ssl->options.havePeerCert) + if (!ssl->options.havePeerVerify) { + CYASSL_MSG("client didn't send cert verify"); + return NO_PEER_VERIFY; + } + #endif + + + ssl->buffers.inputBuffer.idx++; + ssl->keys.encryptionOn = 1; + + #ifdef CYASSL_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 == + CYASSL_CLIENT_END) + ret = BuildFinished(ssl, &ssl->verifyHashes, server); + else if (!ssl->options.resuming && ssl->options.side == + CYASSL_SERVER_END) + ret = BuildFinished(ssl, &ssl->verifyHashes, client); + if (ret != 0) + return ret; + break; + + case application_data: + CYASSL_MSG("got app DATA"); + if ((ret = DoApplicationData(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx)) + != 0) { + CYASSL_ERROR(ret); + return ret; + } + break; + + case alert: + CYASSL_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: + CYASSL_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) { + CYASSL_MSG("More messages in record"); + #ifdef CYASSL_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; + continue; + } + /* more records */ + else { + CYASSL_MSG("More records in input"); + ssl->options.processReply = doProcessInit; + continue; + } + + default: + CYASSL_MSG("Bad process input state, programming error"); + return INPUT_CASE_ERROR; + } + } +} + + +int SendChangeCipher(CYASSL* ssl) +{ + byte *output; + int sendSz = RECORD_HEADER_SZ + ENUM_LEN; + int idx = RECORD_HEADER_SZ; + int ret; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + } + #endif + + /* 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 */ + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + #ifdef CYASSL_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 CYASSL_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(CYASSL* 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 = CyaSSL_GetMacSecret(ssl, verify); + + 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(CYASSL* 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(CYASSL* 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(CYASSL* 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 CYASSL_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 CYASSL_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 CYASSL_SHA384 + ssl->hashSha384 = sha384; + #endif + } + + return 0; +} + +#endif /* CYASSL_LEANPSK */ + +/* Build SSL Message, encrypted */ +static int BuildMessage(CYASSL* ssl, byte* output, 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 CYASSL_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; + + 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) { + 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 + 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) { + byte hmac[MAX_DIGEST_SIZE]; + + ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz, + type, 0); + XMEMCPY(output + idx, hmac, digestSz); + } 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(CYASSL* 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; + + #ifdef CYASSL_DTLS + word32 sequence_number = ssl->keys.dtls_sequence_number; + word16 epoch = ssl->keys.dtls_epoch; + #endif + + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0) + return ret; + + #ifdef CYASSL_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 == CYASSL_CLIENT_END ? client : server); + if (ret != 0) return ret; + + sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake); + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + ssl->keys.dtls_epoch = epoch; + ssl->keys.dtls_sequence_number = sequence_number; + } + #endif + + if (sendSz < 0) + return BUILD_MSG_ERROR; + + if (!ssl->options.resuming) { +#ifndef NO_SESSION_CACHE + AddSession(ssl); /* just try */ +#endif + if (ssl->options.side == CYASSL_CLIENT_END) { + ret = BuildFinished(ssl, &ssl->verifyHashes, server); + if (ret != 0) return ret; + } + else { + ssl->options.handShakeState = HANDSHAKE_DONE; + #ifdef CYASSL_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 == CYASSL_CLIENT_END) { + ssl->options.handShakeState = HANDSHAKE_DONE; + #ifdef CYASSL_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 CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + #ifdef CYASSL_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(CYASSL* 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) 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 CYASSL_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, 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); + /* if add more to output adjust i + i += ssl->buffers.certChain.length; */ + } + } + #ifdef CYASSL_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 CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + if (ssl->options.side == CYASSL_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(CYASSL* ssl) +{ + byte *output; + int ret; + int sendSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + int typeTotal = 1; /* only rsa 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) return 0; /* not needed */ + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + + #ifdef CYASSL_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 */ + 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 CYASSL_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 CYASSL_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(CYASSL* ssl, const void* data, int sz) +{ + int sent = 0, /* plainText size */ + sendSz, + ret; + + if (ssl->error == WANT_WRITE) + ssl->error = 0; + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + CYASSL_MSG("handshake not complete, trying to finish"); + if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) + return err; + } + + /* last time system socket output buffer was full, try again to send */ + if (ssl->buffers.outputBuffer.length > 0) { + CYASSL_MSG("output buffer was full, trying to send again"); + if ( (ssl->error = SendBuffered(ssl)) < 0) { + CYASSL_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; + CYASSL_MSG("sent write buffered data"); + } + } + + 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 */ +#ifdef HAVE_LIBZ + byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + + if (sent == sz) break; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + len = min(len, MAX_UDP_SIZE); + buffSz = len; + } +#endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, len + COMP_EXTRA + + MAX_MSG_EXTRA)) != 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, sendBuffer, buffSz, + application_data); + + ssl->buffers.outputBuffer.length += sendSz; + + if ( (ret = SendBuffered(ssl)) < 0) { + CYASSL_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) { + CYASSL_MSG("Paritial Write on, only sending one record"); + break; + } + } + + return sent; +} + +/* process input data */ +int ReceiveData(CYASSL* ssl, byte* output, int sz, int peek) +{ + int size; + + CYASSL_ENTER("ReceiveData()"); + + if (ssl->error == WANT_READ) + ssl->error = 0; + + if (ssl->error != 0 && ssl->error != WANT_WRITE) { + CYASSL_MSG("User calling CyaSSL_read in error state, not allowed"); + return ssl->error; + } + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + CYASSL_MSG("Handshake not complete, trying to finish"); + if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) + return err; + } + + while (ssl->buffers.clearOutputBuffer.length == 0) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + if (ssl->error == ZERO_RETURN) { + CYASSL_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) { + CYASSL_MSG("Peer reset or closed, connection done"); + return 0; /* peer reset or closed */ + } + } + return ssl->error; + } + + 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); + + CYASSL_LEAVE("ReceiveData()", size); + return size; +} + + +/* send alert message */ +int SendAlert(CYASSL* ssl, int severity, int type) +{ + byte input[ALERT_SIZE]; + byte *output; + int sendSz; + int ret; + 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 CYASSL_DTLS + if (ssl->options.dtls) + dtlsExtra = DTLS_RECORD_EXTRA; + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, + ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra)) != 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.handShakeState == HANDSHAKE_DONE) + sendSz = BuildMessage(ssl, output, input, ALERT_SIZE, alert); + else { + + AddRecordHeader(output, ALERT_SIZE, alert, ssl); + output += RECORD_HEADER_SZ; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + output += DTLS_RECORD_EXTRA; + #endif + XMEMCPY(output, input, ALERT_SIZE); + + sendSz = RECORD_HEADER_SZ + ALERT_SIZE; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA; + #endif + } + + #ifdef CYASSL_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); +} + + + +void SetErrorString(int error, char* str) +{ + const int max = CYASSL_MAX_ERROR_SZ; /* shorthand */ + +#ifdef NO_ERROR_STRINGS + + (void)error; + XSTRNCPY(str, "no support for error strings built in", max); + +#else + + /* pass to CTaoCrypt */ + if (error < MAX_CODE_E && error > MIN_CODE_E) { + CTaoCryptErrorString(error, str); + return; + } + + switch (error) { + + case UNSUPPORTED_SUITE : + XSTRNCPY(str, "unsupported cipher suite", max); + break; + + case INPUT_CASE_ERROR : + XSTRNCPY(str, "input state error", max); + break; + + case PREFIX_ERROR : + XSTRNCPY(str, "bad index to key rounds", max); + break; + + case MEMORY_ERROR : + XSTRNCPY(str, "out of memory", max); + break; + + case VERIFY_FINISHED_ERROR : + XSTRNCPY(str, "verify problem on finished", max); + break; + + case VERIFY_MAC_ERROR : + XSTRNCPY(str, "verify mac problem", max); + break; + + case PARSE_ERROR : + XSTRNCPY(str, "parse error on header", max); + break; + + case SIDE_ERROR : + XSTRNCPY(str, "wrong client/server type", max); + break; + + case NO_PEER_CERT : + XSTRNCPY(str, "peer didn't send cert", max); + break; + + case UNKNOWN_HANDSHAKE_TYPE : + XSTRNCPY(str, "weird handshake type", max); + break; + + case SOCKET_ERROR_E : + XSTRNCPY(str, "error state on socket", max); + break; + + case SOCKET_NODATA : + XSTRNCPY(str, "expected data, not there", max); + break; + + case INCOMPLETE_DATA : + XSTRNCPY(str, "don't have enough data to complete task", max); + break; + + case UNKNOWN_RECORD_TYPE : + XSTRNCPY(str, "unknown type in record hdr", max); + break; + + case DECRYPT_ERROR : + XSTRNCPY(str, "error during decryption", max); + break; + + case FATAL_ERROR : + XSTRNCPY(str, "revcd alert fatal error", max); + break; + + case ENCRYPT_ERROR : + XSTRNCPY(str, "error during encryption", max); + break; + + case FREAD_ERROR : + XSTRNCPY(str, "fread problem", max); + break; + + case NO_PEER_KEY : + XSTRNCPY(str, "need peer's key", max); + break; + + case NO_PRIVATE_KEY : + XSTRNCPY(str, "need the private key", max); + break; + + case NO_DH_PARAMS : + XSTRNCPY(str, "server missing DH params", max); + break; + + case RSA_PRIVATE_ERROR : + XSTRNCPY(str, "error during rsa priv op", max); + break; + + case MATCH_SUITE_ERROR : + XSTRNCPY(str, "can't match cipher suite", max); + break; + + case BUILD_MSG_ERROR : + XSTRNCPY(str, "build message failure", max); + break; + + case BAD_HELLO : + XSTRNCPY(str, "client hello malformed", max); + break; + + case DOMAIN_NAME_MISMATCH : + XSTRNCPY(str, "peer subject name mismatch", max); + break; + + case WANT_READ : + case SSL_ERROR_WANT_READ : + XSTRNCPY(str, "non-blocking socket wants data to be read", max); + break; + + case NOT_READY_ERROR : + XSTRNCPY(str, "handshake layer not ready yet, complete first", max); + break; + + case PMS_VERSION_ERROR : + XSTRNCPY(str, "premaster secret version mismatch error", max); + break; + + case VERSION_ERROR : + XSTRNCPY(str, "record layer version error", max); + break; + + case WANT_WRITE : + case SSL_ERROR_WANT_WRITE : + XSTRNCPY(str, "non-blocking socket write buffer full", max); + break; + + case BUFFER_ERROR : + XSTRNCPY(str, "malformed buffer input error", max); + break; + + case VERIFY_CERT_ERROR : + XSTRNCPY(str, "verify problem on certificate", max); + break; + + case VERIFY_SIGN_ERROR : + XSTRNCPY(str, "verify problem based on signature", max); + break; + + case CLIENT_ID_ERROR : + XSTRNCPY(str, "psk client identity error", max); + break; + + case SERVER_HINT_ERROR: + XSTRNCPY(str, "psk server hint error", max); + break; + + case PSK_KEY_ERROR: + XSTRNCPY(str, "psk key callback error", max); + break; + + case NTRU_KEY_ERROR: + XSTRNCPY(str, "NTRU key error", max); + break; + + case NTRU_DRBG_ERROR: + XSTRNCPY(str, "NTRU drbg error", max); + break; + + case NTRU_ENCRYPT_ERROR: + XSTRNCPY(str, "NTRU encrypt error", max); + break; + + case NTRU_DECRYPT_ERROR: + XSTRNCPY(str, "NTRU decrypt error", max); + break; + + case ZLIB_INIT_ERROR: + XSTRNCPY(str, "zlib init error", max); + break; + + case ZLIB_COMPRESS_ERROR: + XSTRNCPY(str, "zlib compress error", max); + break; + + case ZLIB_DECOMPRESS_ERROR: + XSTRNCPY(str, "zlib decompress error", max); + break; + + case GETTIME_ERROR: + XSTRNCPY(str, "gettimeofday() error", max); + break; + + case GETITIMER_ERROR: + XSTRNCPY(str, "getitimer() error", max); + break; + + case SIGACT_ERROR: + XSTRNCPY(str, "sigaction() error", max); + break; + + case SETITIMER_ERROR: + XSTRNCPY(str, "setitimer() error", max); + break; + + case LENGTH_ERROR: + XSTRNCPY(str, "record layer length error", max); + break; + + case PEER_KEY_ERROR: + XSTRNCPY(str, "cant decode peer key", max); + break; + + case ZERO_RETURN: + case SSL_ERROR_ZERO_RETURN: + XSTRNCPY(str, "peer sent close notify alert", max); + break; + + case ECC_CURVETYPE_ERROR: + XSTRNCPY(str, "Bad ECC Curve Type or unsupported", max); + break; + + case ECC_CURVE_ERROR: + XSTRNCPY(str, "Bad ECC Curve or unsupported", max); + break; + + case ECC_PEERKEY_ERROR: + XSTRNCPY(str, "Bad ECC Peer Key", max); + break; + + case ECC_MAKEKEY_ERROR: + XSTRNCPY(str, "ECC Make Key failure", max); + break; + + case ECC_EXPORT_ERROR: + XSTRNCPY(str, "ECC Export Key failure", max); + break; + + case ECC_SHARED_ERROR: + XSTRNCPY(str, "ECC DHE shared failure", max); + break; + + case NOT_CA_ERROR: + XSTRNCPY(str, "Not a CA by basic constraint error", max); + break; + + case BAD_PATH_ERROR: + XSTRNCPY(str, "Bad path for opendir error", max); + break; + + case BAD_CERT_MANAGER_ERROR: + XSTRNCPY(str, "Bad Cert Manager error", max); + break; + + case OCSP_CERT_REVOKED: + XSTRNCPY(str, "OCSP Cert revoked", max); + break; + + case CRL_CERT_REVOKED: + XSTRNCPY(str, "CRL Cert revoked", max); + break; + + case CRL_MISSING: + XSTRNCPY(str, "CRL missing, not loaded", max); + break; + + case MONITOR_RUNNING_E: + XSTRNCPY(str, "CRL monitor already running", max); + break; + + case THREAD_CREATE_E: + XSTRNCPY(str, "Thread creation problem", max); + break; + + case OCSP_NEED_URL: + XSTRNCPY(str, "OCSP need URL", max); + break; + + case OCSP_CERT_UNKNOWN: + XSTRNCPY(str, "OCSP Cert unknown", max); + break; + + case OCSP_LOOKUP_FAIL: + XSTRNCPY(str, "OCSP Responder lookup fail", max); + break; + + case MAX_CHAIN_ERROR: + XSTRNCPY(str, "Maximum Chain Depth Exceeded", max); + break; + + case COOKIE_ERROR: + XSTRNCPY(str, "DTLS Cookie Error", max); + break; + + case SEQUENCE_ERROR: + XSTRNCPY(str, "DTLS Sequence Error", max); + break; + + case SUITES_ERROR: + XSTRNCPY(str, "Suites Pointer Error", max); + break; + + case SSL_NO_PEM_HEADER: + XSTRNCPY(str, "No PEM Header Error", max); + break; + + case OUT_OF_ORDER_E: + XSTRNCPY(str, "Out of order message, fatal", max); + break; + + case BAD_KEA_TYPE_E: + XSTRNCPY(str, "Bad KEA type found", max); + break; + + case SANITY_CIPHER_E: + XSTRNCPY(str, "Sanity check on ciphertext failed", max); + break; + + case RECV_OVERFLOW_E: + XSTRNCPY(str, "Receive callback returned more than requested", max); + break; + + case GEN_COOKIE_E: + XSTRNCPY(str, "Generate Cookie Error", max); + break; + + case NO_PEER_VERIFY: + XSTRNCPY(str, "Need peer certificate verify Error", max); + break; + + case FWRITE_ERROR: + XSTRNCPY(str, "fwrite Error", max); + break; + + case CACHE_MATCH_ERROR: + XSTRNCPY(str, "Cache restore header match Error", max); + break; + + case UNKNOWN_SNI_HOST_NAME_E: + XSTRNCPY(str, "Unrecognized host name Error", max); + break; + + case KEYUSE_SIGNATURE_E: + XSTRNCPY(str, "Key Use digitalSignature not set Error", max); + break; + + case KEYUSE_ENCIPHER_E: + XSTRNCPY(str, "Key Use keyEncipherment not set Error", max); + break; + + case EXTKEYUSE_AUTH_E: + XSTRNCPY(str, "Ext Key Use server/client auth not set Error", max); + break; + + default : + XSTRNCPY(str, "unknown error number", max); + } + +#endif /* NO_ERROR_STRINGS */ +} + + + +/* 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_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_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_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 + +}; + + + +/* 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_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_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_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 +}; + + +/* return true if set, else false */ +/* only supports full name from cipher_name[] delimited by : */ +int SetCipherList(Suites* s, const char* list) +{ + int ret = 0, i; + char name[MAX_SUITE_NAME]; + + char needle[] = ":"; + char* haystack = (char*)list; + char* prev; + + const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); + int idx = 0; + int haveRSA = 0, haveECDSA = 0; + + if (s == NULL) { + CYASSL_MSG("SetCipherList suite pointer error"); + return 0; + } + + if (!list) + return 0; + + if (*list == 0) return 1; /* CyaSSL default */ + + if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1; /* CyaSSL defualt */ + + for(;;) { + word32 len; + prev = haystack; + haystack = XSTRSTR(haystack, needle); + + if (!haystack) /* last cipher */ + len = min(sizeof(name), (word32)XSTRLEN(prev)); + else + len = min(sizeof(name), (word32)(haystack - prev)); + + XSTRNCPY(name, prev, len); + name[(len == sizeof(name)) ? len - 1 : len] = 0; + + for (i = 0; i < suiteSz; i++) + if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { + if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM")) + s->suites[idx++] = ECC_BYTE; /* ECC suite */ + else + s->suites[idx++] = 0x00; /* normal */ + s->suites[idx++] = (byte)cipher_name_idx[i]; + + /* The suites are either ECDSA, RSA, or PSK. The RSA suites + * don't necessarily have RSA in the name. */ + if ((haveECDSA == 0) && XSTRSTR(name, "ECDSA")) { + haveECDSA = 1; + } + else if ((haveRSA == 0) && (XSTRSTR(name, "PSK") == NULL)) { + haveRSA = 1; + } + + if (!ret) ret = 1; /* found at least one */ + break; + } + if (!haystack) break; + haystack++; + } + + if (ret) { + s->setSuites = 1; + s->suiteSz = (word16)idx; + + idx = 0; + + if (haveECDSA) { + #ifdef CYASSL_SHA384 + s->hashSigAlgo[idx++] = sha384_mac; + s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + #ifndef NO_SHA256 + s->hashSigAlgo[idx++] = sha256_mac; + s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + s->hashSigAlgo[idx++] = sha_mac; + s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + } + + if (haveRSA) { + #ifdef CYASSL_SHA384 + s->hashSigAlgo[idx++] = sha384_mac; + s->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + #ifndef NO_SHA256 + s->hashSigAlgo[idx++] = sha256_mac; + s->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + s->hashSigAlgo[idx++] = sha_mac; + s->hashSigAlgo[idx++] = rsa_sa_algo; + } + + s->hashSigAlgoSz = (word16)idx; + } + + return ret; +} + + +static void PickHashSigAlgo(CYASSL* ssl, + const byte* hashSigAlgo, word32 hashSigAlgoSz) +{ + word32 i; + + ssl->suites->sigAlgo = ssl->specs.sig_algo; + ssl->suites->hashAlgo = sha_mac; + + for (i = 0; i < 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 CYASSL_SHA384 + else if (hashSigAlgo[i] == sha384_mac) { + ssl->suites->hashAlgo = sha384_mac; + break; + } + #endif + } + } +} + + +#ifdef CYASSL_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 CYASSL* 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 /* CYASSL_CALLBACKS */ + + + +/* client only parts */ +#ifndef NO_CYASSL_CLIENT + + int SendClientHello(CYASSL* ssl) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int idSz = ssl->options.resuming ? ID_LEN : 0; + int ret; + + if (ssl->suites == NULL) { + CYASSL_MSG("Bad suites pointer in SendClientHello"); + return SUITES_ERROR; + } + + 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 CYASSL_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 + + /* 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 CYASSL_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, ID_LEN); + idx += ID_LEN; + } + + /* then DTLS cookie */ +#ifdef CYASSL_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 + + #ifdef CYASSL_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; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + +#ifdef CYASSL_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(CYASSL* ssl, const byte* input, + word32* inOutIdx, word32 size) + { + ProtocolVersion pv; + byte cookieSz; + word32 begin = *inOutIdx; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest", + &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); +#endif + +#ifdef CYASSL_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 CYASSL_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 int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte b; + ProtocolVersion pv; + byte compression; + word32 i = *inOutIdx; + word32 begin = i; + +#ifdef CYASSL_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) { + CYASSL_MSG("Server using higher version, fatal error"); + return VERSION_ERROR; + } + else if (pv.minor < ssl->version.minor) { + CYASSL_MSG("server using lower version"); + + if (!ssl->options.downgrade) { + CYASSL_MSG(" no downgrade allowed, fatal error"); + return VERSION_ERROR; + } + + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + CYASSL_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+ */ + CYASSL_MSG(" downgrading to TLSv1"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + CYASSL_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 */ + b = input[i++]; + + if (b == ID_LEN) { + if ((i - begin) + ID_LEN > helloSz) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN)); + i += ID_LEN; + ssl->options.haveSessionId = 1; + } + else if (b) { + CYASSL_MSG("Invalid session ID size"); + return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } + + /* suite and compression */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + compression = input[i++]; + + if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) { + CYASSL_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 (IsTLS(ssl)) { + int ret = 0; + word16 totalExtSz; + Suites clSuites; /* just for compatibility right now */ + + 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, &clSuites))) + return ret; + + i += totalExtSz; + *inOutIdx = i; + } + else +#endif + *inOutIdx = begin + helloSz; /* skip extensions */ + } + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + if (ssl->options.resuming) { + if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, + ssl->session.sessionID, ID_LEN) == 0) { + 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 { + CYASSL_MSG("Unsupported cipher suite, DoServerHello"); + return UNSUPPORTED_SUITE; + } + } + else { + CYASSL_MSG("Server denied resumption attempt"); + ssl->options.resuming = 0; /* server denied resumption try */ + } + } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolReset(ssl); + } + #endif + + return SetCipherSpecs(ssl); + } + + +#ifndef NO_CERTS + /* just read in and ignore for now TODO: */ + static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32* + inOutIdx, word32 size) + { + word16 len; + word32 begin = *inOutIdx; + + #ifdef CYASSL_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; + + return 0; + } +#endif /* !NO_CERTS */ + + + static int DoServerKeyExchange(CYASSL* ssl, const byte* input, + word32* inOutIdx, word32 size) + { + word16 length = 0; + word32 begin = *inOutIdx; + int ret = 0; + + (void)length; /* shut up compiler warnings */ + (void)begin; + (void)ssl; + (void)input; + (void)size; + (void)ret; + + #ifdef CYASSL_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 + #ifdef OPENSSL_EXTRA + 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 /* OPENSSL_EXTRA */ + + #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 (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0) + return ECC_PEERKEY_ERROR; + + *inOutIdx += length; + ssl->peerEccKeyPresent = 1; + } + #endif /* HAVE_ECC */ + + #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) + { +#ifndef NO_OLD_TLS + Md5 md5; + Sha sha; +#endif +#ifndef NO_SHA256 + Sha256 sha256; + byte hash256[SHA256_DIGEST_SIZE]; +#endif +#ifdef CYASSL_SHA384 + Sha384 sha384; + byte hash384[SHA384_DIGEST_SIZE]; +#endif + byte hash[FINISHED_SZ]; + byte messageVerify[MAX_DH_SZ]; + byte hashAlgo = sha_mac; + byte sigAlgo = ssl->specs.sig_algo; + word16 verifySz = (word16) (*inOutIdx - begin); + + /* save message for hash verify */ + if (verifySz > sizeof(messageVerify)) + return BUFFER_ERROR; + + XMEMCPY(messageVerify, input + begin, verifySz); + + if (IsAtLeastTLSv1_2(ssl)) { + if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size) + return BUFFER_ERROR; + + hashAlgo = input[(*inOutIdx)++]; + sigAlgo = input[(*inOutIdx)++]; + } + + /* signature */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + /* inOutIdx updated at the end of the function */ + + /* verify signature */ +#ifndef NO_OLD_TLS + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); + Md5Update(&md5, messageVerify, verifySz); + Md5Final(&md5, hash); + + /* sha */ + ret = InitSha(&sha); + if (ret != 0) + return ret; + 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 + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, messageVerify, verifySz); + if (ret != 0) + return ret; + ret = Sha256Final(&sha256, hash256); + if (ret != 0) + return ret; +#endif + +#ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, messageVerify, verifySz); + if (ret != 0) + return ret; + ret = Sha384Final(&sha384, hash384); + if (ret != 0) + return ret; +#endif + +#ifndef NO_RSA + /* rsa */ + if (sigAlgo == rsa_sa_algo) + { + byte* out = NULL; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaVerifyCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + if (!ssl->peerRsaKeyPresent) + return NO_PEER_KEY; + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + ret = ssl->ctx->RsaVerifyCb(ssl, (byte *) input + *inOutIdx, + length, &out, + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaVerifyCtx); + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaSSL_VerifyInline((byte *) input + *inOutIdx, length, + &out, ssl->peerRsaKey); + } + + if (IsAtLeastTLSv1_2(ssl)) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + 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 + + 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 CYASSL_SHA384 + digest = hash384; + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + + encSigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); + + if (encSigSz != (word32)ret || !out || XMEMCMP(out, encodedSig, + min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) + return VERIFY_SIGN_ERROR; + } + else { + if (ret != sizeof(hash) || !out || XMEMCMP(out, + hash, sizeof(hash)) != 0) + return VERIFY_SIGN_ERROR; + } + } 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) + return NO_PEER_KEY; + + 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 CYASSL_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) + return VERIFY_SIGN_ERROR; + } + else +#endif /* HAVE_ECC */ + return ALGO_ID_E; + + /* signature length */ + *inOutIdx += length; + + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + + return 0; + } +#else /* HAVE_OPENSSL or HAVE_ECC */ + return NOT_COMPILED_IN; /* not supported by build */ +#endif /* HAVE_OPENSSL or HAVE_ECC */ + } + + + int SendClientKeyExchange(CYASSL* ssl) + { + byte encSecret[MAX_ENCRYPT_SZ]; + 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 */ + + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, + SECRET_LEN); + if (ret != 0) + 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) + return NO_PEER_KEY; + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + encSz = sizeof(encSecret); + 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, sizeof(encSecret), + ssl->peerRsaKey, ssl->rng); + if (ret > 0) { + encSz = ret; + ret = 0; /* set success to 0 */ + } + } + break; + #endif + #ifdef OPENSSL_EXTRA + case diffie_hellman_kea: + { + buffer serverP = ssl->buffers.serverDH_P; + buffer serverG = ssl->buffers.serverDH_G; + buffer serverPub = ssl->buffers.serverDH_Pub; + byte priv[ENCRYPT_LEN]; + word32 privSz = 0; + DhKey key; + + if (serverP.buffer == 0 || serverG.buffer == 0 || + serverPub.buffer == 0) + return NO_PEER_KEY; + + 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); + FreeDhKey(&key); + } + break; + #endif /* OPENSSL_EXTRA */ + #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) + return PSK_KEY_ERROR; + encSz = (word32)XSTRLEN(ssl->arrays->client_identity); + if (encSz > MAX_PSK_ID_LEN) 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 */ + #ifdef HAVE_NTRU + case ntru_kea: + { + word32 rc; + word16 cipherLen = sizeof(encSecret); + DRBG_HANDLE drbg; + static uint8_t const cyasslStr[] = { + 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' + }; + + ret = RNG_GenerateBlock(ssl->rng, + ssl->arrays->preMasterSecret, SECRET_LEN); + if (ret != 0) + return ret; + + ssl->arrays->preMasterSz = SECRET_LEN; + + if (ssl->peerNtruKeyPresent == 0) + return NO_PEER_KEY; + + rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr, + sizeof(cyasslStr), GetEntropy, + &drbg); + if (rc != DRBG_OK) + return NTRU_DRBG_ERROR; + + rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen, + ssl->peerNtruKey, + ssl->arrays->preMasterSz, + ssl->arrays->preMasterSecret, + &cipherLen, encSecret); + crypto_drbg_uninstantiate(drbg); + if (rc != NTRU_OK) + 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 = sizeof(encSecret); + + if (ssl->specs.static_ecdh) { + /* TODO: EccDsa is really fixed Ecc change naming */ + if (!ssl->peerEccDsaKeyPresent || !ssl->peerEccDsaKey->dp) + return NO_PEER_KEY; + peerKey = ssl->peerEccDsaKey; + } + else { + if (!ssl->peerEccKeyPresent || !ssl->peerEccKey->dp) + return NO_PEER_KEY; + peerKey = ssl->peerEccKey; + } + + if (peerKey == NULL) + return NO_PEER_KEY; + + ecc_init(&myKey); + ret = ecc_make_key(ssl->rng, peerKey->dp->size, &myKey); + if (ret != 0) + 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: + 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) /* always off */ + tlsSz = 0; + + sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_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, encSz + tlsSz, client_key_exchange, ssl); + + if (tlsSz) { + c16toa((word16)encSz, &output[idx]); + idx += 2; + } + XMEMCPY(output + idx, encSecret, encSz); + /* if add more to output, adjust idx + idx += encSz; */ + #ifdef CYASSL_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 CYASSL_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); + } + + 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(CYASSL* ssl) + { + byte *output; + int sendSz = 0, 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 */ + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, MAX_CERT_VERIFY_SZ)) != 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 + CYASSL_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) { + CYASSL_MSG("Using ECC client cert"); + usingEcc = 1; + sigOutSz = MAX_ENCODED_SIG_SZ; + } + else { + CYASSL_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; + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 extraSz = 0; /* tls 1.2 hash/sig */ + + (void)encodedSig; + (void)signSz; + (void)signBuffer; + + #ifdef CYASSL_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 CYASSL_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 CYASSL_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 + if (ret == 0) { + AddHeaders(output, length + extraSz + VERIFY_HEADER, + certificate_verify, ssl); + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + + extraSz + VERIFY_HEADER; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + } + } +#ifndef NO_RSA + if (initRsaKey) + FreeRsaKey(&key); +#endif +#ifdef HAVE_ECC + ecc_free(&eccKey); +#endif + + if (ret == 0) { + #ifdef CYASSL_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 */ + + +#endif /* NO_CYASSL_CLIENT */ + + +#ifndef NO_CYASSL_SERVER + + int SendServerHello(CYASSL* 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 CYASSL_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 + if (IsTLS(ssl)) + TLSX_WriteResponse(ssl, output + idx); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + #ifdef CYASSL_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 CYASSL_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(CYASSL* ssl) + { + int ret = 0; + (void)ssl; + + #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 CYASSL_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); + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_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 */ + + #ifdef HAVE_ECC + if (ssl->specs.kea == ecc_diffie_hellman_kea) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + byte exportBuf[MAX_EXPORT_ECC_SZ]; + word32 expSz = sizeof(exportBuf); + word32 sigSz; + word32 preSigSz, preSigIdx; +#ifndef NO_RSA + RsaKey rsaKey; +#endif + ecc_key dsaKey; + + if (ssl->specs.static_ecdh) { + CYASSL_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 */ + CYASSL_MSG("Using ephemeral ECDH"); + if (ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0) + return ECC_EXPORT_ERROR; + length += expSz; + + preSigSz = length; + preSigIdx = idx; + +#ifndef NO_RSA + ret = InitRsaKey(&rsaKey, ssl->heap); + if (ret != 0) return ret; +#endif + ecc_init(&dsaKey); + + /* sig length */ + length += LENGTH_SZ; + + if (!ssl->buffers.key.buffer) { +#ifndef NO_RSA + FreeRsaKey(&rsaKey); +#endif + ecc_free(&dsaKey); + return NO_PRIVATE_KEY; + } + +#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) return ret; + 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) return ret; + sigSz = ecc_sig_size(&dsaKey); /* worst case estimate */ + } + else { +#ifndef NO_RSA + FreeRsaKey(&rsaKey); +#endif + ecc_free(&dsaKey); + return ALGO_ID_E; /* unsupported type */ + } + length += sigSz; + + if (IsAtLeastTLSv1_2(ssl)) + length += HASH_SIG_SIZE; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_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); + return ret; + } + + /* 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 */ + + /* do signature */ + { +#ifndef NO_OLD_TLS + Md5 md5; + Sha sha; +#endif + byte hash[FINISHED_SZ]; + #ifndef NO_SHA256 + Sha256 sha256; + byte hash256[SHA256_DIGEST_SIZE]; + #endif + #ifdef CYASSL_SHA384 + Sha384 sha384; + byte hash384[SHA384_DIGEST_SIZE]; + #endif + +#ifndef NO_OLD_TLS + /* md5 */ + 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 */ + ret = InitSha(&sha); + if (ret != 0) + return ret; + 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 + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha256Final(&sha256, hash256); + if (ret != 0) + return ret; + #endif + + #ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha384Final(&sha384, hash384); + if (ret != 0) + return ret; + #endif +#ifndef NO_RSA + if (ssl->suites->sigAlgo == rsa_sa_algo) { + byte* signBuffer = hash; + word32 signSz = sizeof(hash); + byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaSignCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + 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 CYASSL_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); + if (ret > 0) + ret = 0; /* reset on success */ + } + FreeRsaKey(&rsaKey); + ecc_free(&dsaKey); + if (ret < 0) + return ret; + } 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; + + #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 = &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 CYASSL_SHA384 + digest = hash384; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + } + + if (doUserEcc) { + #ifdef HAVE_PK_CALLBACKS + #ifdef 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 /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + } + 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) return ret; + + /* 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; + } + } + + AddHeaders(output, length, server_key_exchange, ssl); + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_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 /* HAVE_ECC */ + + #ifdef OPENSSL_EXTRA + 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) { + ret = InitRsaKey(&rsaKey, ssl->heap); + if (ret != 0) return ret; + } + if (ret == 0) { + 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; + + /* 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; + } + } + if (ret != 0) { + FreeRsaKey(&rsaKey); + return ret; + } + + if (IsAtLeastTLSv1_2(ssl)) + length += HASH_SIG_SIZE; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_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) { + 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; + + /* Add signature */ + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = ssl->suites->hashAlgo; + output[idx++] = ssl->suites->sigAlgo; + } + /* size */ + c16toa((word16)sigSz, output + idx); + idx += LENGTH_SZ; + + /* do signature */ + { +#ifndef NO_OLD_TLS + Md5 md5; + Sha sha; +#endif + byte hash[FINISHED_SZ]; + #ifndef NO_SHA256 + Sha256 sha256; + byte hash256[SHA256_DIGEST_SIZE]; + #endif + #ifdef CYASSL_SHA384 + Sha384 sha384; + byte hash384[SHA384_DIGEST_SIZE]; + #endif + +#ifndef NO_OLD_TLS + /* md5 */ + 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 */ + ret = InitSha(&sha); + if (ret != 0) + return ret; + 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 + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha256Final(&sha256, hash256); + if (ret != 0) + return ret; + #endif + + #ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha384Final(&sha384, hash384); + if (ret != 0) + return ret; + #endif +#ifndef NO_RSA + if (ssl->suites->sigAlgo == rsa_sa_algo) { + byte* signBuffer = hash; + word32 signSz = sizeof(hash); + byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaSignCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + 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 CYASSL_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 /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaSSL_Sign(signBuffer, signSz, output + idx, + sigSz, &rsaKey, ssl->rng); + } + FreeRsaKey(&rsaKey); + if (ret < 0) + return ret; + } +#endif + } + + #ifdef CYASSL_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 CYASSL_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 /* OPENSSL_EXTRA */ + + 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) + { + /* 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; + + default: + CYASSL_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_CBC_SHA256 : + case TLS_PSK_WITH_AES_128_CBC_SHA : + case TLS_PSK_WITH_AES_256_CBC_SHA : + case TLS_PSK_WITH_NULL_SHA256 : + case TLS_PSK_WITH_NULL_SHA : + 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 + + default: + CYASSL_MSG("Unsupported cipher suite, CipherRequires"); + return 0; + } /* switch */ + } /* if ECC / Normal suites else */ + + return 0; + } + + + /* Make sure client setup is valid for this suite, true on success */ + int VerifyClientSuite(CYASSL* ssl) + { + int havePSK = 0; + byte first = ssl->options.cipherSuite0; + byte second = ssl->options.cipherSuite; + + CYASSL_ENTER("VerifyClientSuite"); + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + + if (CipherRequires(first, second, REQUIRES_PSK)) { + CYASSL_MSG("Requires PSK"); + if (havePSK == 0) { + CYASSL_MSG("Don't have PSK"); + return 0; + } + } + + return 1; /* success */ + } + + + /* Make sure server cert/key are valid for this suite, true on success */ + static int VerifyServerSuite(CYASSL* ssl, word16 idx) + { + int haveRSA = !ssl->options.haveStaticECC; + int havePSK = 0; + byte first; + byte second; + + CYASSL_ENTER("VerifyServerSuite"); + + if (ssl->suites == NULL) { + CYASSL_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)) { + CYASSL_MSG("Requires RSA"); + if (haveRSA == 0) { + CYASSL_MSG("Don't have RSA"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_DHE)) { + CYASSL_MSG("Requires DHE"); + if (ssl->options.haveDH == 0) { + CYASSL_MSG("Don't have DHE"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_ECC_DSA)) { + CYASSL_MSG("Requires ECCDSA"); + if (ssl->options.haveECDSAsig == 0) { + CYASSL_MSG("Don't have ECCDSA"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) { + CYASSL_MSG("Requires static ECC"); + if (ssl->options.haveStaticECC == 0) { + CYASSL_MSG("Don't have static ECC"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_PSK)) { + CYASSL_MSG("Requires PSK"); + if (havePSK == 0) { + CYASSL_MSG("Don't have PSK"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_NTRU)) { + CYASSL_MSG("Requires NTRU"); + if (ssl->options.haveNTRU == 0) { + CYASSL_MSG("Don't have NTRU"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_RSA_SIG)) { + CYASSL_MSG("Requires RSA Signature"); + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.haveECDSAsig == 1) { + CYASSL_MSG("Don't have RSA Signature"); + return 0; + } + } + +#ifdef HAVE_SUPPORTED_CURVES + if (!TLSX_ValidateEllipticCurves(ssl, first, second)) { + CYASSL_MSG("Don't have matching curves"); + return 0; + } +#endif + + /* ECCDHE is always supported if ECC on */ + + return 1; + } + + + static int MatchSuite(CYASSL* ssl, Suites* peerSuites) + { + word16 i, j; + + CYASSL_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; + CYASSL_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 { + CYASSL_MSG("Could not verify suite validity, continue"); + } + } + + return MATCH_SUITE_ERROR; + } + + + /* process old style client hello, deprecate? */ + int ProcessOldClientHello(CYASSL* 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; + CYASSL_MSG("Got old format client hello"); +#ifdef CYASSL_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) { + CYASSL_MSG("Client trying to connect with lesser version"); + return VERSION_ERROR; + } + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + CYASSL_MSG(" downgrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + CYASSL_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) { + CYASSL_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; + CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); + if (!session) { + CYASSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } else { + if (MatchSuite(ssl, &clSuites) < 0) { + CYASSL_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); + } + + + static int DoClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte b; + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + +#ifdef CYASSL_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) { + CYASSL_MSG("Client trying to connect with lesser version"); + return VERSION_ERROR; + } + + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + CYASSL_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+ */ + CYASSL_MSG(" downgrading to TLSv1"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + CYASSL_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 */ + CYASSL_MSG("Client wants to resume session"); + } + else if (b) { + CYASSL_MSG("Invalid session ID size"); + return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } + + #ifdef CYASSL_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) { + CYASSL_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) { + CYASSL_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 (IsTLS(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; + } + 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; + CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); + + if (!session) { + CYASSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } + else { + if (MatchSuite(ssl, &clSuites) < 0) { + CYASSL_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(CYASSL* 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 CYASSL_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 */ + + CYASSL_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)) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 sigSz; + byte* digest = ssl->certHashes.sha; + int typeH = SHAh; + int digestSz = SHA_DIGEST_SIZE; + + if (sigAlgo != rsa_sa_algo) { + CYASSL_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 CYASSL_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 */ + } + 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 + + CYASSL_MSG("Doing ECC peer cert verify"); + + if (IsAtLeastTLSv1_2(ssl)) { + if (sigAlgo != ecc_dsa_sa_algo) { + CYASSL_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 CYASSL_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(CYASSL* ssl) + { + byte *output; + int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int ret; + + #ifdef CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_DTLS + int SendHelloVerifyRequest(CYASSL* 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) { + CYASSL_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 CYASSL_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(CYASSL* 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; + + if (ssl->options.side != CYASSL_SERVER_END) { + CYASSL_MSG("Client received client keyexchange, attack?"); + CYASSL_ERROR(ssl->error = SIDE_ERROR); + return SSL_FATAL_ERROR; + } + + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + CYASSL_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) { + CYASSL_MSG("client didn't present peer cert"); + return NO_PEER_CERT; + } + #endif + + #ifdef CYASSL_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) { + CYASSL_MSG("RSA explicit size doesn't match"); + FreeRsaKey(&key); + return RSA_PRIVATE_ERROR; + } + } + + if ((*inOutIdx - begin) + length > size) { + CYASSL_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 != 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 (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 + 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 */ + #ifdef OPENSSL_EXTRA + 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 /* OPENSSL_EXTRA */ + default: + { + CYASSL_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_CYASSL_SERVER */ +