SSL/TLS Library
CyaSSL is SSL/TLS library for embedded systems.
Diff: src/internal.c
- Revision:
- 0:9d17e4342598
diff -r 000000000000 -r 9d17e4342598 src/internal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/internal.c Sun Apr 20 12:40:57 2014 +0000 @@ -0,0 +1,11096 @@ +/* internal.c + * + * Copyright (C) 2006-2013 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 void 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) { + int ret = InitRng(&rng); + if (ret == 0) + return 1; + else + return 0; + } + + if (out == NULL) + return 0; + + if (cmd == GET_BYTE_OF_ENTROPY) { + RNG_GenerateBlock(&rng, out, 1); + return 1; + } + + 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 void 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)) { +#ifndef NO_SHA256 + Sha256Update(&ssl->hashSha256, adj, sz); +#endif +#ifdef CYASSL_SHA384 + Sha384Update(&ssl->hashSha384, adj, sz); +#endif + } +} + + +/* add input to md5 and sha handshake hashes, include handshake header */ +static void 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)) { +#ifndef NO_SHA256 + Sha256Update(&ssl->hashSha256, adj, sz); +#endif +#ifdef CYASSL_SHA384 + Sha384Update(&ssl->hashSha384, adj, sz); +#endif + } +} + + +/* 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 + + 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; + + HashInput(ssl, input + *inOutIdx, size); + +#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); +} + +#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); +} + +#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); +} + +#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 void 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)) { + #ifndef NO_SHA256 + Sha256Final(&ssl->hashSha256, hashes->sha256); + #endif + #ifdef CYASSL_SHA384 + Sha384Final(&ssl->hashSha384, hashes->sha384); + #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 + } +} + +#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; + RNG_GenerateBlock(ssl->rng, iv, ivSz); + } + 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) { + HashOutput(ssl, output, headerSz + inSz, ivSz); + } + + 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 + HashOutput(ssl, output, sendSz, 0); + #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 + HashOutput(ssl, output, sendSz, 0); + + #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; + + 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) { + RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + + /* 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 + HashOutput(ssl, output, sendSz, 0); + + 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; + Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + Sha256Update(&sha256, messageVerify, verifySz); + Sha256Final(&sha256, hash256); +#endif + +#ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + Sha384Update(&sha384, messageVerify, verifySz); + Sha384Final(&sha384, hash384); +#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, 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: + RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, + SECRET_LEN); + 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' + }; + + RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, + SECRET_LEN); + 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 + HashOutput(ssl, output, sendSz, 0); + + #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; + + BuildCertHashes(ssl, &ssl->certHashes); + +#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 + 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) + RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_LEN); + 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) + RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, ID_LEN); + 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 + HashOutput(ssl, output, sendSz, 0); + + #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); + + HashOutput(ssl, output, sendSz, 0); + + #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; + Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + Sha256Update(&sha256, output + preSigIdx, preSigSz); + Sha256Final(&sha256, hash256); + #endif + + #ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + Sha384Update(&sha384, output + preSigIdx, preSigSz); + Sha384Final(&sha384, hash384); + #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); + HashOutput(ssl, output, sendSz, 0); + + #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; + Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + Sha256Update(&sha256, output + preSigIdx, preSigSz); + Sha256Final(&sha256, hash256); + #endif + + #ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + Sha384Update(&sha384, output + preSigIdx, preSigSz); + Sha384Final(&sha384, hash384); + #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 + HashOutput(ssl, output, sendSz, 0); + + #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; + + 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 : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_PSK_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_PSK_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_PSK) + return 1; + break; + + case TLS_PSK_WITH_NULL_SHA256 : + if (requirement == REQUIRES_PSK) + return 1; + break; + + 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 cert/key are valid for this suite, true on success */ + static int VerifySuite(CYASSL* ssl, word16 idx) + { + int haveRSA = !ssl->options.haveStaticECC; + int havePSK = 0; + byte first; + byte second; + + CYASSL_ENTER("VerifySuite"); + + 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 (VerifySuite(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)) + Sha256Update(&ssl->hashSha256, input + idx, sz); +#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 + RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_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.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 + RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_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.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 + HashOutput(ssl, output, sendSz, 0); +#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; + + HashOutput(ssl, output, sendSz, 0); +#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) + BuildCertHashes(ssl, &ssl->certHashes); + #endif + } + + return ret; + } + +#endif /* NO_CYASSL_SERVER */