/* 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 #endif #include #include #include #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 #else #include #endif #endif #ifdef __sun #include #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 #ifndef NO_CYASSL_CLIENT static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*); static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*); #ifndef NO_CERTS static int DoCertificateRequest(CYASSL* ssl, const byte* input,word32*); #endif #endif #ifndef NO_CYASSL_SERVER static int DoClientHello(CYASSL* ssl, const byte* input, word32*, 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 typedef enum { doProcessInit = 0, #ifndef NO_CYASSL_SERVER runProcessOldClientHello, #endif getRecordLayerHeader, getData, runProcessingOneMessage } processReply; #ifndef NO_OLD_TLS static void Hmac(CYASSL* ssl, byte* digest, const byte* buffer, word32 sz, int content, int verify); 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 = (c[0] << 8) | (c[1]); } /* 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]; } #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 Compress(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 DeCompress(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 = 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 #ifdef OPENSSL_EXTRA 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 && method->version.minor >= DTLSv1_2_MINOR) { ctx->CBIORecv = EmbedReceiveFrom; ctx->CBIOSend = EmbedSendTo; } #endif #else /* user will set */ ctx->CBIORecv = NULL; ctx->CBIOSend = NULL; #endif ctx->partialWrite = 0; ctx->verifyCallback = 0; #ifndef NO_CERTS ctx->cm = CyaSSL_CertManagerNew(); #endif #ifdef HAVE_NTRU if (method->side == CLIENT_END) ctx->haveNTRU = 1; /* always on cliet side */ /* server can turn on by loading key */ #endif #ifdef HAVE_ECC if (method->side == 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_OCSP CyaSSL_OCSP_Init(&ctx->ocsp); #endif #ifdef HAVE_CAVIUM ctx->devId = NO_CAVIUM_DEVICE; #endif if (InitMutex(&ctx->countMutex) < 0) { CYASSL_MSG("Mutex error on CTX init"); return BAD_MUTEX_ERROR; } #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_OCSP CyaSSL_OCSP_Cleanup(&ctx->ocsp); #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); 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 BUILD_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 == SERVER_END && haveStaticECC) haveRSA = 0; /* can't do RSA with ECDSA key */ if (side == 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 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 && haveStaticECC) { 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 && haveStaticECC) { 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 && haveStaticECC) { 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 && haveStaticECC) { 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 && haveStaticECC) { 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 && haveStaticECC) { 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_SHA256 if (tls1_2 && haveECDSAsig && haveDH) { suites->suites[idx++] = ECC_BYTE; suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SHA256; } #endif #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8_SHA384 if (tls1_2 && haveECDSAsig && haveDH) { suites->suites[idx++] = ECC_BYTE; suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8_SHA384; } #endif #ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8_SHA256 if (tls1_2 && haveRSA) { suites->suites[idx++] = ECC_BYTE; suites->suites[idx++] = TLS_RSA_WITH_AES_128_CCM_8_SHA256; } #endif #ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8_SHA384 if (tls1_2 && haveRSA) { suites->suites[idx++] = ECC_BYTE; suites->suites[idx++] = TLS_RSA_WITH_AES_256_CCM_8_SHA384; } #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_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_CBC_MD5 if (tls && haveRSA) { suites->suites[idx++] = 0; suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_MD5; } #endif #ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA if (tls && haveRSA) { suites->suites[idx++] = 0; suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_SHA; } #endif #ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA if (tls && haveRSA) { suites->suites[idx++] = 0; suites->suites[idx++] = TLS_RSA_WITH_RABBIT_CBC_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 suites->hashSigAlgo[idx++] = sha_mac; suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; } 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 suites->hashSigAlgo[idx++] = sha_mac; suites->hashSigAlgo[idx++] = rsa_sa_algo; } suites->hashSigAlgoSz = idx; } } /* 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.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.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 OPENSSL_EXTRA ssl->peerCert.derCert.buffer = NULL; ssl->peerCert.altNames = NULL; ssl->peerCert.altNamesNext = NULL; #endif #ifdef HAVE_ECC ssl->eccTempKeySz = ctx->eccTempKeySz; 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 */ #ifndef NO_OLD_TLS #ifndef NO_MD5 InitMd5(&ssl->hashMd5); #endif #ifndef NO_SHA InitSha(&ssl->hashSha); #endif #endif #ifndef NO_SHA256 InitSha256(&ssl->hashSha256); #endif #ifdef CYASSL_SHA384 InitSha384(&ssl->hashSha384); #endif #ifndef NO_RSA ssl->peerRsaKey = NULL; ssl->peerRsaKeyPresent = 0; #endif ssl->verifyCallback = ctx->verifyCallback; 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 == 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_peer_sequence_number = 0; ssl->keys.dtls_expected_peer_sequence_number = 0; ssl->keys.dtls_handshake_number = 0; ssl->keys.dtls_expected_peer_handshake_number = 0; ssl->keys.dtls_epoch = 0; ssl->keys.dtls_peer_epoch = 0; ssl->keys.dtls_expected_peer_epoch = 0; ssl->dtls_timeout = DTLS_DEFAULT_TIMEOUT; ssl->dtls_pool = NULL; ssl->dtls_msg_list = NULL; #endif ssl->keys.encryptSz = 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 = 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; if (ssl->version.major == DTLS_MAJOR && ssl->version.minor >= DTLSv1_2_MINOR) ssl->options.dtls = 1; else ssl->options.dtls = 0; 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 == 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 OPENSSL_EXTRA ssl->peerCert.issuer.sz = 0; ssl->peerCert.subject.sz = 0; #endif #ifdef SESSION_CERTS ssl->session.chain.count = 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 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); /* 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_ERROR; } 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; } #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; } InitRsaKey(ssl->peerRsaKey, ctx->heap); #endif #ifndef NO_CERTS /* make sure server has cert and key unless using PSK */ if (ssl->options.side == 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 == 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 == 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(OPENSSL_EXTRA) || defined(GOAHEAD_WS) XFREE(ssl->peerCert.derCert.buffer, ssl->heap, DYNAMIC_TYPE_CERT); if (ssl->peerCert.altNames) FreeAltNames(ssl->peerCert.altNames, ssl->heap); 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 } /* 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 } 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 = DTLS_DEFAULT_TIMEOUT; } int DtlsPoolTimeout(CYASSL* ssl) { int result = -1; if (ssl->dtls_timeout < 64) { ssl->dtls_timeout *= 2; result = 0; } return result; } int DtlsPoolSend(CYASSL* ssl) { 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; if (dtls->type == change_cipher_spec) { ssl->keys.dtls_epoch++; ssl->keys.dtls_sequence_number = 0; } c16toa(ssl->keys.dtls_epoch, dtls->epoch); c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number); 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); 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 timer_d Timer(void) { static int init = 0; static LARGE_INTEGER freq; LARGE_INTEGER count; if (!init) { QueryPerformanceFrequency(&freq); init = 1; } QueryPerformanceCounter(&count); return (double)count.QuadPart / freq.QuadPart; } word32 LowResTimer(void) { return (word32)Timer(); } #elif defined(THREADX) #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(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 && !THREADX && !MICRIUM && !USER_TICKS */ #include 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; retry: recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx); if (recvd < 0) switch (recvd) { case IO_ERR_GENERAL: /* general/unknown error */ return -1; case IO_ERR_WANT_READ: /* want read, would block */ return WANT_READ; case IO_ERR_CONN_RST: /* connection reset */ #ifdef USE_WINDOWS_API if (ssl->options.dtls) { goto retry; } #endif ssl->options.connReset = 1; return -1; case IO_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 IO_ERR_CONN_CLOSE: /* peer closed connection */ ssl->options.isClosed = 1; return -1; case IO_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->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; } /* 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->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.idx = 0; ssl->buffers.inputBuffer.length = usedLength; } int SendBuffered(CYASSL* ssl) { 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 IO_ERR_WANT_WRITE: /* would block */ return WANT_WRITE; case IO_ERR_CONN_RST: /* connection reset */ ssl->options.connReset = 1; break; case IO_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 IO_ERR_CONN_CLOSE: /* epipe / conn closed, same as reset */ ssl->options.connReset = 1; 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*) XMALLOC(size + ssl->buffers.outputBuffer.length, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); CYASSL_MSG("growing output buffer\n"); if (!tmp) return MEMORY_E; 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->heap, DYNAMIC_TYPE_OUT_BUFFER); ssl->buffers.outputBuffer.dynamicFlag = 1; 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*) XMALLOC(size + usedLength, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); CYASSL_MSG("growing input buffer\n"); if (!tmp) return MEMORY_E; if (usedLength) XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, usedLength); if (ssl->buffers.inputBuffer.dynamicFlag) XFREE(ssl->buffers.inputBuffer.buffer,ssl->heap,DYNAMIC_TYPE_IN_BUFFER); ssl->buffers.inputBuffer.dynamicFlag = 1; ssl->buffers.inputBuffer.buffer = tmp; ssl->buffers.inputBuffer.bufferSize = size + usedLength; ssl->buffers.inputBuffer.idx = 0; ssl->buffers.inputBuffer.length = usedLength; return 0; } /* check avalaible size into output buffer, make room if needed */ int CheckAvalaibleSize(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_peer_epoch); *inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */ ato32(input + *inOutIdx, &ssl->keys.dtls_peer_sequence_number); *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 == SERVER_END && ssl->options.acceptState == ACCEPT_BEGIN) CYASSL_MSG("Client attempting to connect with different version"); else if (ssl->options.side == 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 */ } } #if 0 /* Instead of this, check the datagram against the sliding window of * received datagram goodness. */ #ifdef CYASSL_DTLS /* If DTLS, check the sequence number against expected. If out of * order, drop the record. Allows newer records in and resets the * expected to the next record. */ if (ssl->options.dtls) { if ((ssl->keys.dtls_expected_peer_epoch == ssl->keys.dtls_peer_epoch) && (ssl->keys.dtls_peer_sequence_number >= ssl->keys.dtls_expected_peer_sequence_number)) { ssl->keys.dtls_expected_peer_sequence_number = ssl->keys.dtls_peer_sequence_number + 1; } else { return SEQUENCE_ERROR; } } #endif #endif /* record layer length check */ if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) return LENGTH_ERROR; /* verify record type here as well */ switch ((enum ContentType)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 void 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 if (ssl->options.tls) BuildTlsFinished(ssl, hashes, sender); #ifndef NO_OLD_TLS else { 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 } } #ifndef NO_CERTS static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) { word32 listSz, i = *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 c24to32(&input[i], &listSz); i += CERT_HEADER_SZ; 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) { /* cert size */ word32 certSz; if (totalCerts >= MAX_CHAIN_DEPTH) return MAX_CHAIN_ERROR; c24to32(&input[i], &certSz); i += CERT_HEADER_SZ; if (listSz > MAX_RECORD_SIZE || certSz > MAX_RECORD_SIZE) return BUFFER_E; certs[totalCerts].length = certSz; certs[totalCerts].buffer = input + i; #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 + i, certSz); ssl->session.chain.count++; } else { CYASSL_MSG("Couldn't store chain cert for session"); } #endif i += 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; InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, ssl->ctx->cm); 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, dCert.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("Veriying 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) { ret = CyaSSL_OCSP_Lookup_Cert(&ssl->ctx->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->ocsp.enabled) { 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 OPENSSL_EXTRA /* set X509 format for peer cert even if fatal */ XSTRNCPY(ssl->peerCert.issuer.name, dCert.issuer, ASN_NAME_MAX); ssl->peerCert.issuer.name[ASN_NAME_MAX - 1] = '\0'; ssl->peerCert.issuer.sz = (int)XSTRLEN(ssl->peerCert.issuer.name) + 1; XSTRNCPY(ssl->peerCert.subject.name, dCert.subject, ASN_NAME_MAX); ssl->peerCert.subject.name[ASN_NAME_MAX - 1] = '\0'; ssl->peerCert.subject.sz = (int)XSTRLEN(ssl->peerCert.subject.name) + 1; XMEMCPY(ssl->peerCert.serial, dCert.serial, EXTERNAL_SERIAL_SIZE); ssl->peerCert.serialSz = dCert.serialSz; if (dCert.subjectCNLen < ASN_NAME_MAX) { XMEMCPY(ssl->peerCert.subjectCN,dCert.subjectCN,dCert.subjectCNLen); ssl->peerCert.subjectCN[dCert.subjectCNLen] = '\0'; } else ssl->peerCert.subjectCN[0] = '\0'; /* store cert for potential retrieval */ ssl->peerCert.derCert.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, DYNAMIC_TYPE_CERT); if (ssl->peerCert.derCert.buffer == NULL) { ret = MEMORY_E; fatal = 1; } else { XMEMCPY(ssl->peerCert.derCert.buffer, myCert.buffer, myCert.length); ssl->peerCert.derCert.length = myCert.length; } ssl->peerCert.altNames = dCert.altNames; dCert.altNames = NULL; /* takes ownership */ ssl->peerCert.altNamesNext = ssl->peerCert.altNames; /* index hint */ #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 (XSTRNCMP((char*)ssl->buffers.domainName.buffer, dCert.subjectCN, ssl->buffers.domainName.length - 1) != 0) { 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; } 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; } break; #endif /* HAVE_ECC */ default: break; } FreeDecodedCert(&dCert); } if (anyError != 0 && ret == 0) ret = anyError; if (ret == 0 && ssl->options.side == 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.domain = domain; #ifdef OPENSSL_EXTRA 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; } } if (ret != 0) { SendAlert(ssl, alert_fatal, why); /* try to send */ ssl->options.isClosed = 1; } } ssl->error = ret; } #ifdef FORTRESS else { if (ssl->verifyCallback) { int ok; CYASSL_X509_STORE_CTX store; store.error = ret; store.error_depth = totalCerts; store.domain = domain; store.current_cert = &ssl->peerCert; 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; } } } #endif *inOutIdx = i; return ret; } #endif /* !NO_CERTS */ static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx) { if (ssl->keys.encryptionOn) { const byte* mac; int padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - ssl->specs.hash_size; byte verify[SHA256_DIGEST_SIZE]; ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ, HANDSHAKE_HEADER_SZ, handshake, 1); /* read mac and fill */ mac = input + *inOutIdx; *inOutIdx += ssl->specs.hash_size; if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) padSz -= ssl->specs.block_size; *inOutIdx += padSz; /* verify */ if (XMEMCMP(mac, verify, ssl->specs.hash_size) != 0) { CYASSL_MSG(" hello_request verify mac error"); return VERIFY_MAC_ERROR; } } if (ssl->options.side == 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, int sniff) { int finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ; int headerSz = HANDSHAKE_HEADER_SZ; word32 macSz = finishedSz + HANDSHAKE_HEADER_SZ, idx = *inOutIdx, padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - finishedSz - ssl->specs.hash_size; const byte* mac; #ifdef CYASSL_DTLS if (ssl->options.dtls) { headerSz += DTLS_HANDSHAKE_EXTRA; macSz += DTLS_HANDSHAKE_EXTRA; padSz -= DTLS_HANDSHAKE_EXTRA; } #endif #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 + idx, &ssl->verifyHashes, finishedSz) != 0) { CYASSL_MSG("Verify finished error on hashes"); return VERIFY_FINISHED_ERROR; } } if (ssl->specs.cipher_type != aead) { byte verifyMAC[MAX_DIGEST_SIZE]; ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz, handshake, 1); idx += finishedSz; /* read mac and fill */ mac = input + idx; idx += ssl->specs.hash_size; if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) padSz -= ssl->specs.block_size; idx += padSz; /* verify mac */ if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size) != 0) { CYASSL_MSG("Verify finished error on mac"); return VERIFY_MAC_ERROR; } } else { idx += (finishedSz + AEAD_AUTH_TAG_SZ); } if (ssl->options.side == CLIENT_END) { ssl->options.serverState = SERVER_FINISHED_COMPLETE; if (!ssl->options.resuming) ssl->options.handShakeState = HANDSHAKE_DONE; } else { ssl->options.clientState = CLIENT_FINISHED_COMPLETE; if (ssl->options.resuming) ssl->options.handShakeState = HANDSHAKE_DONE; } *inOutIdx = idx; 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"); 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 == 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 == 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 == 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); break; #ifndef NO_CYASSL_CLIENT case hello_verify_request: CYASSL_MSG("processing hello verify request"); ret = DoHelloVerifyRequest(ssl, input,inOutIdx); 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); break; #endif case server_key_exchange: CYASSL_MSG("processing server key exchange"); ret = DoServerKeyExchange(ssl, input, inOutIdx); break; #endif #ifndef NO_CERTS case certificate: CYASSL_MSG("processing certificate"); ret = DoCertificate(ssl, input, inOutIdx); 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, NO_SNIFF); break; #ifndef NO_CYASSL_SERVER case client_hello: CYASSL_MSG("processing client hello"); ret = DoClientHello(ssl, input, inOutIdx, totalSz, size); break; case client_key_exchange: CYASSL_MSG("processing client key exchange"); ret = DoClientKeyExchange(ssl, input, inOutIdx, totalSz); break; #if !defined(NO_RSA) || defined(HAVE_ECC) case certificate_verify: CYASSL_MSG("processing certificate verify"); ret = DoCertificateVerify(ssl, input, inOutIdx, totalSz); break; #endif /* !NO_RSA || HAVE_ECC */ #endif /* !NO_CYASSL_SERVER */ default: CYASSL_MSG("Unknown handshake message type"); ret = UNKNOWN_HANDSHAKE_TYPE; } 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; if (*inOutIdx + size > totalSz) return INCOMPLETE_DATA; ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); CYASSL_LEAVE("DoHandShakeMsg()", ret); return ret; } #ifdef CYASSL_DTLS static int DtlsMsgDrain(CYASSL* ssl) { DtlsMsg* item = ssl->dtls_msg_list; int ret = 0; word32 idx = 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) { 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->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, word32 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 rc4: Arc4Process(ssl->encrypt.arc4, out, input, sz); break; #endif #ifdef BUILD_DES3 case triple_des: Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz); break; #endif #ifdef BUILD_AES case aes: #ifdef CYASSL_AESNI if ((word)input % 16) { byte* tmp = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) return MEMORY_E; XMEMCPY(tmp, input, sz); AesCbcEncrypt(ssl->encrypt.aes, tmp, tmp, sz); XMEMCPY(out, tmp, sz); XFREE(tmp, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); break; } #endif AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); break; #endif #ifdef BUILD_AESGCM case 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 - AEAD_AUTH_TAG_SZ, 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 - AEAD_AUTH_TAG_SZ, nonce, AEAD_NONCE_SZ, out + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, additional, AEAD_AUTH_DATA_SZ); AeadIncrementExpIV(ssl); XMEMSET(nonce, 0, AEAD_NONCE_SZ); } break; #endif #ifdef HAVE_AESCCM case 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) 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 - AEAD_AUTH_TAG_SZ, 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 - AEAD_AUTH_TAG_SZ, nonce, AEAD_NONCE_SZ, out + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, additional, AEAD_AUTH_DATA_SZ); AeadIncrementExpIV(ssl); XMEMSET(nonce, 0, AEAD_NONCE_SZ); } break; #endif #ifdef HAVE_CAMELLIA case camellia: CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz); break; #endif #ifdef HAVE_HC128 case hc128: #ifdef XSTREAM_ALIGNMENT if ((word)input % 4) { byte* tmp = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) return MEMORY_E; XMEMCPY(tmp, input, sz); Hc128_Process(ssl->encrypt.hc128, tmp, tmp, sz); XMEMCPY(out, tmp, sz); XFREE(tmp, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); break; } #endif Hc128_Process(ssl->encrypt.hc128, out, input, sz); break; #endif #ifdef BUILD_RABBIT case rabbit: #ifdef XSTREAM_ALIGNMENT if ((word)input % 4) { byte* tmp = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) return MEMORY_E; XMEMCPY(tmp, input, sz); RabbitProcess(ssl->encrypt.rabbit, tmp, tmp, sz); XMEMCPY(out, tmp, sz); XFREE(tmp, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); break; } #endif RabbitProcess(ssl->encrypt.rabbit, out, input, sz); break; #endif #ifdef HAVE_NULL_CIPHER case 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, word32 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 rc4: Arc4Process(ssl->decrypt.arc4, plain, input, sz); break; #endif #ifdef BUILD_DES3 case triple_des: Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz); break; #endif #ifdef BUILD_AES case aes: AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); break; #endif #ifdef BUILD_AESGCM case 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 - AEAD_AUTH_TAG_SZ, 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 - AEAD_AUTH_TAG_SZ, nonce, AEAD_NONCE_SZ, input + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, 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 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); 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 - AEAD_AUTH_TAG_SZ, 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 - AEAD_AUTH_TAG_SZ, nonce, AEAD_NONCE_SZ, input + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, 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 camellia: CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz); break; #endif #ifdef HAVE_HC128 case hc128: Hc128_Process(ssl->decrypt.hc128, plain, input, sz); break; #endif #ifdef BUILD_RABBIT case rabbit: RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); break; #endif #ifdef HAVE_NULL_CIPHER case 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) { word32 minLength = 0; if (ssl->specs.cipher_type == block) { if (encryptSz % ssl->specs.block_size) { CYASSL_MSG("Block ciphertext not block size"); return SANITY_CIPHER_E; } minLength = ssl->specs.hash_size + 1; /* 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 == stream) { minLength = ssl->specs.hash_size; } else if (ssl->specs.cipher_type == aead) { minLength = ssl->specs.block_size; /* explicit IV + implicit IV + CTR*/ } if (encryptSz < minLength) { CYASSL_MSG("Ciphertext not minimum size"); return SANITY_CIPHER_E; } return 0; } /* decrypt input message in place */ static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx) { int decryptResult; int sanityResult = SanityCheckCipherText(ssl, sz); if (sanityResult != 0) return sanityResult; decryptResult = Decrypt(ssl, input, input, sz); if (decryptResult == 0) { ssl->keys.encryptSz = sz; ssl->keys.decryptedCur = 1; if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) *idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ if (ssl->specs.cipher_type == aead) *idx += AEAD_EXP_IV_SZ; } return decryptResult; } #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); } static INLINE void ShaRounds(int rounds, const byte* data, int sz) { Sha sha; int i; InitSha(&sha); 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); 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); 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); 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 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) { byte verify[MAX_DIGEST_SIZE]; byte dummy[MAX_PAD_SIZE]; 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, application_data, 1); 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, application_data, 1); ConstantCompare(verify, input + pLen - t, t); return VERIFY_MAC_ERROR; } PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, application_data, 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; } return 0; } int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) { word32 msgSz = ssl->keys.encryptSz; word32 pad = 0, padByte = 0, idx = *inOutIdx, digestSz = ssl->specs.hash_size; int dataSz, ret; int ivExtra = 0; byte* rawData = input + idx; /* keep current for hmac */ #ifdef HAVE_LIBZ byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; #endif byte verify[MAX_DIGEST_SIZE]; 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; pad = *(input + idx + msgSz - ivExtra - 1); padByte = 1; if (ssl->options.tls) { ret = TimingPadVerify(ssl, input + idx, pad, digestSz, msgSz - ivExtra); if (ret != 0) return ret; } else { /* sslv3, some implementations have bad padding */ ssl->hmac(ssl, verify, rawData, msgSz - digestSz - pad - 1, application_data, 1); if (ConstantCompare(verify, rawData + msgSz - digestSz - pad - 1, digestSz) != 0) return VERIFY_MAC_ERROR; } } else if (ssl->specs.cipher_type == stream) { ssl->hmac(ssl, verify, rawData, msgSz - digestSz, application_data, 1); if (ConstantCompare(verify, rawData + msgSz - digestSz, digestSz) != 0){ return VERIFY_MAC_ERROR; } } else if (ssl->specs.cipher_type == aead) { ivExtra = AEAD_EXP_IV_SZ; digestSz = AEAD_AUTH_TAG_SZ; } dataSz = msgSz - ivExtra - digestSz - pad - padByte; 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 = DeCompress(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 += digestSz; idx += pad; if (padByte) idx++; #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) { 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 level = input[(*inOutIdx)++]; code = (int)input[(*inOutIdx)++]; ssl->alert_history.last_rx.code = code; ssl->alert_history.last_rx.level = level; *type = code; CYASSL_MSG("Got alert"); if (*type == close_notify) { CYASSL_MSG(" close notify"); ssl->options.closeNotify = 1; } CYASSL_ERROR(*type); if (ssl->keys.encryptionOn) { if (ssl->specs.cipher_type != aead) { int aSz = ALERT_SIZE; const byte* mac; byte verify[MAX_DIGEST_SIZE]; int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size; ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1); /* read mac and fill */ mac = input + *inOutIdx; *inOutIdx += (ssl->specs.hash_size + padSz); /* verify */ if (XMEMCMP(mac, verify, ssl->specs.hash_size) != 0) { CYASSL_MSG(" alert verify mac error"); return VERIFY_MAC_ERROR; } } else { *inOutIdx += AEAD_AUTH_TAG_SZ; } } return level; } static int GetInputData(CYASSL *ssl, word32 size) { int in; int inSz; int maxLength; int usedLength; /* 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) inSz = MAX_MTU; /* read ahead up to MTU */ #endif if (inSz > maxLength) { if (GrowInputBuffer(ssl, size, 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; } /* 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; word32 startIdx = 0; #ifndef NO_CYASSL_SERVER byte b0, b1; #endif #ifdef CYASSL_DTLS int used; #endif for (;;) { switch ((processReply)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 == 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 = ((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) { /* This message is out of order. If we are handshaking, save *it for later. Otherwise go ahead and process it. */ 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: if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0) { ret = DecryptMessage(ssl, ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, ssl->curSize, &ssl->buffers.inputBuffer.idx); if (ret < 0) { CYASSL_ERROR(ret); return DECRYPT_ERROR; } } 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 == 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_expected_peer_epoch++; ssl->keys.dtls_expected_peer_sequence_number = 0; } #endif #ifdef HAVE_LIBZ if (ssl->options.usingCompression) if ( (ret = InitStreams(ssl)) != 0) return ret; #endif if (ssl->options.resuming && ssl->options.side == CLIENT_END) BuildFinished(ssl, &ssl->verifyHashes, server); else if (!ssl->options.resuming && ssl->options.side == SERVER_END) BuildFinished(ssl, &ssl->verifyHashes, client); 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!"); if (DoAlert(ssl, ssl->buffers.inputBuffer.buffer, &ssl->buffers.inputBuffer.idx, &type) == alert_fatal) return FATAL_ERROR; /* 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 = CheckAvalaibleSize(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; else return SendBuffered(ssl); } static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify) { if ( (ssl->options.side == CLIENT_END && !verify) || (ssl->options.side == SERVER_END && verify) ) return ssl->keys.client_write_MAC_secret; else return ssl->keys.server_write_MAC_secret; } #ifndef NO_OLD_TLS static void 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; Md5 md5; Sha sha; /* data */ byte seq[SEQ_SZ]; byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */ const byte* macSecret = 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 { InitSha(&sha); /* 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); } } 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 #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) { word32 digestSz = ssl->specs.hash_size; 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; #ifdef CYASSL_DTLS if (ssl->options.dtls) { sz += DTLS_RECORD_EXTRA; idx += DTLS_RECORD_EXTRA; headerSz += DTLS_RECORD_EXTRA; } #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 + 16 - 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) { #ifdef CYASSL_DTLS if (ssl->options.dtls) { if ((ret = DtlsPoolSave(ssl, output, headerSz+inSz)) != 0) return ret; } #endif HashOutput(ssl, output, headerSz + inSz, ivSz); } if (ssl->specs.cipher_type != aead) { ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); idx += digestSz; } if (ssl->specs.cipher_type == block) for (i = 0; i <= pad; i++) output[idx++] = (byte)pad; /* pad byte gets pad value too */ 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 if (ssl->options.dtls) { headerSz += DTLS_HANDSHAKE_EXTRA; ssl->keys.dtls_epoch++; ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */ } #endif /* check for avalaible size */ if ((ret = CheckAvalaibleSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0) return ret; /* get ouput buffer */ output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; AddHandShakeHeader(input, finishedSz, finished, ssl); /* make finished hashes */ hashes = (Hashes*)&input[headerSz]; BuildFinished(ssl, hashes, ssl->options.side == CLIENT_END ? client : server); if ( (sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake)) < 0) return BUILD_MSG_ERROR; if (!ssl->options.resuming) { #ifndef NO_SESSION_CACHE AddSession(ssl); /* just try */ #endif if (ssl->options.side == CLIENT_END) BuildFinished(ssl, &ssl->verifyHashes, server); else ssl->options.handShakeState = HANDSHAKE_DONE; } else { if (ssl->options.side == CLIENT_END) ssl->options.handShakeState = HANDSHAKE_DONE; else BuildFinished(ssl, &ssl->verifyHashes, client); } #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 avalaible size */ if ((ret = CheckAvalaibleSize(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 == 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 avalaible size */ if ((ret = CheckAvalaibleSize(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)) != 0) 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 (;;) { int len = min(sz - sent, OUTPUT_RECORD_SIZE); 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 avalaible size */ if ((ret = CheckAvalaibleSize(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 = Compress(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->options.handShakeState != HANDSHAKE_DONE) { int err; CYASSL_MSG("Handshake not complete, trying to finish"); if ( (err = CyaSSL_negotiate(ssl)) != 0) 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"); ssl->options.isClosed = 1; /* Don't send close_notify */ 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; /* if sendalert is called again for nonbloking */ if (ssl->options.sendAlertState != 0) { ret = SendBuffered(ssl); if (ret == 0) ssl->options.sendAlertState = 0; return ret; } /* check for avalaible size */ if ((ret = CheckAvalaibleSize(ssl, ALERT_SIZE + MAX_MSG_EXTRA)) != 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; /* 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 output += DTLS_RECORD_EXTRA; #endif XMEMCPY(output, input, ALERT_SIZE); sendSz = RECORD_HEADER_SZ + ALERT_SIZE; #ifdef CYASSL_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 = 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 BAD_MUTEX_ERROR: XSTRNCPY(str, "Bad mutex, operation failed", 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; default : XSTRNCPY(str, "unknown error number", max); } #endif /* NO_ERROR_STRINGS */ } /* be sure to add to cipher_name_idx too !!!! */ 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_NULL_SHA256 "PSK-NULL-SHA256", #endif #ifdef BUILD_TLS_PSK_WITH_NULL_SHA "PSK-NULL-SHA", #endif #ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5 "HC128-MD5", #endif #ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA "HC128-SHA", #endif #ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_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_SHA256 "AES128-CCM-8-SHA256", #endif #ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8_SHA384 "AES256-CCM-8-SHA384", #endif #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SHA256 "ECDHE-ECDSA-AES128-CCM-8-SHA256", #endif #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8_SHA384 "ECDHE-ECDSA-AES256-CCM-8-SHA384", #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 */ 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_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_CBC_MD5 TLS_RSA_WITH_HC_128_CBC_MD5, #endif #ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA TLS_RSA_WITH_HC_128_CBC_SHA, #endif #ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA TLS_RSA_WITH_RABBIT_CBC_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_SHA256 TLS_RSA_WITH_AES_128_CCM_8_SHA256, #endif #ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8_SHA384 TLS_RSA_WITH_AES_256_CCM_8_SHA384, #endif #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SHA256, #endif #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8_SHA384, #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; } #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; 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; if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { length += ssl->suites->hashSigAlgoSz + HELLO_EXT_SZ; } 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 avalaible size */ if ((ret = CheckAvalaibleSize(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; 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]; } } #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) { ProtocolVersion pv; byte cookieSz; #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 XMEMCPY(&pv, input + *inOutIdx, sizeof(pv)); *inOutIdx += (word32)sizeof(pv); cookieSz = input[(*inOutIdx)++]; if (cookieSz) { #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; byte compression; ProtocolVersion pv; word32 i = *inOutIdx; word32 begin = i; #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); #endif XMEMCPY(&pv, input + i, sizeof(pv)); i += (word32)sizeof(pv); 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; } else 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; } } XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); i += RAN_LEN; b = input[i++]; if (b) { XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN)); i += b; ssl->options.haveSessionId = 1; } 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; if ( (i - begin) < helloSz) *inOutIdx = begin + helloSz; /* skip extensions */ ssl->options.serverState = SERVER_HELLO_COMPLETE; *inOutIdx = i; if (ssl->options.resuming) { if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, ssl->session.sessionID, ID_LEN) == 0) { if (SetCipherSpecs(ssl) == 0) { int ret; XMEMCPY(ssl->arrays->masterSecret, ssl->session.masterSecret, SECRET_LEN); #ifndef NO_OLD_TLS if (ssl->options.tls) ret = DeriveTlsKeys(ssl); else ret = DeriveKeys(ssl); #else ret = DeriveTlsKeys(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) { word16 len; #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("CertificateRequest", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); #endif len = input[(*inOutIdx)++]; /* types, read in here */ *inOutIdx += len; if (IsAtLeastTLSv1_2(ssl)) { /* hash sig format */ ato16(&input[*inOutIdx], &len); *inOutIdx += LENGTH_SZ; PickHashSigAlgo(ssl, &input[*inOutIdx], len); *inOutIdx += len; } /* authorities */ ato16(&input[*inOutIdx], &len); *inOutIdx += LENGTH_SZ; while (len) { word16 dnSz; ato16(&input[*inOutIdx], &dnSz); *inOutIdx += (REQUEST_HEADER + dnSz); len -= dnSz + REQUEST_HEADER; } /* 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 (IsAtLeastTLSv1_2(ssl)) ssl->options.sendVerify = SEND_BLANK_CERT; return 0; } #endif /* !NO_CERTS */ static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32* inOutIdx) { #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) word16 length = 0; word16 sigLen = 0; word16 verifySz = (word16)*inOutIdx; /* keep start idx */ byte* signature = 0; #endif (void)ssl; (void)input; (void)inOutIdx; #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) { word16 pskLen = 0; ato16(&input[*inOutIdx], &pskLen); *inOutIdx += LENGTH_SZ; XMEMCPY(ssl->arrays->server_hint, &input[*inOutIdx], min(pskLen, MAX_PSK_ID_LEN)); if (pskLen < MAX_PSK_ID_LEN) ssl->arrays->server_hint[pskLen] = 0; else ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = 0; *inOutIdx += pskLen; return 0; } #endif #ifdef OPENSSL_EXTRA if (ssl->specs.kea == diffie_hellman_kea) { /* p */ ato16(&input[*inOutIdx], &length); *inOutIdx += LENGTH_SZ; 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 */ ato16(&input[*inOutIdx], &length); *inOutIdx += LENGTH_SZ; 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 */ ato16(&input[*inOutIdx], &length); *inOutIdx += LENGTH_SZ; 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 = input[*inOutIdx]; *inOutIdx += 1; if (b != named_curve) return ECC_CURVETYPE_ERROR; *inOutIdx += 1; /* curve type, eat leading 0 */ b = input[*inOutIdx]; *inOutIdx += 1; if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b != secp160r1 && b != secp192r1 && b != secp224r1) return ECC_CURVE_ERROR; length = input[*inOutIdx]; *inOutIdx += 1; 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 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 byte messageVerify[MAX_DH_SZ]; byte hashAlgo = sha_mac; byte sigAlgo = ssl->specs.sig_algo; /* adjust from start idx */ verifySz = (word16)(*inOutIdx - verifySz); /* save message for hash verify */ if (verifySz > sizeof(messageVerify)) return BUFFER_ERROR; XMEMCPY(messageVerify, &input[*inOutIdx - verifySz], verifySz); if (IsAtLeastTLSv1_2(ssl)) { hashAlgo = input[*inOutIdx]; *inOutIdx += 1; sigAlgo = input[*inOutIdx]; *inOutIdx += 1; } /* signature */ ato16(&input[*inOutIdx], &length); *inOutIdx += LENGTH_SZ; signature = (byte*)&input[*inOutIdx]; *inOutIdx += length; sigLen = length; /* 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 */ InitSha(&sha); 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 InitSha256(&sha256); 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 InitSha384(&sha384); 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) { int ret; byte* out; if (!ssl->peerRsaKeyPresent) return NO_PEER_KEY; ret = RsaSSL_VerifyInline(signature, sigLen,&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 || XMEMCMP(out, encodedSig, min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) return VERIFY_SIGN_ERROR; } else { if (ret != sizeof(hash) || 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, ret; #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 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 } } ret = ecc_verify_hash(signature, sigLen, digest, digestSz, &verify, ssl->peerEccDsaKey); if (ret != 0 || verify == 0) return VERIFY_SIGN_ERROR; } else #endif /* HAVE_ECC */ return ALGO_ID_E; 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; 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; 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; } 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 = &myKey; 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; } 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 avalaible size */ if ((ret = CheckAvalaibleSize(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; } 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; #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 avalaible size */ if ((ret = CheckAvalaibleSize(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 InitRsaKey(&key, ssl->heap); 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; #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 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 } } 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 { 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 */ 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 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; /* check for avalaible size */ if ((ret = CheckAvalaibleSize(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; /* last, compression */ if (ssl->options.usingCompression) output[idx++] = ZLIB_COMPRESSION; else output[idx++] = NO_COMPRESSION; 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; break; case 24: return secp192r1; break; case 28: return secp224r1; break; case 32: return secp256r1; break; case 48: return secp384r1; break; case 66: return secp521r1; break; 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 avalaible size */ if ((ret = CheckAvalaibleSize(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 InitRsaKey(&rsaKey, ssl->heap); #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) + 2; /* 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 avalaible size */ if ((ret = CheckAvalaibleSize(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 */ InitSha(&sha); 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 InitSha256(&sha256); 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 InitSha384(&sha384); 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]; 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; ret = RsaSSL_Sign(signBuffer, signSz, output + idx, sigSz, &rsaKey, ssl->rng); FreeRsaKey(&rsaKey); ecc_free(&dsaKey); if (ret > 0) ret = 0; /* reset on success */ else 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; 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 } } 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); InitRsaKey(&rsaKey, ssl->heap); 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 avalaible size */ if ((ret = CheckAvalaibleSize(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 */ InitSha(&sha); 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 InitSha256(&sha256); 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 InitSha384(&sha384); 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]; 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; } 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_3DES 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_3DES 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_SHA256 : case TLS_RSA_WITH_AES_256_CCM_8_SHA384 : if (requirement == REQUIRES_RSA) return 1; if (requirement == REQUIRES_RSA_SIG) return 1; break; case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SHA256 : case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8_SHA384 : if (requirement == REQUIRES_ECC_DSA) 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_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_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; 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; #endif 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_CBC_MD5 : if (requirement == REQUIRES_RSA) return 1; break; case TLS_RSA_WITH_HC_128_CBC_SHA : if (requirement == REQUIRES_RSA) return 1; break; case TLS_RSA_WITH_RABBIT_CBC_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 == SERVER_END && ssl->options.haveECDSAsig == 1) { CYASSL_MSG("Don't have RSA Signature"); return 0; } } /* ECCDHE is always supported if ECC on */ return 1; } 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 } } } 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; /* 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; 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; } RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_LEN); #ifndef NO_OLD_TLS if (ssl->options.tls) ret = DeriveTlsKeys(ssl); else ret = DeriveKeys(ssl); #else ret = DeriveTlsKeys(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 totalSz, 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 /* make sure can read up to session */ if (i + sizeof(pv) + RAN_LEN + ENUM_LEN > totalSz) return INCOMPLETE_DATA; XMEMCPY(&pv, input + i, sizeof(pv)); ssl->chVersion = pv; /* store */ i += (word32)sizeof(pv); 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) { if (i + ID_LEN > totalSz) return INCOMPLETE_DATA; XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN); i += b; ssl->options.resuming= 1; /* client wants to resume */ CYASSL_MSG("Client wants to resume session"); } #ifdef CYASSL_DTLS /* cookie */ if (ssl->options.dtls) { b = input[i++]; if (b) { byte cookie[MAX_COOKIE_LEN]; if (b > MAX_COOKIE_LEN) return BUFFER_ERROR; if (i + b > totalSz) return INCOMPLETE_DATA; if ((EmbedGenerateCookie(cookie, COOKIE_SZ, ssl) != COOKIE_SZ) || (b != COOKIE_SZ) || (XMEMCMP(cookie, input + i, b) != 0)) { return COOKIE_ERROR; } i += b; } } #endif if (i + LENGTH_SZ > totalSz) return INCOMPLETE_DATA; /* suites */ ato16(&input[i], &clSuites.suiteSz); i += 2; /* suites and comp len */ if (i + clSuites.suiteSz + ENUM_LEN > totalSz) return INCOMPLETE_DATA; if (clSuites.suiteSz > MAX_SUITE_SZ) return BUFFER_ERROR; XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); i += clSuites.suiteSz; clSuites.hashSigAlgoSz = 0; b = input[i++]; /* comp len */ if (i + b > totalSz) return INCOMPLETE_DATA; 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 */ ssl->options.clientState = CLIENT_HELLO_COMPLETE; *inOutIdx = i; if ( (i - begin) < helloSz) { if (IsAtLeastTLSv1_2(ssl)) { /* Process the hello extension. Skip unsupported. */ word16 totalExtSz; ato16(&input[i], &totalExtSz); i += LENGTH_SZ; if (totalExtSz > helloSz + begin - i) return INCOMPLETE_DATA; while (totalExtSz) { word16 extId, extSz; ato16(&input[i], &extId); i += LENGTH_SZ; ato16(&input[i], &extSz); i += EXT_ID_SZ; if (extSz > totalExtSz - LENGTH_SZ - EXT_ID_SZ) return INCOMPLETE_DATA; if (extId == HELLO_EXT_SIG_ALGO) { ato16(&input[i], &clSuites.hashSigAlgoSz); i += LENGTH_SZ; if (clSuites.hashSigAlgoSz > extSz - LENGTH_SZ) return INCOMPLETE_DATA; XMEMCPY(clSuites.hashSigAlgo, &input[i], min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX)); i += clSuites.hashSigAlgoSz; } else i += extSz; totalExtSz -= LENGTH_SZ + EXT_ID_SZ + extSz; } *inOutIdx = i; } else *inOutIdx = begin + helloSz; /* skip extensions */ } ssl->options.haveSessionId = 1; /* ProcessOld uses same resume code */ if (ssl->options.resuming) { /* let's try */ int ret; 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; } RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_LEN); #ifndef NO_OLD_TLS if (ssl->options.tls) ret = DeriveTlsKeys(ssl); else ret = DeriveKeys(ssl); #else ret = DeriveTlsKeys(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* inOutsz, word32 totalSz) { word16 sz = 0; word32 i = *inOutsz; int ret = VERIFY_CERT_ERROR; /* start in error state */ byte* sig; byte* out; int outLen; byte hashAlgo = sha_mac; byte sigAlgo = anonymous_sa_algo; (void)out; (void)outLen; #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("CertificateVerify", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("CertificateVerify", &ssl->timeoutInfo); #endif if ( (i + VERIFY_HEADER) > totalSz) return INCOMPLETE_DATA; if (IsAtLeastTLSv1_2(ssl)) { hashAlgo = input[i++]; sigAlgo = input[i++]; } ato16(&input[i], &sz); i += VERIFY_HEADER; if ( (i + sz) > totalSz) return INCOMPLETE_DATA; if (sz > ENCRYPT_LEN) return BUFFER_ERROR; sig = &input[i]; *inOutsz = i + sz; /* RSA */ #ifndef NO_RSA if (ssl->peerRsaKeyPresent != 0) { CYASSL_MSG("Doing RSA peer cert verify"); outLen = RsaSSL_VerifyInline(sig, 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 && XMEMCMP(out, encodedSig, min(sigSz, MAX_ENCODED_SIG_SZ)) == 0) ret = 0; /* verified */ } else { if (outLen == FINISHED_SZ && 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; 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 } } err = ecc_verify_hash(sig, sz, digest, digestSz, &verify, ssl->peerEccDsaKey); if (err == 0 && verify == 1) ret = 0; /* verified */ } #endif 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 avalaible size */ if ((ret = CheckAvalaibleSize(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 avalaible size */ if ((ret = CheckAvalaibleSize(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 ((ret = EmbedGenerateCookie(output + idx, cookieSz, ssl)) < 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 totalSz) { int ret = 0; word32 length = 0; byte* out = NULL; (void)length; /* shut up compiler warnings */ (void)out; (void)input; (void)inOutIdx; (void)totalSz; 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* tmp = 0; InitRsaKey(&key, ssl->heap); 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; ato16(input + *inOutIdx, &check); if ((word32)check != length) { CYASSL_MSG("RSA explicit size doesn't match"); FreeRsaKey(&key); return RSA_PRIVATE_ERROR; } (*inOutIdx) += 2; } tmp = input + *inOutIdx; *inOutIdx += length; if (*inOutIdx > totalSz) { CYASSL_MSG("RSA message too big"); FreeRsaKey(&key); return INCOMPLETE_DATA; } if (RsaPrivateDecryptInline(tmp, length, &out, &key) == 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; ato16(&input[*inOutIdx], &ci_sz); *inOutIdx += LENGTH_SZ; if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR; XMEMCPY(ssl->arrays->client_identity, &input[*inOutIdx], ci_sz); *inOutIdx += ci_sz; if (ci_sz < MAX_PSK_ID_LEN) ssl->arrays->client_identity[ci_sz] = 0; else ssl->arrays->client_identity[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 += 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; ret = MakeMasterSecret(ssl); } break; #endif /* NO_PSK */ #ifdef HAVE_NTRU case ntru_kea: { word32 rc; word16 cipherLen; word16 plainLen = sizeof(ssl->arrays->preMasterSecret); byte* tmp; if (!ssl->buffers.key.buffer) return NO_PRIVATE_KEY; ato16(&input[*inOutIdx], &cipherLen); *inOutIdx += LENGTH_SZ; if (cipherLen > MAX_NTRU_ENCRYPT_SZ) return NTRU_KEY_ERROR; tmp = input + *inOutIdx; rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length, ssl->buffers.key.buffer, cipherLen, tmp, &plainLen, ssl->arrays->preMasterSecret); if (rc != NTRU_OK || 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: { word32 size; word32 bLength = input[*inOutIdx]; /* one byte length */ *inOutIdx += 1; ret = ecc_import_x963(&input[*inOutIdx], bLength, ssl->peerEccKey); if (ret != 0) return ECC_PEERKEY_ERROR; *inOutIdx += bLength; ssl->peerEccKeyPresent = 1; size = 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, &size); ecc_free(&staticKey); } else ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey, ssl->arrays->preMasterSecret, &size); if (ret != 0) return ECC_SHARED_ERROR; ssl->arrays->preMasterSz = size; ret = MakeMasterSecret(ssl); } break; #endif /* HAVE_ECC */ #ifdef OPENSSL_EXTRA case diffie_hellman_kea: { byte* clientPub; word16 clientPubSz; DhKey dhKey; ato16(&input[*inOutIdx], &clientPubSz); *inOutIdx += LENGTH_SZ; clientPub = &input[*inOutIdx]; *inOutIdx += clientPubSz; 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, clientPub, clientPubSz); FreeDhKey(&dhKey); if (ret == 0) ret = MakeMasterSecret(ssl); } break; #endif /* OPENSSL_EXTRA */ default: { CYASSL_MSG("Bad kea type"); ret = BAD_KEA_TYPE_E; } break; } 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 */ #ifdef SINGLE_THREADED int InitMutex(CyaSSL_Mutex* m) { (void)m; return 0; } int FreeMutex(CyaSSL_Mutex *m) { (void)m; return 0; } int LockMutex(CyaSSL_Mutex *m) { (void)m; return 0; } int UnLockMutex(CyaSSL_Mutex *m) { (void)m; return 0; } #else /* MULTI_THREAD */ #if defined(FREERTOS) int InitMutex(CyaSSL_Mutex* m) { int iReturn; *m = ( CyaSSL_Mutex ) xSemaphoreCreateMutex(); if( *m != NULL ) iReturn = 0; else iReturn = BAD_MUTEX_ERROR; return iReturn; } int FreeMutex(CyaSSL_Mutex* m) { vSemaphoreDelete( *m ); return 0; } int LockMutex(CyaSSL_Mutex* m) { /* Assume an infinite block, or should there be zero block? */ xSemaphoreTake( *m, portMAX_DELAY ); return 0; } int UnLockMutex(CyaSSL_Mutex* m) { xSemaphoreGive( *m ); return 0; } #elif defined(CYASSL_SAFERTOS) int InitMutex(CyaSSL_Mutex* m) { vSemaphoreCreateBinary(m->mutexBuffer, m->mutex); if (m->mutex == NULL) return BAD_MUTEX_ERROR; return 0; } int FreeMutex(CyaSSL_Mutex* m) { (void)m; return 0; } int LockMutex(CyaSSL_Mutex* m) { /* Assume an infinite block */ xSemaphoreTake(m->mutex, portMAX_DELAY); return 0; } int UnLockMutex(CyaSSL_Mutex* m) { xSemaphoreGive(m->mutex); return 0; } #elif defined(USE_WINDOWS_API) int InitMutex(CyaSSL_Mutex* m) { InitializeCriticalSection(m); return 0; } int FreeMutex(CyaSSL_Mutex* m) { DeleteCriticalSection(m); return 0; } int LockMutex(CyaSSL_Mutex* m) { EnterCriticalSection(m); return 0; } int UnLockMutex(CyaSSL_Mutex* m) { LeaveCriticalSection(m); return 0; } #elif defined(CYASSL_PTHREADS) int InitMutex(CyaSSL_Mutex* m) { if (pthread_mutex_init(m, 0) == 0) return 0; else return BAD_MUTEX_ERROR; } int FreeMutex(CyaSSL_Mutex* m) { if (pthread_mutex_destroy(m) == 0) return 0; else return BAD_MUTEX_ERROR; } int LockMutex(CyaSSL_Mutex* m) { if (pthread_mutex_lock(m) == 0) return 0; else return BAD_MUTEX_ERROR; } int UnLockMutex(CyaSSL_Mutex* m) { if (pthread_mutex_unlock(m) == 0) return 0; else return BAD_MUTEX_ERROR; } #elif defined(THREADX) int InitMutex(CyaSSL_Mutex* m) { if (tx_mutex_create(m, "CyaSSL Mutex", TX_NO_INHERIT) == 0) return 0; else return BAD_MUTEX_ERROR; } int FreeMutex(CyaSSL_Mutex* m) { if (tx_mutex_delete(m) == 0) return 0; else return BAD_MUTEX_ERROR; } int LockMutex(CyaSSL_Mutex* m) { if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0) return 0; else return BAD_MUTEX_ERROR; } int UnLockMutex(CyaSSL_Mutex* m) { if (tx_mutex_put(m) == 0) return 0; else return BAD_MUTEX_ERROR; } #elif defined(MICRIUM) int InitMutex(CyaSSL_Mutex* m) { #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) if (NetSecure_OS_MutexCreate(m) == 0) return 0; else return BAD_MUTEX_ERROR; #else return 0; #endif } int FreeMutex(CyaSSL_Mutex* m) { #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) if (NetSecure_OS_FreeMutex(m) == 0) return 0; else return BAD_MUTEX_ERROR; #else return 0; #endif } int LockMutex(CyaSSL_Mutex* m) { #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) if (NetSecure_OS_LockMutex(m) == 0) return 0; else return BAD_MUTEX_ERROR; #else return 0; #endif } int UnLockMutex(CyaSSL_Mutex* m) { #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) if (NetSecure_OS_UnLockMutex(m) == 0) return 0; else return BAD_MUTEX_ERROR; #else return 0; #endif } #elif defined(EBSNET) int InitMutex(CyaSSL_Mutex* m) { if (rtp_sig_mutex_alloc(m, "CyaSSL Mutex") == -1) return BAD_MUTEX_ERROR; else return 0; } int FreeMutex(CyaSSL_Mutex* m) { rtp_sig_mutex_free(*m); return 0; } int LockMutex(CyaSSL_Mutex* m) { if (rtp_sig_mutex_claim_timed(*m, RTIP_INF) == 0) return 0; else return BAD_MUTEX_ERROR; } int UnLockMutex(CyaSSL_Mutex* m) { rtp_sig_mutex_release(*m); return 0; } #elif defined(FREESCALE_MQX) int InitMutex(CyaSSL_Mutex* m) { if (_mutex_init(m, NULL) == MQX_EOK) return 0; else return BAD_MUTEX_ERROR; } int FreeMutex(CyaSSL_Mutex* m) { if (_mutex_destroy(m) == MQX_EOK) return 0; else return BAD_MUTEX_ERROR; } int LockMutex(CyaSSL_Mutex* m) { if (_mutex_lock(m) == MQX_EOK) return 0; else return BAD_MUTEX_ERROR; } int UnLockMutex(CyaSSL_Mutex* m) { if (_mutex_unlock(m) == MQX_EOK) return 0; else return BAD_MUTEX_ERROR; } #endif /* USE_WINDOWS_API */ #endif /* SINGLE_THREADED */