CyaSSL changed for NucleoF401RE board: implemented random and time functions for build. (Has trouble with wildcard domains like *.google.com, *.yahoo.com)
Fork of CyaSSL by
Revision 4:e505054279ed, committed 2015-01-14
- Comitter:
- Vanger
- Date:
- Wed Jan 14 22:07:14 2015 +0000
- Parent:
- 3:64d4f7cb83d5
- Commit message:
- Implemented some platform specific functions in the Cyassl library code: time functions, seed random functions, and also changed the settings.h file to define settings specific to the platform being used
Changed in this revision
diff -r 64d4f7cb83d5 -r e505054279ed ctaocrypt/src/asn.c --- a/ctaocrypt/src/asn.c Wed Dec 03 05:24:18 2014 +0000 +++ b/ctaocrypt/src/asn.c Wed Jan 14 22:07:14 2015 +0000 @@ -1,6982 +1,6984 @@ -/* asn.c - * - * Copyright (C) 2006-2014 wolfSSL Inc. - * - * This file is part of CyaSSL. - * - * CyaSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * CyaSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <cyassl/ctaocrypt/settings.h> - -#ifndef NO_ASN - -#ifdef HAVE_RTP_SYS - #include "os.h" /* dc_rtc_api needs */ - #include "dc_rtc_api.h" /* to get current time */ -#endif - -#include <cyassl/ctaocrypt/integer.h> -#include <cyassl/ctaocrypt/asn.h> -#include <cyassl/ctaocrypt/coding.h> -#include <cyassl/ctaocrypt/sha.h> -#include <cyassl/ctaocrypt/md5.h> -#include <cyassl/ctaocrypt/md2.h> -#include <cyassl/ctaocrypt/error-crypt.h> -#include <cyassl/ctaocrypt/pwdbased.h> -#include <cyassl/ctaocrypt/des3.h> -#include <cyassl/ctaocrypt/sha256.h> -#include <cyassl/ctaocrypt/sha512.h> -#include <cyassl/ctaocrypt/logging.h> - -#include <cyassl/ctaocrypt/random.h> - - -#ifndef NO_RC4 - #include <cyassl/ctaocrypt/arc4.h> -#endif - -#ifdef HAVE_NTRU - #include "crypto_ntru.h" -#endif - -#ifdef HAVE_ECC - #include <cyassl/ctaocrypt/ecc.h> -#endif - -#ifdef CYASSL_DEBUG_ENCODING - #ifdef FREESCALE_MQX - #include <fio.h> - #else - #include <stdio.h> - #endif -#endif - -#ifdef _MSC_VER - /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */ - #pragma warning(disable: 4996) -#endif - - -#ifndef TRUE - #define TRUE 1 -#endif -#ifndef FALSE - #define FALSE 0 -#endif - - -#ifdef HAVE_RTP_SYS - /* uses parital <time.h> structures */ - #define XTIME(tl) (0) - #define XGMTIME(c) my_gmtime((c)) - #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) -#elif defined(MICRIUM) - #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) - #define XVALIDATE_DATE(d,f,t) NetSecure_ValidateDateHandler((d),(f),(t)) - #else - #define XVALIDATE_DATE(d, f, t) (0) - #endif - #define NO_TIME_H - /* since Micrium not defining XTIME or XGMTIME, CERT_GEN not available */ -#elif defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP) - #include <time.h> - #define XTIME(t1) pic32_time((t1)) - #define XGMTIME(c) gmtime((c)) - #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) -#elif defined(FREESCALE_MQX) - #include <time.h> - #define XTIME(t1) mqx_time((t1)) - #define XGMTIME(c) gmtime((c)) - #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) -#elif defined(CYASSL_MDK_ARM) - #if defined(CYASSL_MDK5) - #include "cmsis_os.h" - #else - #include <rtl.h> - #endif - #undef RNG - #include "cyassl_MDK_ARM.h" - #undef RNG - #define RNG CyaSSL_RNG /*for avoiding name conflict in "stm32f2xx.h" */ - #define XTIME(tl) (0) - #define XGMTIME(c) Cyassl_MDK_gmtime((c)) - #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) -#elif defined(USER_TIME) - /* user time, and gmtime compatible functions, there is a gmtime - implementation here that WINCE uses, so really just need some ticks - since the EPOCH - */ - - struct tm { - int tm_sec; /* seconds after the minute [0-60] */ - int tm_min; /* minutes after the hour [0-59] */ - int tm_hour; /* hours since midnight [0-23] */ - int tm_mday; /* day of the month [1-31] */ - int tm_mon; /* months since January [0-11] */ - int tm_year; /* years since 1900 */ - int tm_wday; /* days since Sunday [0-6] */ - int tm_yday; /* days since January 1 [0-365] */ - int tm_isdst; /* Daylight Savings Time flag */ - long tm_gmtoff; /* offset from CUT in seconds */ - char *tm_zone; /* timezone abbreviation */ - }; - typedef long time_t; - - /* forward declaration */ - struct tm* gmtime(const time_t* timer); - extern time_t XTIME(time_t * timer); - - #define XGMTIME(c) gmtime((c)) - #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) - - #ifdef STACK_TRAP - /* for stack trap tracking, don't call os gmtime on OS X/linux, - uses a lot of stack spce */ - extern time_t time(time_t * timer); - #define XTIME(tl) time((tl)) - #endif /* STACK_TRAP */ - -#else - /* default */ - /* uses complete <time.h> facility */ - #include <time.h> - #define XTIME(tl) time((tl)) - #define XGMTIME(c) gmtime((c)) - #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) -#endif - - -#ifdef _WIN32_WCE -/* no time() or gmtime() even though in time.h header?? */ - -#include <windows.h> - - -time_t time(time_t* timer) -{ - SYSTEMTIME sysTime; - FILETIME fTime; - ULARGE_INTEGER intTime; - time_t localTime; - - if (timer == NULL) - timer = &localTime; - - GetSystemTime(&sysTime); - SystemTimeToFileTime(&sysTime, &fTime); - - XMEMCPY(&intTime, &fTime, sizeof(FILETIME)); - /* subtract EPOCH */ - intTime.QuadPart -= 0x19db1ded53e8000; - /* to secs */ - intTime.QuadPart /= 10000000; - *timer = (time_t)intTime.QuadPart; - - return *timer; -} - -#endif /* _WIN32_WCE */ -#if defined( _WIN32_WCE ) || defined( USER_TIME ) - -struct tm* gmtime(const time_t* timer) -{ - #define YEAR0 1900 - #define EPOCH_YEAR 1970 - #define SECS_DAY (24L * 60L * 60L) - #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400))) - #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) - - static const int _ytab[2][12] = - { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} - }; - - static struct tm st_time; - struct tm* ret = &st_time; - time_t secs = *timer; - unsigned long dayclock, dayno; - int year = EPOCH_YEAR; - - dayclock = (unsigned long)secs % SECS_DAY; - dayno = (unsigned long)secs / SECS_DAY; - - ret->tm_sec = (int) dayclock % 60; - ret->tm_min = (int)(dayclock % 3600) / 60; - ret->tm_hour = (int) dayclock / 3600; - ret->tm_wday = (int) (dayno + 4) % 7; /* day 0 a Thursday */ - - while(dayno >= (unsigned long)YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - - ret->tm_year = year - YEAR0; - ret->tm_yday = (int)dayno; - ret->tm_mon = 0; - - while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) { - dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon]; - ret->tm_mon++; - } - - ret->tm_mday = (int)++dayno; - ret->tm_isdst = 0; - - return ret; -} - -#endif /* _WIN32_WCE || USER_TIME */ - - -#ifdef HAVE_RTP_SYS - -#define YEAR0 1900 - -struct tm* my_gmtime(const time_t* timer) /* has a gmtime() but hangs */ -{ - static struct tm st_time; - struct tm* ret = &st_time; - - DC_RTC_CALENDAR cal; - dc_rtc_time_get(&cal, TRUE); - - ret->tm_year = cal.year - YEAR0; /* gm starts at 1900 */ - ret->tm_mon = cal.month - 1; /* gm starts at 0 */ - ret->tm_mday = cal.day; - ret->tm_hour = cal.hour; - ret->tm_min = cal.minute; - ret->tm_sec = cal.second; - - return ret; -} - -#endif /* HAVE_RTP_SYS */ - - -#if defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP) - -/* - * time() is just a stub in Microchip libraries. We need our own - * implementation. Use SNTP client to get seconds since epoch. - */ -time_t pic32_time(time_t* timer) -{ -#ifdef MICROCHIP_TCPIP_V5 - DWORD sec = 0; -#else - uint32_t sec = 0; -#endif - time_t localTime; - - if (timer == NULL) - timer = &localTime; - -#ifdef MICROCHIP_MPLAB_HARMONY - sec = TCPIP_SNTP_UTCSecondsGet(); -#else - sec = SNTPGetUTCSeconds(); -#endif - *timer = (time_t) sec; - - return *timer; -} - -#endif /* MICROCHIP_TCPIP */ - - -#ifdef FREESCALE_MQX - -time_t mqx_time(time_t* timer) -{ - time_t localTime; - TIME_STRUCT time_s; - - if (timer == NULL) - timer = &localTime; - - _time_get(&time_s); - *timer = (time_t) time_s.SECONDS; - - return *timer; -} - -#endif /* FREESCALE_MQX */ - - -static INLINE word32 btoi(byte b) -{ - return b - 0x30; -} - - -/* two byte date/time, add to value */ -static INLINE void GetTime(int* value, const byte* date, int* idx) -{ - int i = *idx; - - *value += btoi(date[i++]) * 10; - *value += btoi(date[i++]); - - *idx = i; -} - - -#if defined(MICRIUM) - -CPU_INT32S NetSecure_ValidateDateHandler(CPU_INT08U *date, CPU_INT08U format, - CPU_INT08U dateType) -{ - CPU_BOOLEAN rtn_code; - CPU_INT32S i; - CPU_INT32S val; - CPU_INT16U year; - CPU_INT08U month; - CPU_INT16U day; - CPU_INT08U hour; - CPU_INT08U min; - CPU_INT08U sec; - - i = 0; - year = 0u; - - if (format == ASN_UTC_TIME) { - if (btoi(date[0]) >= 5) - year = 1900; - else - year = 2000; - } - else { /* format == GENERALIZED_TIME */ - year += btoi(date[i++]) * 1000; - year += btoi(date[i++]) * 100; - } - - val = year; - GetTime(&val, date, &i); - year = (CPU_INT16U)val; - - val = 0; - GetTime(&val, date, &i); - month = (CPU_INT08U)val; - - val = 0; - GetTime(&val, date, &i); - day = (CPU_INT16U)val; - - val = 0; - GetTime(&val, date, &i); - hour = (CPU_INT08U)val; - - val = 0; - GetTime(&val, date, &i); - min = (CPU_INT08U)val; - - val = 0; - GetTime(&val, date, &i); - sec = (CPU_INT08U)val; - - return NetSecure_ValidateDate(year, month, day, hour, min, sec, dateType); -} - -#endif /* MICRIUM */ - - -CYASSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, - word32 maxIdx) -{ - int length = 0; - word32 i = *inOutIdx; - byte b; - - if ( (i+1) > maxIdx) { /* for first read */ - CYASSL_MSG("GetLength bad index on input"); - return BUFFER_E; - } - - b = input[i++]; - if (b >= ASN_LONG_LENGTH) { - word32 bytes = b & 0x7F; - - if ( (i+bytes) > maxIdx) { /* for reading bytes */ - CYASSL_MSG("GetLength bad long length"); - return BUFFER_E; - } - - while (bytes--) { - b = input[i++]; - length = (length << 8) | b; - } - } - else - length = b; - - if ( (i+length) > maxIdx) { /* for user of length */ - CYASSL_MSG("GetLength value exceeds buffer length"); - return BUFFER_E; - } - - *inOutIdx = i; - *len = length; - - return length; -} - - -CYASSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, - word32 maxIdx) -{ - int length = -1; - word32 idx = *inOutIdx; - - if (input[idx++] != (ASN_SEQUENCE | ASN_CONSTRUCTED) || - GetLength(input, &idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - *len = length; - *inOutIdx = idx; - - return length; -} - - -CYASSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len, - word32 maxIdx) -{ - int length = -1; - word32 idx = *inOutIdx; - - if (input[idx++] != (ASN_SET | ASN_CONSTRUCTED) || - GetLength(input, &idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - *len = length; - *inOutIdx = idx; - - return length; -} - - -/* winodws header clash for WinCE using GetVersion */ -CYASSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx, int* version) -{ - word32 idx = *inOutIdx; - - CYASSL_ENTER("GetMyVersion"); - - if (input[idx++] != ASN_INTEGER) - return ASN_PARSE_E; - - if (input[idx++] != 0x01) - return ASN_VERSION_E; - - *version = input[idx++]; - *inOutIdx = idx; - - return *version; -} - - -#ifndef NO_PWDBASED -/* Get small count integer, 32 bits or less */ -static int GetShortInt(const byte* input, word32* inOutIdx, int* number) -{ - word32 idx = *inOutIdx; - word32 len; - - *number = 0; - - if (input[idx++] != ASN_INTEGER) - return ASN_PARSE_E; - - len = input[idx++]; - if (len > 4) - return ASN_PARSE_E; - - while (len--) { - *number = *number << 8 | input[idx++]; - } - - *inOutIdx = idx; - - return *number; -} -#endif /* !NO_PWDBASED */ - - -/* May not have one, not an error */ -static int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version) -{ - word32 idx = *inOutIdx; - - CYASSL_ENTER("GetExplicitVersion"); - if (input[idx++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { - *inOutIdx = ++idx; /* eat header */ - return GetMyVersion(input, inOutIdx, version); - } - - /* go back as is */ - *version = 0; - - return 0; -} - - -CYASSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, - word32 maxIdx) -{ - word32 i = *inOutIdx; - byte b = input[i++]; - int length; - - if (b != ASN_INTEGER) - return ASN_PARSE_E; - - if (GetLength(input, &i, &length, maxIdx) < 0) - return ASN_PARSE_E; - - if ( (b = input[i++]) == 0x00) - length--; - else - i--; - - if (mp_init(mpi) != MP_OKAY) - return MP_INIT_E; - - if (mp_read_unsigned_bin(mpi, (byte*)input + i, length) != 0) { - mp_clear(mpi); - return ASN_GETINT_E; - } - - *inOutIdx = i + length; - return 0; -} - - -static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, - word32 maxIdx) -{ - int length; - word32 i = *inOutIdx; - byte b; - *oid = 0; - - b = input[i++]; - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(input, &i, &length, maxIdx) < 0) - return ASN_PARSE_E; - - while(length--) - *oid += input[i++]; - /* just sum it up for now */ - - *inOutIdx = i; - - return 0; -} - - -CYASSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, - word32 maxIdx) -{ - int length; - word32 i = *inOutIdx; - byte b; - *oid = 0; - - CYASSL_ENTER("GetAlgoId"); - - if (GetSequence(input, &i, &length, maxIdx) < 0) - return ASN_PARSE_E; - - b = input[i++]; - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(input, &i, &length, maxIdx) < 0) - return ASN_PARSE_E; - - while(length--) { - /* odd HC08 compiler behavior here when input[i++] */ - *oid += input[i]; - i++; - } - /* just sum it up for now */ - - /* could have NULL tag and 0 terminator, but may not */ - b = input[i++]; - - if (b == ASN_TAG_NULL) { - b = input[i++]; - if (b != 0) - return ASN_EXPECT_0_E; - } - else - /* go back, didn't have it */ - i--; - - *inOutIdx = i; - - return 0; -} - -#ifndef NO_RSA - - -#ifdef HAVE_CAVIUM - -static int GetCaviumInt(byte** buff, word16* buffSz, const byte* input, - word32* inOutIdx, word32 maxIdx, void* heap) -{ - word32 i = *inOutIdx; - byte b = input[i++]; - int length; - - if (b != ASN_INTEGER) - return ASN_PARSE_E; - - if (GetLength(input, &i, &length, maxIdx) < 0) - return ASN_PARSE_E; - - if ( (b = input[i++]) == 0x00) - length--; - else - i--; - - *buffSz = (word16)length; - *buff = XMALLOC(*buffSz, heap, DYNAMIC_TYPE_CAVIUM_RSA); - if (*buff == NULL) - return MEMORY_E; - - XMEMCPY(*buff, input + i, *buffSz); - - *inOutIdx = i + length; - return 0; -} - -static int CaviumRsaPrivateKeyDecode(const byte* input, word32* inOutIdx, - RsaKey* key, word32 inSz) -{ - int version, length; - void* h = key->heap; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(input, inOutIdx, &version) < 0) - return ASN_PARSE_E; - - key->type = RSA_PRIVATE; - - if (GetCaviumInt(&key->c_n, &key->c_nSz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_e, &key->c_eSz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_d, &key->c_dSz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_p, &key->c_pSz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_q, &key->c_qSz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_dP, &key->c_dP_Sz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_dQ, &key->c_dQ_Sz, input, inOutIdx, inSz, h) < 0 || - GetCaviumInt(&key->c_u, &key->c_uSz, input, inOutIdx, inSz, h) < 0 ) - return ASN_RSA_KEY_E; - - return 0; -} - - -#endif /* HAVE_CAVIUM */ - -int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, - word32 inSz) -{ - int version, length; - -#ifdef HAVE_CAVIUM - if (key->magic == CYASSL_RSA_CAVIUM_MAGIC) - return CaviumRsaPrivateKeyDecode(input, inOutIdx, key, inSz); -#endif - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(input, inOutIdx, &version) < 0) - return ASN_PARSE_E; - - key->type = RSA_PRIVATE; - - if (GetInt(&key->n, input, inOutIdx, inSz) < 0 || - GetInt(&key->e, input, inOutIdx, inSz) < 0 || - GetInt(&key->d, input, inOutIdx, inSz) < 0 || - GetInt(&key->p, input, inOutIdx, inSz) < 0 || - GetInt(&key->q, input, inOutIdx, inSz) < 0 || - GetInt(&key->dP, input, inOutIdx, inSz) < 0 || - GetInt(&key->dQ, input, inOutIdx, inSz) < 0 || - GetInt(&key->u, input, inOutIdx, inSz) < 0 ) return ASN_RSA_KEY_E; - - return 0; -} - -#endif /* NO_RSA */ - -/* Remove PKCS8 header, move beginning of traditional to beginning of input */ -int ToTraditional(byte* input, word32 sz) -{ - word32 inOutIdx = 0, oid; - int version, length; - - if (GetSequence(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(input, &inOutIdx, &version) < 0) - return ASN_PARSE_E; - - if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) - return ASN_PARSE_E; - - if (input[inOutIdx] == ASN_OBJECT_ID) { - /* pkcs8 ecc uses slightly different format */ - inOutIdx++; /* past id */ - if (GetLength(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - inOutIdx += length; /* over sub id, key input will verify */ - } - - if (input[inOutIdx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - XMEMMOVE(input, input + inOutIdx, length); - - return length; -} - - -#ifndef NO_PWDBASED - -/* Check To see if PKCS version algo is supported, set id if it is return 0 - < 0 on error */ -static int CheckAlgo(int first, int second, int* id, int* version) -{ - *id = ALGO_ID_E; - *version = PKCS5; /* default */ - - if (first == 1) { - switch (second) { - case 1: - *id = PBE_SHA1_RC4_128; - *version = PKCS12; - return 0; - case 3: - *id = PBE_SHA1_DES3; - *version = PKCS12; - return 0; - default: - return ALGO_ID_E; - } - } - - if (first != PKCS5) - return ASN_INPUT_E; /* VERSION ERROR */ - - if (second == PBES2) { - *version = PKCS5v2; - return 0; - } - - switch (second) { - case 3: /* see RFC 2898 for ids */ - *id = PBE_MD5_DES; - return 0; - case 10: - *id = PBE_SHA1_DES; - return 0; - default: - return ALGO_ID_E; - - } -} - - -/* Check To see if PKCS v2 algo is supported, set id if it is return 0 - < 0 on error */ -static int CheckAlgoV2(int oid, int* id) -{ - switch (oid) { - case 69: - *id = PBE_SHA1_DES; - return 0; - case 652: - *id = PBE_SHA1_DES3; - return 0; - default: - return ALGO_ID_E; - - } -} - - -/* Decrypt intput in place from parameters based on id */ -static int DecryptKey(const char* password, int passwordSz, byte* salt, - int saltSz, int iterations, int id, byte* input, - int length, int version, byte* cbcIv) -{ - byte key[MAX_KEY_SIZE]; - int typeH; - int derivedLen; - int decryptionType; - int ret = 0; - - switch (id) { - case PBE_MD5_DES: - typeH = MD5; - derivedLen = 16; /* may need iv for v1.5 */ - decryptionType = DES_TYPE; - break; - - case PBE_SHA1_DES: - typeH = SHA; - derivedLen = 16; /* may need iv for v1.5 */ - decryptionType = DES_TYPE; - break; - - case PBE_SHA1_DES3: - typeH = SHA; - derivedLen = 32; /* may need iv for v1.5 */ - decryptionType = DES3_TYPE; - break; - - case PBE_SHA1_RC4_128: - typeH = SHA; - derivedLen = 16; - decryptionType = RC4_TYPE; - break; - - default: - return ALGO_ID_E; - } - - if (version == PKCS5v2) - ret = PBKDF2(key, (byte*)password, passwordSz, salt, saltSz, iterations, - derivedLen, typeH); - else if (version == PKCS5) - ret = PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations, - derivedLen, typeH); - else if (version == PKCS12) { - int i, idx = 0; - byte unicodePasswd[MAX_UNICODE_SZ]; - - if ( (passwordSz * 2 + 2) > (int)sizeof(unicodePasswd)) - return UNICODE_SIZE_E; - - for (i = 0; i < passwordSz; i++) { - unicodePasswd[idx++] = 0x00; - unicodePasswd[idx++] = (byte)password[i]; - } - /* add trailing NULL */ - unicodePasswd[idx++] = 0x00; - unicodePasswd[idx++] = 0x00; - - ret = PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz, - iterations, derivedLen, typeH, 1); - if (decryptionType != RC4_TYPE) - ret += PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz, - iterations, 8, typeH, 2); - } - else - return ALGO_ID_E; - - if (ret != 0) - return ret; - - switch (decryptionType) { -#ifndef NO_DES3 - case DES_TYPE: - { - Des dec; - byte* desIv = key + 8; - - if (version == PKCS5v2 || version == PKCS12) - desIv = cbcIv; - - ret = Des_SetKey(&dec, key, desIv, DES_DECRYPTION); - if (ret != 0) - return ret; - - Des_CbcDecrypt(&dec, input, input, length); - break; - } - - case DES3_TYPE: - { - Des3 dec; - byte* desIv = key + 24; - - if (version == PKCS5v2 || version == PKCS12) - desIv = cbcIv; - ret = Des3_SetKey(&dec, key, desIv, DES_DECRYPTION); - if (ret != 0) - return ret; - ret = Des3_CbcDecrypt(&dec, input, input, length); - if (ret != 0) - return ret; - break; - } -#endif -#ifndef NO_RC4 - case RC4_TYPE: - { - Arc4 dec; - - Arc4SetKey(&dec, key, derivedLen); - Arc4Process(&dec, input, input, length); - break; - } -#endif - - default: - return ALGO_ID_E; - } - - return 0; -} - - -/* Remove Encrypted PKCS8 header, move beginning of traditional to beginning - of input */ -int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) -{ - word32 inOutIdx = 0, oid; - int first, second, length, version, saltSz, id; - int iterations = 0; - byte salt[MAX_SALT_SIZE]; - byte cbcIv[MAX_IV_SIZE]; - - if (GetSequence(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) - return ASN_PARSE_E; - - first = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */ - second = input[inOutIdx - 1]; /* version.algo, algo id last byte */ - - if (CheckAlgo(first, second, &id, &version) < 0) - return ASN_INPUT_E; /* Algo ID error */ - - if (version == PKCS5v2) { - - if (GetSequence(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) - return ASN_PARSE_E; - - if (oid != PBKDF2_OID) - return ASN_PARSE_E; - } - - if (GetSequence(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - if (input[inOutIdx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(input, &inOutIdx, &saltSz, sz) < 0) - return ASN_PARSE_E; - - if (saltSz > MAX_SALT_SIZE) - return ASN_PARSE_E; - - XMEMCPY(salt, &input[inOutIdx], saltSz); - inOutIdx += saltSz; - - if (GetShortInt(input, &inOutIdx, &iterations) < 0) - return ASN_PARSE_E; - - if (version == PKCS5v2) { - /* get encryption algo */ - if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) - return ASN_PARSE_E; - - if (CheckAlgoV2(oid, &id) < 0) - return ASN_PARSE_E; /* PKCS v2 algo id error */ - - if (input[inOutIdx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - XMEMCPY(cbcIv, &input[inOutIdx], length); - inOutIdx += length; - } - - if (input[inOutIdx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - - if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id, - input + inOutIdx, length, version, cbcIv) < 0) - return ASN_INPUT_E; /* decrypt failure */ - - XMEMMOVE(input, input + inOutIdx, length); - return ToTraditional(input, length); -} - -#endif /* NO_PWDBASED */ - -#ifndef NO_RSA - -int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, - word32 inSz) -{ - int length; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - key->type = RSA_PUBLIC; - -#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA) - { - byte b = input[*inOutIdx]; - if (b != ASN_INTEGER) { - /* not from decoded cert, will have algo id, skip past */ - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - b = input[(*inOutIdx)++]; - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - *inOutIdx += length; /* skip past */ - - /* could have NULL tag and 0 terminator, but may not */ - b = input[(*inOutIdx)++]; - - if (b == ASN_TAG_NULL) { - b = input[(*inOutIdx)++]; - if (b != 0) - return ASN_EXPECT_0_E; - } - else - /* go back, didn't have it */ - (*inOutIdx)--; - - /* should have bit tag length and seq next */ - b = input[(*inOutIdx)++]; - if (b != ASN_BIT_STRING) - return ASN_BITSTR_E; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - /* could have 0 */ - b = input[(*inOutIdx)++]; - if (b != 0) - (*inOutIdx)--; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - } /* end if */ - } /* openssl var block */ -#endif /* OPENSSL_EXTRA */ - - if (GetInt(&key->n, input, inOutIdx, inSz) < 0 || - GetInt(&key->e, input, inOutIdx, inSz) < 0 ) return ASN_RSA_KEY_E; - - return 0; -} - -#endif - -#ifndef NO_DH - -int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) -{ - int length; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || - GetInt(&key->g, input, inOutIdx, inSz) < 0 ) return ASN_DH_KEY_E; - - return 0; -} - -int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz) -{ - if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) - return BAD_FUNC_ARG; - - /* may have leading 0 */ - if (p[0] == 0) { - pSz--; p++; - } - - if (g[0] == 0) { - gSz--; g++; - } - - if (mp_init(&key->p) != MP_OKAY) - return MP_INIT_E; - if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) { - mp_clear(&key->p); - return ASN_DH_KEY_E; - } - - if (mp_init(&key->g) != MP_OKAY) { - mp_clear(&key->p); - return MP_INIT_E; - } - if (mp_read_unsigned_bin(&key->g, g, gSz) != 0) { - mp_clear(&key->g); - mp_clear(&key->p); - return ASN_DH_KEY_E; - } - - return 0; -} - - -#ifdef OPENSSL_EXTRA - -int DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz, - byte* g, word32* gInOutSz) -{ - word32 i = 0; - byte b; - int length; - - if (GetSequence(input, &i, &length, inSz) < 0) - return ASN_PARSE_E; - - b = input[i++]; - if (b != ASN_INTEGER) - return ASN_PARSE_E; - - if (GetLength(input, &i, &length, inSz) < 0) - return ASN_PARSE_E; - - if ( (b = input[i++]) == 0x00) - length--; - else - i--; - - if (length <= (int)*pInOutSz) { - XMEMCPY(p, &input[i], length); - *pInOutSz = length; - } - else - return BUFFER_E; - - i += length; - - b = input[i++]; - if (b != ASN_INTEGER) - return ASN_PARSE_E; - - if (GetLength(input, &i, &length, inSz) < 0) - return ASN_PARSE_E; - - if (length <= (int)*gInOutSz) { - XMEMCPY(g, &input[i], length); - *gInOutSz = length; - } - else - return BUFFER_E; - - return 0; -} - -#endif /* OPENSSL_EXTRA */ -#endif /* NO_DH */ - - -#ifndef NO_DSA - -int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key, - word32 inSz) -{ - int length; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || - GetInt(&key->q, input, inOutIdx, inSz) < 0 || - GetInt(&key->g, input, inOutIdx, inSz) < 0 || - GetInt(&key->y, input, inOutIdx, inSz) < 0 ) return ASN_DH_KEY_E; - - key->type = DSA_PUBLIC; - return 0; -} - - -int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key, - word32 inSz) -{ - int length, version; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(input, inOutIdx, &version) < 0) - return ASN_PARSE_E; - - if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || - GetInt(&key->q, input, inOutIdx, inSz) < 0 || - GetInt(&key->g, input, inOutIdx, inSz) < 0 || - GetInt(&key->y, input, inOutIdx, inSz) < 0 || - GetInt(&key->x, input, inOutIdx, inSz) < 0 ) return ASN_DH_KEY_E; - - key->type = DSA_PRIVATE; - return 0; -} - -#endif /* NO_DSA */ - - -void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) -{ - cert->publicKey = 0; - cert->pubKeySize = 0; - cert->pubKeyStored = 0; - cert->version = 0; - cert->signature = 0; - cert->subjectCN = 0; - cert->subjectCNLen = 0; - cert->subjectCNStored = 0; - cert->altNames = NULL; -#ifndef IGNORE_NAME_CONSTRAINTS - cert->altEmailNames = NULL; - cert->permittedNames = NULL; - cert->excludedNames = NULL; -#endif /* IGNORE_NAME_CONSTRAINTS */ - cert->issuer[0] = '\0'; - cert->subject[0] = '\0'; - cert->source = source; /* don't own */ - cert->srcIdx = 0; - cert->maxIdx = inSz; /* can't go over this index */ - cert->heap = heap; - XMEMSET(cert->serial, 0, EXTERNAL_SERIAL_SIZE); - cert->serialSz = 0; - cert->extensions = 0; - cert->extensionsSz = 0; - cert->extensionsIdx = 0; - cert->extAuthInfo = NULL; - cert->extAuthInfoSz = 0; - cert->extCrlInfo = NULL; - cert->extCrlInfoSz = 0; - XMEMSET(cert->extSubjKeyId, 0, SHA_SIZE); - cert->extSubjKeyIdSet = 0; - XMEMSET(cert->extAuthKeyId, 0, SHA_SIZE); - cert->extAuthKeyIdSet = 0; - cert->extKeyUsageSet = 0; - cert->extKeyUsage = 0; - cert->extExtKeyUsageSet = 0; - cert->extExtKeyUsage = 0; - cert->isCA = 0; -#ifdef HAVE_PKCS7 - cert->issuerRaw = NULL; - cert->issuerRawLen = 0; -#endif -#ifdef CYASSL_CERT_GEN - cert->subjectSN = 0; - cert->subjectSNLen = 0; - cert->subjectC = 0; - cert->subjectCLen = 0; - cert->subjectL = 0; - cert->subjectLLen = 0; - cert->subjectST = 0; - cert->subjectSTLen = 0; - cert->subjectO = 0; - cert->subjectOLen = 0; - cert->subjectOU = 0; - cert->subjectOULen = 0; - cert->subjectEmail = 0; - cert->subjectEmailLen = 0; -#endif /* CYASSL_CERT_GEN */ - cert->beforeDate = NULL; - cert->beforeDateLen = 0; - cert->afterDate = NULL; - cert->afterDateLen = 0; -#ifdef OPENSSL_EXTRA - XMEMSET(&cert->issuerName, 0, sizeof(DecodedName)); - XMEMSET(&cert->subjectName, 0, sizeof(DecodedName)); - cert->extBasicConstSet = 0; - cert->extBasicConstCrit = 0; - cert->extBasicConstPlSet = 0; - cert->pathLength = 0; - cert->extSubjAltNameSet = 0; - cert->extSubjAltNameCrit = 0; - cert->extAuthKeyIdCrit = 0; - cert->extSubjKeyIdCrit = 0; - cert->extKeyUsageCrit = 0; - cert->extExtKeyUsageCrit = 0; - cert->extExtKeyUsageSrc = NULL; - cert->extExtKeyUsageSz = 0; - cert->extExtKeyUsageCount = 0; - cert->extAuthKeyIdSrc = NULL; - cert->extAuthKeyIdSz = 0; - cert->extSubjKeyIdSrc = NULL; - cert->extSubjKeyIdSz = 0; -#endif /* OPENSSL_EXTRA */ -#if defined(OPENSSL_EXTRA) || !defined(IGNORE_NAME_CONSTRAINTS) - cert->extNameConstraintSet = 0; -#endif /* OPENSSL_EXTRA || !IGNORE_NAME_CONSTRAINTS */ -#ifdef HAVE_ECC - cert->pkCurveOID = 0; -#endif /* HAVE_ECC */ -#ifdef CYASSL_SEP - cert->deviceTypeSz = 0; - cert->deviceType = NULL; - cert->hwTypeSz = 0; - cert->hwType = NULL; - cert->hwSerialNumSz = 0; - cert->hwSerialNum = NULL; - #ifdef OPENSSL_EXTRA - cert->extCertPolicySet = 0; - cert->extCertPolicyCrit = 0; - #endif /* OPENSSL_EXTRA */ -#endif /* CYASSL_SEP */ -} - - -void FreeAltNames(DNS_entry* altNames, void* heap) -{ - (void)heap; - - while (altNames) { - DNS_entry* tmp = altNames->next; - - XFREE(altNames->name, heap, DYNAMIC_TYPE_ALTNAME); - XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME); - altNames = tmp; - } -} - -#ifndef IGNORE_NAME_CONSTRAINTS - -void FreeNameSubtrees(Base_entry* names, void* heap) -{ - (void)heap; - - while (names) { - Base_entry* tmp = names->next; - - XFREE(names->name, heap, DYNAMIC_TYPE_ALTNAME); - XFREE(names, heap, DYNAMIC_TYPE_ALTNAME); - names = tmp; - } -} - -#endif /* IGNORE_NAME_CONSTRAINTS */ - -void FreeDecodedCert(DecodedCert* cert) -{ - if (cert->subjectCNStored == 1) - XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN); - if (cert->pubKeyStored == 1) - XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (cert->altNames) - FreeAltNames(cert->altNames, cert->heap); -#ifndef IGNORE_NAME_CONSTRAINTS - if (cert->altEmailNames) - FreeAltNames(cert->altEmailNames, cert->heap); - if (cert->permittedNames) - FreeNameSubtrees(cert->permittedNames, cert->heap); - if (cert->excludedNames) - FreeNameSubtrees(cert->excludedNames, cert->heap); -#endif /* IGNORE_NAME_CONSTRAINTS */ -#ifdef CYASSL_SEP - XFREE(cert->deviceType, cert->heap, 0); - XFREE(cert->hwType, cert->heap, 0); - XFREE(cert->hwSerialNum, cert->heap, 0); -#endif /* CYASSL_SEP */ -#ifdef OPENSSL_EXTRA - if (cert->issuerName.fullName != NULL) - XFREE(cert->issuerName.fullName, NULL, DYNAMIC_TYPE_X509); - if (cert->subjectName.fullName != NULL) - XFREE(cert->subjectName.fullName, NULL, DYNAMIC_TYPE_X509); -#endif /* OPENSSL_EXTRA */ -} - - -static int GetCertHeader(DecodedCert* cert) -{ - int ret = 0, len; - byte serialTmp[EXTERNAL_SERIAL_SIZE]; - mp_int mpi; - - if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0) - return ASN_PARSE_E; - - cert->certBegin = cert->srcIdx; - - if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0) - return ASN_PARSE_E; - cert->sigIndex = len + cert->srcIdx; - - if (GetExplicitVersion(cert->source, &cert->srcIdx, &cert->version) < 0) - return ASN_PARSE_E; - - if (GetInt(&mpi, cert->source, &cert->srcIdx, cert->maxIdx) < 0) - return ASN_PARSE_E; - - len = mp_unsigned_bin_size(&mpi); - if (len < (int)sizeof(serialTmp)) { - if ( (ret = mp_to_unsigned_bin(&mpi, serialTmp)) == MP_OKAY) { - if (len > EXTERNAL_SERIAL_SIZE) - len = EXTERNAL_SERIAL_SIZE; - XMEMCPY(cert->serial, serialTmp, len); - cert->serialSz = len; - } - } - mp_clear(&mpi); - return ret; -} - -#if !defined(NO_RSA) -/* Store Rsa Key, may save later, Dsa could use in future */ -static int StoreRsaKey(DecodedCert* cert) -{ - int length; - word32 recvd = cert->srcIdx; - - if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - recvd = cert->srcIdx - recvd; - length += recvd; - - while (recvd--) - cert->srcIdx--; - - cert->pubKeySize = length; - cert->publicKey = cert->source + cert->srcIdx; - cert->srcIdx += length; - - return 0; -} -#endif - - -#ifdef HAVE_ECC - - /* return 0 on sucess if the ECC curve oid sum is supported */ - static int CheckCurve(word32 oid) - { - if (oid != ECC_256R1 && oid != ECC_384R1 && oid != ECC_521R1 && oid != - ECC_160R1 && oid != ECC_192R1 && oid != ECC_224R1) - return ALGO_ID_E; - - return 0; - } - -#endif /* HAVE_ECC */ - - -static int GetKey(DecodedCert* cert) -{ - int length; -#ifdef HAVE_NTRU - int tmpIdx = cert->srcIdx; -#endif - - if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - if (GetAlgoId(cert->source, &cert->srcIdx, &cert->keyOID, cert->maxIdx) < 0) - return ASN_PARSE_E; - - switch (cert->keyOID) { - #ifndef NO_RSA - case RSAk: - { - byte b = cert->source[cert->srcIdx++]; - if (b != ASN_BIT_STRING) - return ASN_BITSTR_E; - - if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0) - return ASN_PARSE_E; - b = cert->source[cert->srcIdx++]; - if (b != 0x00) - return ASN_EXPECT_0_E; - - return StoreRsaKey(cert); - } - - #endif /* NO_RSA */ - #ifdef HAVE_NTRU - case NTRUk: - { - const byte* key = &cert->source[tmpIdx]; - byte* next = (byte*)key; - word16 keyLen; - byte keyBlob[MAX_NTRU_KEY_SZ]; - - word32 rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, - &keyLen, NULL, &next); - - if (rc != NTRU_OK) - return ASN_NTRU_KEY_E; - if (keyLen > sizeof(keyBlob)) - return ASN_NTRU_KEY_E; - - rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,&keyLen, - keyBlob, &next); - if (rc != NTRU_OK) - return ASN_NTRU_KEY_E; - - if ( (next - key) < 0) - return ASN_NTRU_KEY_E; - - cert->srcIdx = tmpIdx + (int)(next - key); - - cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (cert->publicKey == NULL) - return MEMORY_E; - XMEMCPY(cert->publicKey, keyBlob, keyLen); - cert->pubKeyStored = 1; - cert->pubKeySize = keyLen; - - return 0; - } - #endif /* HAVE_NTRU */ - #ifdef HAVE_ECC - case ECDSAk: - { - int oidSz = 0; - byte b = cert->source[cert->srcIdx++]; - - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(cert->source,&cert->srcIdx,&oidSz,cert->maxIdx) < 0) - return ASN_PARSE_E; - - while(oidSz--) - cert->pkCurveOID += cert->source[cert->srcIdx++]; - - if (CheckCurve(cert->pkCurveOID) < 0) - return ECC_CURVE_OID_E; - - /* key header */ - b = cert->source[cert->srcIdx++]; - if (b != ASN_BIT_STRING) - return ASN_BITSTR_E; - - if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0) - return ASN_PARSE_E; - b = cert->source[cert->srcIdx++]; - if (b != 0x00) - return ASN_EXPECT_0_E; - - /* actual key, use length - 1 since ate preceding 0 */ - length -= 1; - - cert->publicKey = (byte*) XMALLOC(length, cert->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (cert->publicKey == NULL) - return MEMORY_E; - XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length); - cert->pubKeyStored = 1; - cert->pubKeySize = length; - - cert->srcIdx += length; - - return 0; - } - #endif /* HAVE_ECC */ - default: - return ASN_UNKNOWN_OID_E; - } -} - - -/* process NAME, either issuer or subject */ -static int GetName(DecodedCert* cert, int nameType) -{ - Sha sha; /* MUST have SHA-1 hash for cert names */ - int length; /* length of all distinguished names */ - int dummy; - int ret; - char* full = (nameType == ISSUER) ? cert->issuer : cert->subject; - word32 idx; - #ifdef OPENSSL_EXTRA - DecodedName* dName = - (nameType == ISSUER) ? &cert->issuerName : &cert->subjectName; - #endif /* OPENSSL_EXTRA */ - - CYASSL_MSG("Getting Cert Name"); - - if (cert->source[cert->srcIdx] == ASN_OBJECT_ID) { - CYASSL_MSG("Trying optional prefix..."); - - if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - cert->srcIdx += length; - CYASSL_MSG("Got optional prefix"); - } - - /* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be - * calculated over the entire DER encoding of the Name field, including - * the tag and length. */ - idx = cert->srcIdx; - if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, &cert->source[idx], length + cert->srcIdx - idx); - if (nameType == ISSUER) - ShaFinal(&sha, cert->issuerHash); - else - ShaFinal(&sha, cert->subjectHash); - - length += cert->srcIdx; - idx = 0; - -#ifdef HAVE_PKCS7 - /* store pointer to raw issuer */ - if (nameType == ISSUER) { - cert->issuerRaw = &cert->source[cert->srcIdx]; - cert->issuerRawLen = length - cert->srcIdx; - } -#endif -#ifndef IGNORE_NAME_CONSTRAINTS - if (nameType == SUBJECT) { - cert->subjectRaw = &cert->source[cert->srcIdx]; - cert->subjectRawLen = length - cert->srcIdx; - } -#endif - - while (cert->srcIdx < (word32)length) { - byte b; - byte joint[2]; - byte tooBig = FALSE; - int oidSz; - - if (GetSet(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0) { - CYASSL_MSG("Cert name lacks set header, trying sequence"); - } - - if (GetSequence(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0) - return ASN_PARSE_E; - - b = cert->source[cert->srcIdx++]; - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(cert->source, &cert->srcIdx, &oidSz, cert->maxIdx) < 0) - return ASN_PARSE_E; - - XMEMCPY(joint, &cert->source[cert->srcIdx], sizeof(joint)); - - /* v1 name types */ - if (joint[0] == 0x55 && joint[1] == 0x04) { - byte id; - byte copy = FALSE; - int strLen; - - cert->srcIdx += 2; - id = cert->source[cert->srcIdx++]; - b = cert->source[cert->srcIdx++]; /* strType */ - (void)b; /* may want to validate? */ - - if (GetLength(cert->source, &cert->srcIdx, &strLen, - cert->maxIdx) < 0) - return ASN_PARSE_E; - - if ( (strLen + 14) > (int)(ASN_NAME_MAX - idx)) { - /* include biggest pre fix header too 4 = "/serialNumber=" */ - CYASSL_MSG("ASN Name too big, skipping"); - tooBig = TRUE; - } - - if (id == ASN_COMMON_NAME) { - if (nameType == SUBJECT) { - cert->subjectCN = (char *)&cert->source[cert->srcIdx]; - cert->subjectCNLen = strLen; - } - - if (!tooBig) { - XMEMCPY(&full[idx], "/CN=", 4); - idx += 4; - copy = TRUE; - } - #ifdef OPENSSL_EXTRA - dName->cnIdx = cert->srcIdx; - dName->cnLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_SUR_NAME) { - if (!tooBig) { - XMEMCPY(&full[idx], "/SN=", 4); - idx += 4; - copy = TRUE; - } - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectSN = (char*)&cert->source[cert->srcIdx]; - cert->subjectSNLen = strLen; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->snIdx = cert->srcIdx; - dName->snLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_COUNTRY_NAME) { - if (!tooBig) { - XMEMCPY(&full[idx], "/C=", 3); - idx += 3; - copy = TRUE; - } - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectC = (char*)&cert->source[cert->srcIdx]; - cert->subjectCLen = strLen; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->cIdx = cert->srcIdx; - dName->cLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_LOCALITY_NAME) { - if (!tooBig) { - XMEMCPY(&full[idx], "/L=", 3); - idx += 3; - copy = TRUE; - } - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectL = (char*)&cert->source[cert->srcIdx]; - cert->subjectLLen = strLen; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->lIdx = cert->srcIdx; - dName->lLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_STATE_NAME) { - if (!tooBig) { - XMEMCPY(&full[idx], "/ST=", 4); - idx += 4; - copy = TRUE; - } - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectST = (char*)&cert->source[cert->srcIdx]; - cert->subjectSTLen = strLen; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->stIdx = cert->srcIdx; - dName->stLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_ORG_NAME) { - if (!tooBig) { - XMEMCPY(&full[idx], "/O=", 3); - idx += 3; - copy = TRUE; - } - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectO = (char*)&cert->source[cert->srcIdx]; - cert->subjectOLen = strLen; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->oIdx = cert->srcIdx; - dName->oLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_ORGUNIT_NAME) { - if (!tooBig) { - XMEMCPY(&full[idx], "/OU=", 4); - idx += 4; - copy = TRUE; - } - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectOU = (char*)&cert->source[cert->srcIdx]; - cert->subjectOULen = strLen; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->ouIdx = cert->srcIdx; - dName->ouLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - else if (id == ASN_SERIAL_NUMBER) { - if (!tooBig) { - XMEMCPY(&full[idx], "/serialNumber=", 14); - idx += 14; - copy = TRUE; - } - #ifdef OPENSSL_EXTRA - dName->snIdx = cert->srcIdx; - dName->snLen = strLen; - #endif /* OPENSSL_EXTRA */ - } - - if (copy && !tooBig) { - XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen); - idx += strLen; - } - - cert->srcIdx += strLen; - } - else { - /* skip */ - byte email = FALSE; - byte uid = FALSE; - int adv; - - if (joint[0] == 0x2a && joint[1] == 0x86) /* email id hdr */ - email = TRUE; - - if (joint[0] == 0x9 && joint[1] == 0x92) /* uid id hdr */ - uid = TRUE; - - cert->srcIdx += oidSz + 1; - - if (GetLength(cert->source, &cert->srcIdx, &adv, cert->maxIdx) < 0) - return ASN_PARSE_E; - - if (adv > (int)(ASN_NAME_MAX - idx)) { - CYASSL_MSG("ASN name too big, skipping"); - tooBig = TRUE; - } - - if (email) { - if ( (14 + adv) > (int)(ASN_NAME_MAX - idx)) { - CYASSL_MSG("ASN name too big, skipping"); - tooBig = TRUE; - } - if (!tooBig) { - XMEMCPY(&full[idx], "/emailAddress=", 14); - idx += 14; - } - - #ifdef CYASSL_CERT_GEN - if (nameType == SUBJECT) { - cert->subjectEmail = (char*)&cert->source[cert->srcIdx]; - cert->subjectEmailLen = adv; - } - #endif /* CYASSL_CERT_GEN */ - #ifdef OPENSSL_EXTRA - dName->emailIdx = cert->srcIdx; - dName->emailLen = adv; - #endif /* OPENSSL_EXTRA */ - #ifndef IGNORE_NAME_CONSTRAINTS - { - DNS_entry* emailName = NULL; - - emailName = (DNS_entry*)XMALLOC(sizeof(DNS_entry), - cert->heap, DYNAMIC_TYPE_ALTNAME); - if (emailName == NULL) { - CYASSL_MSG("\tOut of Memory"); - return MEMORY_E; - } - emailName->name = (char*)XMALLOC(adv + 1, - cert->heap, DYNAMIC_TYPE_ALTNAME); - if (emailName->name == NULL) { - CYASSL_MSG("\tOut of Memory"); - return MEMORY_E; - } - XMEMCPY(emailName->name, - &cert->source[cert->srcIdx], adv); - emailName->name[adv] = 0; - - emailName->next = cert->altEmailNames; - cert->altEmailNames = emailName; - } - #endif /* IGNORE_NAME_CONSTRAINTS */ - if (!tooBig) { - XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv); - idx += adv; - } - } - - if (uid) { - if ( (5 + adv) > (int)(ASN_NAME_MAX - idx)) { - CYASSL_MSG("ASN name too big, skipping"); - tooBig = TRUE; - } - if (!tooBig) { - XMEMCPY(&full[idx], "/UID=", 5); - idx += 5; - - XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv); - idx += adv; - } - #ifdef OPENSSL_EXTRA - dName->uidIdx = cert->srcIdx; - dName->uidLen = adv; - #endif /* OPENSSL_EXTRA */ - } - - cert->srcIdx += adv; - } - } - full[idx++] = 0; - - #ifdef OPENSSL_EXTRA - { - int totalLen = 0; - - if (dName->cnLen != 0) - totalLen += dName->cnLen + 4; - if (dName->snLen != 0) - totalLen += dName->snLen + 4; - if (dName->cLen != 0) - totalLen += dName->cLen + 3; - if (dName->lLen != 0) - totalLen += dName->lLen + 3; - if (dName->stLen != 0) - totalLen += dName->stLen + 4; - if (dName->oLen != 0) - totalLen += dName->oLen + 3; - if (dName->ouLen != 0) - totalLen += dName->ouLen + 4; - if (dName->emailLen != 0) - totalLen += dName->emailLen + 14; - if (dName->uidLen != 0) - totalLen += dName->uidLen + 5; - if (dName->serialLen != 0) - totalLen += dName->serialLen + 14; - - dName->fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509); - if (dName->fullName != NULL) { - idx = 0; - - if (dName->cnLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/CN=", 4); - idx += 4; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->cnIdx], dName->cnLen); - dName->cnIdx = idx; - idx += dName->cnLen; - } - if (dName->snLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/SN=", 4); - idx += 4; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->snIdx], dName->snLen); - dName->snIdx = idx; - idx += dName->snLen; - } - if (dName->cLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/C=", 3); - idx += 3; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->cIdx], dName->cLen); - dName->cIdx = idx; - idx += dName->cLen; - } - if (dName->lLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/L=", 3); - idx += 3; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->lIdx], dName->lLen); - dName->lIdx = idx; - idx += dName->lLen; - } - if (dName->stLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/ST=", 4); - idx += 4; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->stIdx], dName->stLen); - dName->stIdx = idx; - idx += dName->stLen; - } - if (dName->oLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/O=", 3); - idx += 3; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->oIdx], dName->oLen); - dName->oIdx = idx; - idx += dName->oLen; - } - if (dName->ouLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/OU=", 4); - idx += 4; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->ouIdx], dName->ouLen); - dName->ouIdx = idx; - idx += dName->ouLen; - } - if (dName->emailLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/emailAddress=", 14); - idx += 14; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->emailIdx], dName->emailLen); - dName->emailIdx = idx; - idx += dName->emailLen; - } - if (dName->uidLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/UID=", 5); - idx += 5; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->uidIdx], dName->uidLen); - dName->uidIdx = idx; - idx += dName->uidLen; - } - if (dName->serialLen != 0) { - dName->entryCount++; - XMEMCPY(&dName->fullName[idx], "/serialNumber=", 14); - idx += 14; - XMEMCPY(&dName->fullName[idx], - &cert->source[dName->serialIdx], dName->serialLen); - dName->serialIdx = idx; - idx += dName->serialLen; - } - dName->fullName[idx] = '\0'; - dName->fullNameLen = totalLen; - } - } - #endif /* OPENSSL_EXTRA */ - - return 0; -} - - -#ifndef NO_TIME_H - -/* to the second */ -static int DateGreaterThan(const struct tm* a, const struct tm* b) -{ - if (a->tm_year > b->tm_year) - return 1; - - if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon) - return 1; - - if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && - a->tm_mday > b->tm_mday) - return 1; - - if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && - a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour) - return 1; - - if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && - a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && - a->tm_min > b->tm_min) - return 1; - - if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && - a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && - a->tm_min == b->tm_min && a->tm_sec > b->tm_sec) - return 1; - - return 0; /* false */ -} - - -static INLINE int DateLessThan(const struct tm* a, const struct tm* b) -{ - return !DateGreaterThan(a,b); -} - - -/* like atoi but only use first byte */ -/* Make sure before and after dates are valid */ -int ValidateDate(const byte* date, byte format, int dateType) -{ - time_t ltime; - struct tm certTime; - struct tm* localTime; - int i = 0; - - ltime = XTIME(0); - XMEMSET(&certTime, 0, sizeof(certTime)); - - if (format == ASN_UTC_TIME) { - if (btoi(date[0]) >= 5) - certTime.tm_year = 1900; - else - certTime.tm_year = 2000; - } - else { /* format == GENERALIZED_TIME */ - certTime.tm_year += btoi(date[i++]) * 1000; - certTime.tm_year += btoi(date[i++]) * 100; - } - - GetTime(&certTime.tm_year, date, &i); certTime.tm_year -= 1900; /* adjust */ - GetTime(&certTime.tm_mon, date, &i); certTime.tm_mon -= 1; /* adjust */ - GetTime(&certTime.tm_mday, date, &i); - GetTime(&certTime.tm_hour, date, &i); - GetTime(&certTime.tm_min, date, &i); - GetTime(&certTime.tm_sec, date, &i); - - if (date[i] != 'Z') { /* only Zulu supported for this profile */ - CYASSL_MSG("Only Zulu time supported for this profile"); - return 0; - } - - localTime = XGMTIME(<ime); - - if (dateType == BEFORE) { - if (DateLessThan(localTime, &certTime)) - return 0; - } - else - if (DateGreaterThan(localTime, &certTime)) - return 0; - - return 1; -} - -#endif /* NO_TIME_H */ - - -static int GetDate(DecodedCert* cert, int dateType) -{ - int length; - byte date[MAX_DATE_SIZE]; - byte b; - word32 startIdx = 0; - - if (dateType == BEFORE) - cert->beforeDate = &cert->source[cert->srcIdx]; - else - cert->afterDate = &cert->source[cert->srcIdx]; - startIdx = cert->srcIdx; - - b = cert->source[cert->srcIdx++]; - if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) - return ASN_TIME_E; - - if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE) - return ASN_DATE_SZ_E; - - XMEMCPY(date, &cert->source[cert->srcIdx], length); - cert->srcIdx += length; - - if (dateType == BEFORE) - cert->beforeDateLen = cert->srcIdx - startIdx; - else - cert->afterDateLen = cert->srcIdx - startIdx; - - if (!XVALIDATE_DATE(date, b, dateType)) { - if (dateType == BEFORE) - return ASN_BEFORE_DATE_E; - else - return ASN_AFTER_DATE_E; - } - - return 0; -} - - -static int GetValidity(DecodedCert* cert, int verify) -{ - int length; - int badDate = 0; - - if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - if (GetDate(cert, BEFORE) < 0 && verify) - badDate = ASN_BEFORE_DATE_E; /* continue parsing */ - - if (GetDate(cert, AFTER) < 0 && verify) - return ASN_AFTER_DATE_E; - - if (badDate != 0) - return badDate; - - return 0; -} - - -int DecodeToKey(DecodedCert* cert, int verify) -{ - int badDate = 0; - int ret; - - if ( (ret = GetCertHeader(cert)) < 0) - return ret; - - CYASSL_MSG("Got Cert Header"); - - if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID, - cert->maxIdx)) < 0) - return ret; - - CYASSL_MSG("Got Algo ID"); - - if ( (ret = GetName(cert, ISSUER)) < 0) - return ret; - - if ( (ret = GetValidity(cert, verify)) < 0) - badDate = ret; - - if ( (ret = GetName(cert, SUBJECT)) < 0) - return ret; - - CYASSL_MSG("Got Subject Name"); - - if ( (ret = GetKey(cert)) < 0) - return ret; - - CYASSL_MSG("Got Key"); - - if (badDate != 0) - return badDate; - - return ret; -} - - -static int GetSignature(DecodedCert* cert) -{ - int length; - byte b = cert->source[cert->srcIdx++]; - - if (b != ASN_BIT_STRING) - return ASN_BITSTR_E; - - if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) - return ASN_PARSE_E; - - cert->sigLength = length; - - b = cert->source[cert->srcIdx++]; - if (b != 0x00) - return ASN_EXPECT_0_E; - - cert->sigLength--; - cert->signature = &cert->source[cert->srcIdx]; - cert->srcIdx += cert->sigLength; - - return 0; -} - - -static word32 SetDigest(const byte* digest, word32 digSz, byte* output) -{ - output[0] = ASN_OCTET_STRING; - output[1] = (byte)digSz; - XMEMCPY(&output[2], digest, digSz); - - return digSz + 2; -} - - -static word32 BytePrecision(word32 value) -{ - word32 i; - for (i = sizeof(value); i; --i) - if (value >> ((i - 1) * CYASSL_BIT_SIZE)) - break; - - return i; -} - - -CYASSL_LOCAL word32 SetLength(word32 length, byte* output) -{ - word32 i = 0, j; - - if (length < ASN_LONG_LENGTH) - output[i++] = (byte)length; - else { - output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH); - - for (j = BytePrecision(length); j; --j) { - output[i] = (byte)(length >> ((j - 1) * CYASSL_BIT_SIZE)); - i++; - } - } - - return i; -} - - -CYASSL_LOCAL word32 SetSequence(word32 len, byte* output) -{ - output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED; - return SetLength(len, output + 1) + 1; -} - -CYASSL_LOCAL word32 SetOctetString(word32 len, byte* output) -{ - output[0] = ASN_OCTET_STRING; - return SetLength(len, output + 1) + 1; -} - -/* Write a set header to output */ -CYASSL_LOCAL word32 SetSet(word32 len, byte* output) -{ - output[0] = ASN_SET | ASN_CONSTRUCTED; - return SetLength(len, output + 1) + 1; -} - -CYASSL_LOCAL word32 SetImplicit(byte tag, byte number, word32 len, byte* output) -{ - - output[0] = ((tag == ASN_SEQUENCE || tag == ASN_SET) ? ASN_CONSTRUCTED : 0) - | ASN_CONTEXT_SPECIFIC | number; - return SetLength(len, output + 1) + 1; -} - -CYASSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output) -{ - output[0] = ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | number; - return SetLength(len, output + 1) + 1; -} - - -#if defined(HAVE_ECC) && defined(CYASSL_CERT_GEN) - -static word32 SetCurve(ecc_key* key, byte* output) -{ - - /* curve types */ - static const byte ECC_192v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, - 0x03, 0x01, 0x01}; - static const byte ECC_256v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, - 0x03, 0x01, 0x07}; - static const byte ECC_160r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, - 0x02}; - static const byte ECC_224r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, - 0x21}; - static const byte ECC_384r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, - 0x22}; - static const byte ECC_521r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, - 0x23}; - - int oidSz = 0; - int idx = 0; - int lenSz = 0; - const byte* oid = 0; - - output[0] = ASN_OBJECT_ID; - idx++; - - switch (key->dp->size) { - case 20: - oidSz = sizeof(ECC_160r1_AlgoID); - oid = ECC_160r1_AlgoID; - break; - - case 24: - oidSz = sizeof(ECC_192v1_AlgoID); - oid = ECC_192v1_AlgoID; - break; - - case 28: - oidSz = sizeof(ECC_224r1_AlgoID); - oid = ECC_224r1_AlgoID; - break; - - case 32: - oidSz = sizeof(ECC_256v1_AlgoID); - oid = ECC_256v1_AlgoID; - break; - - case 48: - oidSz = sizeof(ECC_384r1_AlgoID); - oid = ECC_384r1_AlgoID; - break; - - case 66: - oidSz = sizeof(ECC_521r1_AlgoID); - oid = ECC_521r1_AlgoID; - break; - - default: - return ASN_UNKNOWN_OID_E; - } - lenSz = SetLength(oidSz, output+idx); - idx += lenSz; - - XMEMCPY(output+idx, oid, oidSz); - idx += oidSz; - - return idx; -} - -#endif /* HAVE_ECC && CYASSL_CERT_GEN */ - - -CYASSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) -{ - /* adding TAG_NULL and 0 to end */ - - /* hashTypes */ - static const byte shaAlgoID[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a, - 0x05, 0x00 }; - static const byte sha256AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, - 0x04, 0x02, 0x01, 0x05, 0x00 }; - static const byte sha384AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, - 0x04, 0x02, 0x02, 0x05, 0x00 }; - static const byte sha512AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, - 0x04, 0x02, 0x03, 0x05, 0x00 }; - static const byte md5AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x02, 0x05, 0x05, 0x00 }; - static const byte md2AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x02, 0x02, 0x05, 0x00}; - - /* blkTypes, no NULL tags because IV is there instead */ - static const byte desCbcAlgoID[] = { 0x2B, 0x0E, 0x03, 0x02, 0x07 }; - static const byte des3CbcAlgoID[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x03, 0x07 }; - - /* RSA sigTypes */ - #ifndef NO_RSA - static const byte md5wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00}; - static const byte shawRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00}; - static const byte sha256wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00}; - static const byte sha384wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00}; - static const byte sha512wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00}; - #endif /* NO_RSA */ - - /* ECDSA sigTypes */ - #ifdef HAVE_ECC - static const byte shawECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, - 0x04, 0x01, 0x05, 0x00}; - static const byte sha256wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d, - 0x04, 0x03, 0x02, 0x05, 0x00}; - static const byte sha384wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d, - 0x04, 0x03, 0x03, 0x05, 0x00}; - static const byte sha512wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d, - 0x04, 0x03, 0x04, 0x05, 0x00}; - #endif /* HAVE_ECC */ - - /* RSA keyType */ - #ifndef NO_RSA - static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x01, 0x01, 0x05, 0x00}; - #endif /* NO_RSA */ - - #ifdef HAVE_ECC - /* ECC keyType */ - /* no tags, so set tagSz smaller later */ - static const byte ECC_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, - 0x02, 0x01}; - #endif /* HAVE_ECC */ - - int algoSz = 0; - int tagSz = 2; /* tag null and terminator */ - word32 idSz, seqSz; - const byte* algoName = 0; - byte ID_Length[MAX_LENGTH_SZ]; - byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */ - - if (type == hashType) { - switch (algoOID) { - case SHAh: - algoSz = sizeof(shaAlgoID); - algoName = shaAlgoID; - break; - - case SHA256h: - algoSz = sizeof(sha256AlgoID); - algoName = sha256AlgoID; - break; - - case SHA384h: - algoSz = sizeof(sha384AlgoID); - algoName = sha384AlgoID; - break; - - case SHA512h: - algoSz = sizeof(sha512AlgoID); - algoName = sha512AlgoID; - break; - - case MD2h: - algoSz = sizeof(md2AlgoID); - algoName = md2AlgoID; - break; - - case MD5h: - algoSz = sizeof(md5AlgoID); - algoName = md5AlgoID; - break; - - default: - CYASSL_MSG("Unknown Hash Algo"); - return 0; /* UNKOWN_HASH_E; */ - } - } - else if (type == blkType) { - switch (algoOID) { - case DESb: - algoSz = sizeof(desCbcAlgoID); - algoName = desCbcAlgoID; - tagSz = 0; - break; - case DES3b: - algoSz = sizeof(des3CbcAlgoID); - algoName = des3CbcAlgoID; - tagSz = 0; - break; - default: - CYASSL_MSG("Unknown Block Algo"); - return 0; - } - } - else if (type == sigType) { /* sigType */ - switch (algoOID) { - #ifndef NO_RSA - case CTC_MD5wRSA: - algoSz = sizeof(md5wRSA_AlgoID); - algoName = md5wRSA_AlgoID; - break; - - case CTC_SHAwRSA: - algoSz = sizeof(shawRSA_AlgoID); - algoName = shawRSA_AlgoID; - break; - - case CTC_SHA256wRSA: - algoSz = sizeof(sha256wRSA_AlgoID); - algoName = sha256wRSA_AlgoID; - break; - - case CTC_SHA384wRSA: - algoSz = sizeof(sha384wRSA_AlgoID); - algoName = sha384wRSA_AlgoID; - break; - - case CTC_SHA512wRSA: - algoSz = sizeof(sha512wRSA_AlgoID); - algoName = sha512wRSA_AlgoID; - break; - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case CTC_SHAwECDSA: - algoSz = sizeof(shawECDSA_AlgoID); - algoName = shawECDSA_AlgoID; - break; - - case CTC_SHA256wECDSA: - algoSz = sizeof(sha256wECDSA_AlgoID); - algoName = sha256wECDSA_AlgoID; - break; - - case CTC_SHA384wECDSA: - algoSz = sizeof(sha384wECDSA_AlgoID); - algoName = sha384wECDSA_AlgoID; - break; - - case CTC_SHA512wECDSA: - algoSz = sizeof(sha512wECDSA_AlgoID); - algoName = sha512wECDSA_AlgoID; - break; - #endif /* HAVE_ECC */ - default: - CYASSL_MSG("Unknown Signature Algo"); - return 0; - } - } - else if (type == keyType) { /* keyType */ - switch (algoOID) { - #ifndef NO_RSA - case RSAk: - algoSz = sizeof(RSA_AlgoID); - algoName = RSA_AlgoID; - break; - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - algoSz = sizeof(ECC_AlgoID); - algoName = ECC_AlgoID; - tagSz = 0; - break; - #endif /* HAVE_ECC */ - default: - CYASSL_MSG("Unknown Key Algo"); - return 0; - } - } - else { - CYASSL_MSG("Unknown Algo type"); - return 0; - } - - idSz = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */ - seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray); - /* +1 for object id, curveID of curveSz follows for ecc */ - seqArray[seqSz++] = ASN_OBJECT_ID; - - XMEMCPY(output, seqArray, seqSz); - XMEMCPY(output + seqSz, ID_Length, idSz); - XMEMCPY(output + seqSz + idSz, algoName, algoSz); - - return seqSz + idSz + algoSz; - -} - - -word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID) -{ - byte digArray[MAX_ENCODED_DIG_SZ]; - byte algoArray[MAX_ALGO_SZ]; - byte seqArray[MAX_SEQ_SZ]; - word32 encDigSz, algoSz, seqSz; - - encDigSz = SetDigest(digest, digSz, digArray); - algoSz = SetAlgoID(hashOID, algoArray, hashType, 0); - seqSz = SetSequence(encDigSz + algoSz, seqArray); - - XMEMCPY(out, seqArray, seqSz); - XMEMCPY(out + seqSz, algoArray, algoSz); - XMEMCPY(out + seqSz + algoSz, digArray, encDigSz); - - return encDigSz + algoSz + seqSz; -} - - -/* return true (1) for Confirmation */ -static int ConfirmSignature(const byte* buf, word32 bufSz, - const byte* key, word32 keySz, word32 keyOID, - const byte* sig, word32 sigSz, word32 sigOID, - void* heap) -{ -#ifdef CYASSL_SHA512 - byte digest[SHA512_DIGEST_SIZE]; /* max size */ -#elif !defined(NO_SHA256) - byte digest[SHA256_DIGEST_SIZE]; /* max size */ -#else - byte digest[SHA_DIGEST_SIZE]; /* max size */ -#endif - int typeH, digestSz, ret = 0; - - (void)key; - (void)keySz; - (void)sig; - (void)sigSz; - (void)heap; - (void)ret; - - switch (sigOID) { -#ifndef NO_MD5 - case CTC_MD5wRSA: - { - Md5 md5; - InitMd5(&md5); - Md5Update(&md5, buf, bufSz); - Md5Final(&md5, digest); - typeH = MD5h; - digestSz = MD5_DIGEST_SIZE; - } - break; -#endif - #if defined(CYASSL_MD2) - case CTC_MD2wRSA: - { - Md2 md2; - InitMd2(&md2); - Md2Update(&md2, buf, bufSz); - Md2Final(&md2, digest); - typeH = MD2h; - digestSz = MD2_DIGEST_SIZE; - } - break; - #endif -#ifndef NO_SHA - case CTC_SHAwRSA: - case CTC_SHAwDSA: - case CTC_SHAwECDSA: - { - Sha sha; - ret = InitSha(&sha); - if (ret != 0) { - CYASSL_MSG("InitSha failed"); - return 0; /* not confirmed */ - } - ShaUpdate(&sha, buf, bufSz); - ShaFinal(&sha, digest); - typeH = SHAh; - digestSz = SHA_DIGEST_SIZE; - } - break; -#endif - #ifndef NO_SHA256 - case CTC_SHA256wRSA: - case CTC_SHA256wECDSA: - { - Sha256 sha256; - ret = InitSha256(&sha256); - if (ret != 0) { - CYASSL_MSG("InitSha256 failed"); - return 0; /* not confirmed */ - } - - ret = Sha256Update(&sha256, buf, bufSz); - if (ret != 0) { - CYASSL_MSG("Sha256Update failed"); - return 0; /* not confirmed */ - } - - ret = Sha256Final(&sha256, digest); - if (ret != 0) { - CYASSL_MSG("Sha256Final failed"); - return 0; /* not confirmed */ - } - - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - } - break; - #endif - #ifdef CYASSL_SHA512 - case CTC_SHA512wRSA: - case CTC_SHA512wECDSA: - { - Sha512 sha512; - ret = InitSha512(&sha512); - if (ret != 0) { - CYASSL_MSG("InitSha512 failed"); - return 0; /* not confirmed */ - } - - ret = Sha512Update(&sha512, buf, bufSz); - if (ret != 0) { - CYASSL_MSG("Sha512Update failed"); - return 0; /* not confirmed */ - } - - ret = Sha512Final(&sha512, digest); - if (ret != 0) { - CYASSL_MSG("Sha512Final failed"); - return 0; /* not confirmed */ - } - - typeH = SHA512h; - digestSz = SHA512_DIGEST_SIZE; - } - break; - #endif - #ifdef CYASSL_SHA384 - case CTC_SHA384wRSA: - case CTC_SHA384wECDSA: - { - Sha384 sha384; - ret = InitSha384(&sha384); - if (ret != 0) { - CYASSL_MSG("InitSha384 failed"); - return 0; /* not confirmed */ - } - - ret = Sha384Update(&sha384, buf, bufSz); - if (ret != 0) { - CYASSL_MSG("Sha384Update failed"); - return 0; /* not confirmed */ - } - - ret = Sha384Final(&sha384, digest); - if (ret != 0) { - CYASSL_MSG("Sha384Final failed"); - return 0; /* not confirmed */ - } - - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - } - break; - #endif - default: - CYASSL_MSG("Verify Signautre has unsupported type"); - return 0; - } - (void)typeH; /* some builds won't read */ - - switch (keyOID) { - #ifndef NO_RSA - case RSAk: - { - RsaKey pubKey; - byte encodedSig[MAX_ENCODED_SIG_SZ]; - byte plain[MAX_ENCODED_SIG_SZ]; - word32 idx = 0; - int encodedSigSz, verifySz; - byte* out; - - if (sigSz > MAX_ENCODED_SIG_SZ) { - CYASSL_MSG("Verify Signautre is too big"); - return 0; - } - - ret = InitRsaKey(&pubKey, heap); - if (ret != 0) return ret; - if (RsaPublicKeyDecode(key, &idx, &pubKey, keySz) < 0) { - CYASSL_MSG("ASN Key decode error RSA"); - ret = 0; - } - else { - XMEMCPY(plain, sig, sigSz); - if ( (verifySz = RsaSSL_VerifyInline(plain, sigSz, &out, - &pubKey)) < 0) { - CYASSL_MSG("Rsa SSL verify error"); - ret = 0; - } - else { - /* make sure we're right justified */ - encodedSigSz = - EncodeSignature(encodedSig, digest, digestSz, typeH); - if (encodedSigSz != verifySz || - XMEMCMP(out, encodedSig, encodedSigSz) != 0) { - CYASSL_MSG("Rsa SSL verify match encode error"); - ret = 0; - } - else - ret = 1; /* match */ - - #ifdef CYASSL_DEBUG_ENCODING - { - int x; - printf("cyassl encodedSig:\n"); - for (x = 0; x < encodedSigSz; x++) { - printf("%02x ", encodedSig[x]); - if ( (x % 16) == 15) - printf("\n"); - } - printf("\n"); - printf("actual digest:\n"); - for (x = 0; x < verifySz; x++) { - printf("%02x ", out[x]); - if ( (x % 16) == 15) - printf("\n"); - } - printf("\n"); - } - #endif /* CYASSL_DEBUG_ENCODING */ - } - } - FreeRsaKey(&pubKey); - return ret; - } - - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - { - ecc_key pubKey; - int verify = 0; - - if (ecc_import_x963(key, keySz, &pubKey) < 0) { - CYASSL_MSG("ASN Key import error ECC"); - return 0; - } - - ret = ecc_verify_hash(sig,sigSz,digest,digestSz,&verify,&pubKey); - ecc_free(&pubKey); - if (ret == 0 && verify == 1) - return 1; /* match */ - - CYASSL_MSG("ECC Verify didn't match"); - return 0; - } - #endif /* HAVE_ECC */ - default: - CYASSL_MSG("Verify Key type unknown"); - return 0; - } -} - - -#ifndef IGNORE_NAME_CONSTRAINTS - -static int MatchBaseName(int type, const char* name, int nameSz, - const char* base, int baseSz) -{ - if (base == NULL || baseSz <= 0 || name == NULL || nameSz <= 0 || - name[0] == '.' || nameSz < baseSz || - (type != ASN_RFC822_TYPE && type != ASN_DNS_TYPE)) - return 0; - - /* If an email type, handle special cases where the base is only - * a domain, or is an email address itself. */ - if (type == ASN_RFC822_TYPE) { - const char* p = NULL; - int count = 0; - - if (base[0] != '.') { - p = base; - count = 0; - - /* find the '@' in the base */ - while (*p != '@' && count < baseSz) { - count++; - p++; - } - - /* No '@' in base, reset p to NULL */ - if (count >= baseSz) - p = NULL; - } - - if (p == NULL) { - /* Base isn't an email address, it is a domain name, - * wind the name forward one character past its '@'. */ - p = name; - count = 0; - while (*p != '@' && count < baseSz) { - count++; - p++; - } - - if (count < baseSz && *p == '@') { - name = p + 1; - nameSz -= count + 1; - } - } - } - - if ((type == ASN_DNS_TYPE || type == ASN_RFC822_TYPE) && base[0] == '.') { - int szAdjust = nameSz - baseSz; - name += szAdjust; - nameSz -= szAdjust; - } - - while (nameSz > 0) { - if (XTOLOWER(*name++) != XTOLOWER(*base++)) - return 0; - nameSz--; - } - - return 1; -} - - -static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) -{ - if (signer == NULL || cert == NULL) - return 0; - - /* Check against the excluded list */ - if (signer->excludedNames) { - Base_entry* base = signer->excludedNames; - - while (base != NULL) { - if (base->type == ASN_DNS_TYPE) { - DNS_entry* name = cert->altNames; - while (name != NULL) { - if (MatchBaseName(ASN_DNS_TYPE, - name->name, (int)XSTRLEN(name->name), - base->name, base->nameSz)) - return 0; - name = name->next; - } - } - else if (base->type == ASN_RFC822_TYPE) { - DNS_entry* name = cert->altEmailNames; - while (name != NULL) { - if (MatchBaseName(ASN_RFC822_TYPE, - name->name, (int)XSTRLEN(name->name), - base->name, base->nameSz)) - return 0; - - name = name->next; - } - } - else if (base->type == ASN_DIR_TYPE) { - if (cert->subjectRawLen == base->nameSz && - XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) { - - return 0; - } - } - base = base->next; - } - } - - /* Check against the permitted list */ - if (signer->permittedNames != NULL) { - int needDns = 0; - int matchDns = 0; - int needEmail = 0; - int matchEmail = 0; - int needDir = 0; - int matchDir = 0; - Base_entry* base = signer->permittedNames; - - while (base != NULL) { - if (base->type == ASN_DNS_TYPE) { - DNS_entry* name = cert->altNames; - - if (name != NULL) - needDns = 1; - - while (name != NULL) { - matchDns = MatchBaseName(ASN_DNS_TYPE, - name->name, (int)XSTRLEN(name->name), - base->name, base->nameSz); - name = name->next; - } - } - else if (base->type == ASN_RFC822_TYPE) { - DNS_entry* name = cert->altEmailNames; - - if (name != NULL) - needEmail = 1; - - while (name != NULL) { - matchEmail = MatchBaseName(ASN_DNS_TYPE, - name->name, (int)XSTRLEN(name->name), - base->name, base->nameSz); - name = name->next; - } - } - else if (base->type == ASN_DIR_TYPE) { - needDir = 1; - if (cert->subjectRaw != NULL && - cert->subjectRawLen == base->nameSz && - XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) { - - matchDir = 1; - } - } - base = base->next; - } - - if ((needDns && !matchDns) || (needEmail && !matchEmail) || - (needDir && !matchDir)) { - - return 0; - } - } - - return 1; -} - -#endif /* IGNORE_NAME_CONSTRAINTS */ - - -static int DecodeAltNames(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length = 0; - - CYASSL_ENTER("DecodeAltNames"); - - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tBad Sequence"); - return ASN_PARSE_E; - } - - while (length > 0) { - byte b = input[idx++]; - - length--; - - /* Save DNS Type names in the altNames list. */ - /* Save Other Type names in the cert's OidMap */ - if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) { - DNS_entry* dnsEntry; - int strLen; - word32 lenStartIdx = idx; - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfail: str length"); - return ASN_PARSE_E; - } - length -= (idx - lenStartIdx); - - dnsEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap, - DYNAMIC_TYPE_ALTNAME); - if (dnsEntry == NULL) { - CYASSL_MSG("\tOut of Memory"); - return ASN_PARSE_E; - } - - dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, - DYNAMIC_TYPE_ALTNAME); - if (dnsEntry->name == NULL) { - CYASSL_MSG("\tOut of Memory"); - XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME); - return ASN_PARSE_E; - } - - XMEMCPY(dnsEntry->name, &input[idx], strLen); - dnsEntry->name[strLen] = '\0'; - - dnsEntry->next = cert->altNames; - cert->altNames = dnsEntry; - - length -= strLen; - idx += strLen; - } -#ifndef IGNORE_NAME_CONSTRAINTS - else if (b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) { - DNS_entry* emailEntry; - int strLen; - word32 lenStartIdx = idx; - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfail: str length"); - return ASN_PARSE_E; - } - length -= (idx - lenStartIdx); - - emailEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap, - DYNAMIC_TYPE_ALTNAME); - if (emailEntry == NULL) { - CYASSL_MSG("\tOut of Memory"); - return ASN_PARSE_E; - } - - emailEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, - DYNAMIC_TYPE_ALTNAME); - if (emailEntry->name == NULL) { - CYASSL_MSG("\tOut of Memory"); - XFREE(emailEntry, cert->heap, DYNAMIC_TYPE_ALTNAME); - return ASN_PARSE_E; - } - - XMEMCPY(emailEntry->name, &input[idx], strLen); - emailEntry->name[strLen] = '\0'; - - emailEntry->next = cert->altEmailNames; - cert->altEmailNames = emailEntry; - - length -= strLen; - idx += strLen; - } -#endif /* IGNORE_NAME_CONSTRAINTS */ -#ifdef CYASSL_SEP - else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE)) - { - int strLen; - word32 lenStartIdx = idx; - word32 oid = 0; - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfail: other name length"); - return ASN_PARSE_E; - } - /* Consume the rest of this sequence. */ - length -= (strLen + idx - lenStartIdx); - - if (GetObjectId(input, &idx, &oid, sz) < 0) { - CYASSL_MSG("\tbad OID"); - return ASN_PARSE_E; - } - - if (oid != HW_NAME_OID) { - CYASSL_MSG("\tincorrect OID"); - return ASN_PARSE_E; - } - - if (input[idx++] != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { - CYASSL_MSG("\twrong type"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfail: str len"); - return ASN_PARSE_E; - } - - if (GetSequence(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tBad Sequence"); - return ASN_PARSE_E; - } - - if (input[idx++] != ASN_OBJECT_ID) { - CYASSL_MSG("\texpected OID"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfailed: str len"); - return ASN_PARSE_E; - } - - cert->hwType = (byte*)XMALLOC(strLen, cert->heap, 0); - if (cert->hwType == NULL) { - CYASSL_MSG("\tOut of Memory"); - return MEMORY_E; - } - - XMEMCPY(cert->hwType, &input[idx], strLen); - cert->hwTypeSz = strLen; - idx += strLen; - - if (input[idx++] != ASN_OCTET_STRING) { - CYASSL_MSG("\texpected Octet String"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfailed: str len"); - return ASN_PARSE_E; - } - - cert->hwSerialNum = (byte*)XMALLOC(strLen + 1, cert->heap, 0); - if (cert->hwSerialNum == NULL) { - CYASSL_MSG("\tOut of Memory"); - return MEMORY_E; - } - - XMEMCPY(cert->hwSerialNum, &input[idx], strLen); - cert->hwSerialNum[strLen] = '\0'; - cert->hwSerialNumSz = strLen; - idx += strLen; - } -#endif /* CYASSL_SEP */ - else { - int strLen; - word32 lenStartIdx = idx; - - CYASSL_MSG("\tUnsupported name type, skipping"); - - if (GetLength(input, &idx, &strLen, sz) < 0) { - CYASSL_MSG("\tfail: unsupported name length"); - return ASN_PARSE_E; - } - length -= (strLen + idx - lenStartIdx); - idx += strLen; - } - } - return 0; -} - - -static int DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length = 0; - - CYASSL_ENTER("DecodeBasicCaConstraint"); - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: bad SEQUENCE"); - return ASN_PARSE_E; - } - - if (length == 0) - return 0; - - /* If the basic ca constraint is false, this extension may be named, but - * left empty. So, if the length is 0, just return. */ - - if (input[idx++] != ASN_BOOLEAN) - { - CYASSL_MSG("\tfail: constraint not BOOLEAN"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &length, sz) < 0) - { - CYASSL_MSG("\tfail: length"); - return ASN_PARSE_E; - } - - if (input[idx++]) - cert->isCA = 1; - - #ifdef OPENSSL_EXTRA - /* If there isn't any more data, return. */ - if (idx >= (word32)sz) - return 0; - - /* Anything left should be the optional pathlength */ - if (input[idx++] != ASN_INTEGER) { - CYASSL_MSG("\tfail: pathlen not INTEGER"); - return ASN_PARSE_E; - } - - if (input[idx++] != 1) { - CYASSL_MSG("\tfail: pathlen too long"); - return ASN_PARSE_E; - } - - cert->pathLength = input[idx]; - cert->extBasicConstPlSet = 1; - #endif /* OPENSSL_EXTRA */ - - return 0; -} - - -#define CRLDP_FULL_NAME 0 - /* From RFC3280 SS4.2.1.14, Distribution Point Name*/ -#define GENERALNAME_URI 6 - /* From RFC3280 SS4.2.1.7, GeneralName */ - -static int DecodeCrlDist(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length = 0; - - CYASSL_ENTER("DecodeCrlDist"); - - /* Unwrap the list of Distribution Points*/ - if (GetSequence(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - /* Unwrap a single Distribution Point */ - if (GetSequence(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - /* The Distribution Point has three explicit optional members - * First check for a DistributionPointName - */ - if (input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - { - idx++; - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - if (input[idx] == - (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CRLDP_FULL_NAME)) - { - idx++; - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - if (input[idx] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI)) - { - idx++; - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - cert->extCrlInfoSz = length; - cert->extCrlInfo = input + idx; - idx += length; - } - else - /* This isn't a URI, skip it. */ - idx += length; - } - else - /* This isn't a FULLNAME, skip it. */ - idx += length; - } - - /* Check for reasonFlags */ - if (idx < (word32)sz && - input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) - { - idx++; - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - idx += length; - } - - /* Check for cRLIssuer */ - if (idx < (word32)sz && - input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2)) - { - idx++; - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - idx += length; - } - - if (idx < (word32)sz) - { - CYASSL_MSG("\tThere are more CRL Distribution Point records, " - "but we only use the first one."); - } - - return 0; -} - - -static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert) -/* - * Read the first of the Authority Information Access records. If there are - * any issues, return without saving the record. - */ -{ - word32 idx = 0; - int length = 0; - byte b; - word32 oid; - - CYASSL_ENTER("DecodeAuthInfo"); - - /* Unwrap the list of AIAs */ - if (GetSequence(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - while (idx < (word32)sz) { - /* Unwrap a single AIA */ - if (GetSequence(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - oid = 0; - if (GetObjectId(input, &idx, &oid, sz) < 0) - return ASN_PARSE_E; - - /* Only supporting URIs right now. */ - b = input[idx++]; - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - if (b == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI) && - oid == AIA_OCSP_OID) - { - cert->extAuthInfoSz = length; - cert->extAuthInfo = input + idx; - break; - } - idx += length; - } - - return 0; -} - - -static int DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length = 0, ret = 0; - - CYASSL_ENTER("DecodeAuthKeyId"); - - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: should be a SEQUENCE\n"); - return ASN_PARSE_E; - } - - if (input[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) { - CYASSL_MSG("\tfail: wanted OPTIONAL item 0, not available\n"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: extension data length"); - return ASN_PARSE_E; - } - - #ifdef OPENSSL_EXTRA - cert->extAuthKeyIdSrc = &input[idx]; - cert->extAuthKeyIdSz = length; - #endif /* OPENSSL_EXTRA */ - - if (length == SHA_SIZE) { - XMEMCPY(cert->extAuthKeyId, input + idx, length); - } - else { - Sha sha; - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, input + idx, length); - ShaFinal(&sha, cert->extAuthKeyId); - } - - return 0; -} - - -static int DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length = 0, ret = 0; - - CYASSL_ENTER("DecodeSubjKeyId"); - - if (input[idx++] != ASN_OCTET_STRING) { - CYASSL_MSG("\tfail: should be an OCTET STRING"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: extension data length"); - return ASN_PARSE_E; - } - - #ifdef OPENSSL_EXTRA - cert->extSubjKeyIdSrc = &input[idx]; - cert->extSubjKeyIdSz = length; - #endif /* OPENSSL_EXTRA */ - - if (length == SIGNER_DIGEST_SIZE) { - XMEMCPY(cert->extSubjKeyId, input + idx, length); - } - else { - Sha sha; - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, input + idx, length); - ShaFinal(&sha, cert->extSubjKeyId); - } - - return ret; -} - - -static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length; - byte unusedBits; - CYASSL_ENTER("DecodeKeyUsage"); - - if (input[idx++] != ASN_BIT_STRING) { - CYASSL_MSG("\tfail: key usage expected bit string"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: key usage bad length"); - return ASN_PARSE_E; - } - - unusedBits = input[idx++]; - length--; - - if (length == 2) { - cert->extKeyUsage = (word16)((input[idx] << 8) | input[idx+1]); - cert->extKeyUsage >>= unusedBits; - } - else if (length == 1) - cert->extKeyUsage = (word16)(input[idx] << 1); - - return 0; -} - - -static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0, oid; - int length; - - CYASSL_ENTER("DecodeExtKeyUsage"); - - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: should be a SEQUENCE"); - return ASN_PARSE_E; - } - - #ifdef OPENSSL_EXTRA - cert->extExtKeyUsageSrc = input + idx; - cert->extExtKeyUsageSz = length; - #endif - - while (idx < (word32)sz) { - if (GetObjectId(input, &idx, &oid, sz) < 0) - return ASN_PARSE_E; - - switch (oid) { - case EKU_ANY_OID: - cert->extExtKeyUsage |= EXTKEYUSE_ANY; - break; - case EKU_SERVER_AUTH_OID: - cert->extExtKeyUsage |= EXTKEYUSE_SERVER_AUTH; - break; - case EKU_CLIENT_AUTH_OID: - cert->extExtKeyUsage |= EXTKEYUSE_CLIENT_AUTH; - break; - case EKU_OCSP_SIGN_OID: - cert->extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN; - break; - } - - #ifdef OPENSSL_EXTRA - cert->extExtKeyUsageCount++; - #endif - } - - return 0; -} - - -#ifndef IGNORE_NAME_CONSTRAINTS -static int DecodeSubtree(byte* input, int sz, Base_entry** head, void* heap) -{ - word32 idx = 0; - - (void)heap; - - while (idx < (word32)sz) { - int seqLength, strLength; - word32 nameIdx; - byte b; - - if (GetSequence(input, &idx, &seqLength, sz) < 0) { - CYASSL_MSG("\tfail: should be a SEQUENCE"); - return ASN_PARSE_E; - } - - nameIdx = idx; - b = input[nameIdx++]; - if (GetLength(input, &nameIdx, &strLength, sz) <= 0) { - CYASSL_MSG("\tinvalid length"); - return ASN_PARSE_E; - } - - if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE) || - b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE) || - b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE)) { - - Base_entry* entry = (Base_entry*)XMALLOC(sizeof(Base_entry), - heap, DYNAMIC_TYPE_ALTNAME); - - if (entry == NULL) { - CYASSL_MSG("allocate error"); - return MEMORY_E; - } - - entry->name = (char*)XMALLOC(strLength, heap, DYNAMIC_TYPE_ALTNAME); - if (entry->name == NULL) { - CYASSL_MSG("allocate error"); - return MEMORY_E; - } - - XMEMCPY(entry->name, &input[nameIdx], strLength); - entry->nameSz = strLength; - entry->type = b & 0x0F; - - entry->next = *head; - *head = entry; - } - - idx += seqLength; - } - - return 0; -} - - -static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert) -{ - word32 idx = 0; - int length = 0; - - CYASSL_ENTER("DecodeNameConstraints"); - - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: should be a SEQUENCE"); - return ASN_PARSE_E; - } - - while (idx < (word32)sz) { - byte b = input[idx++]; - Base_entry** subtree = NULL; - - if (GetLength(input, &idx, &length, sz) <= 0) { - CYASSL_MSG("\tinvalid length"); - return ASN_PARSE_E; - } - - if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) - subtree = &cert->permittedNames; - else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) - subtree = &cert->excludedNames; - else { - CYASSL_MSG("\tinvalid subtree"); - return ASN_PARSE_E; - } - - DecodeSubtree(input + idx, length, subtree, cert->heap); - - idx += length; - } - - return 0; -} -#endif /* IGNORE_NAME_CONSTRAINTS */ - - -#ifdef CYASSL_SEP - static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert) - { - word32 idx = 0; - int length = 0; - - CYASSL_ENTER("DecodeCertPolicy"); - - /* Unwrap certificatePolicies */ - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tdeviceType isn't OID"); - return ASN_PARSE_E; - } - - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tdeviceType isn't OID"); - return ASN_PARSE_E; - } - - if (input[idx++] != ASN_OBJECT_ID) { - CYASSL_MSG("\tdeviceType isn't OID"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tCouldn't read length of deviceType"); - return ASN_PARSE_E; - } - - if (length > 0) { - cert->deviceType = (byte*)XMALLOC(length, cert->heap, 0); - if (cert->deviceType == NULL) { - CYASSL_MSG("\tCouldn't alloc memory for deviceType"); - return MEMORY_E; - } - cert->deviceTypeSz = length; - XMEMCPY(cert->deviceType, input + idx, length); - } - - CYASSL_LEAVE("DecodeCertPolicy", 0); - return 0; - } -#endif /* CYASSL_SEP */ - - -static int DecodeCertExtensions(DecodedCert* cert) -/* - * Processing the Certificate Extensions. This does not modify the current - * index. It is works starting with the recorded extensions pointer. - */ -{ - word32 idx = 0; - int sz = cert->extensionsSz; - byte* input = cert->extensions; - int length; - word32 oid; - byte critical = 0; - byte criticalFail = 0; - - CYASSL_ENTER("DecodeCertExtensions"); - - if (input == NULL || sz == 0) - return BAD_FUNC_ARG; - - if (input[idx++] != ASN_EXTENSIONS) - return ASN_PARSE_E; - - if (GetLength(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - if (GetSequence(input, &idx, &length, sz) < 0) - return ASN_PARSE_E; - - while (idx < (word32)sz) { - if (GetSequence(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: should be a SEQUENCE"); - return ASN_PARSE_E; - } - - oid = 0; - if (GetObjectId(input, &idx, &oid, sz) < 0) { - CYASSL_MSG("\tfail: OBJECT ID"); - return ASN_PARSE_E; - } - - /* check for critical flag */ - critical = 0; - if (input[idx] == ASN_BOOLEAN) { - int boolLength = 0; - idx++; - if (GetLength(input, &idx, &boolLength, sz) < 0) { - CYASSL_MSG("\tfail: critical boolean length"); - return ASN_PARSE_E; - } - if (input[idx++]) - critical = 1; - } - - /* process the extension based on the OID */ - if (input[idx++] != ASN_OCTET_STRING) { - CYASSL_MSG("\tfail: should be an OCTET STRING"); - return ASN_PARSE_E; - } - - if (GetLength(input, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: extension data length"); - return ASN_PARSE_E; - } - - switch (oid) { - case BASIC_CA_OID: - #ifdef OPENSSL_EXTRA - cert->extBasicConstSet = 1; - cert->extBasicConstCrit = critical; - #endif - if (DecodeBasicCaConstraint(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case CRL_DIST_OID: - if (DecodeCrlDist(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case AUTH_INFO_OID: - if (DecodeAuthInfo(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case ALT_NAMES_OID: - #ifdef OPENSSL_EXTRA - cert->extSubjAltNameSet = 1; - cert->extSubjAltNameCrit = critical; - #endif - if (DecodeAltNames(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case AUTH_KEY_OID: - cert->extAuthKeyIdSet = 1; - #ifdef OPENSSL_EXTRA - cert->extAuthKeyIdCrit = critical; - #endif - if (DecodeAuthKeyId(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case SUBJ_KEY_OID: - cert->extSubjKeyIdSet = 1; - #ifdef OPENSSL_EXTRA - cert->extSubjKeyIdCrit = critical; - #endif - if (DecodeSubjKeyId(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case CERT_POLICY_OID: - CYASSL_MSG("Certificate Policy extension not supported yet."); - #ifdef CYASSL_SEP - #ifdef OPENSSL_EXTRA - cert->extCertPolicySet = 1; - cert->extCertPolicyCrit = critical; - #endif - if (DecodeCertPolicy(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - #endif - break; - - case KEY_USAGE_OID: - cert->extKeyUsageSet = 1; - #ifdef OPENSSL_EXTRA - cert->extKeyUsageCrit = critical; - #endif - if (DecodeKeyUsage(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - case EXT_KEY_USAGE_OID: - cert->extExtKeyUsageSet = 1; - #ifdef OPENSSL_EXTRA - cert->extExtKeyUsageCrit = critical; - #endif - if (DecodeExtKeyUsage(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - - #ifndef IGNORE_NAME_CONSTRAINTS - case NAME_CONS_OID: - cert->extNameConstraintSet = 1; - #ifdef OPENSSL_EXTRA - cert->extNameConstraintCrit = critical; - #endif - if (DecodeNameConstraints(&input[idx], length, cert) < 0) - return ASN_PARSE_E; - break; - #endif /* IGNORE_NAME_CONSTRAINTS */ - - case INHIBIT_ANY_OID: - CYASSL_MSG("Inhibit anyPolicy extension not supported yet."); - break; - - default: - /* While it is a failure to not support critical extensions, - * still parse the certificate ignoring the unsupported - * extention to allow caller to accept it with the verify - * callback. */ - if (critical) - criticalFail = 1; - break; - } - idx += length; - } - - return criticalFail ? ASN_CRIT_EXT_E : 0; -} - - -int ParseCert(DecodedCert* cert, int type, int verify, void* cm) -{ - int ret; - char* ptr; - - ret = ParseCertRelative(cert, type, verify, cm); - if (ret < 0) - return ret; - - if (cert->subjectCNLen > 0) { - ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap, - DYNAMIC_TYPE_SUBJECT_CN); - if (ptr == NULL) - return MEMORY_E; - XMEMCPY(ptr, cert->subjectCN, cert->subjectCNLen); - ptr[cert->subjectCNLen] = '\0'; - cert->subjectCN = ptr; - cert->subjectCNStored = 1; - } - - if (cert->keyOID == RSAk && - cert->publicKey != NULL && cert->pubKeySize > 0) { - ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (ptr == NULL) - return MEMORY_E; - XMEMCPY(ptr, cert->publicKey, cert->pubKeySize); - cert->publicKey = (byte *)ptr; - cert->pubKeyStored = 1; - } - - return ret; -} - - -/* from SSL proper, for locking can't do find here anymore */ -#ifdef __cplusplus - extern "C" { -#endif - CYASSL_LOCAL Signer* GetCA(void* signers, byte* hash); - #ifndef NO_SKID - CYASSL_LOCAL Signer* GetCAByName(void* signers, byte* hash); - #endif -#ifdef __cplusplus - } -#endif - - -int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) -{ - word32 confirmOID; - int ret; - int badDate = 0; - int criticalExt = 0; - - if ((ret = DecodeToKey(cert, verify)) < 0) { - if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E) - badDate = ret; - else - return ret; - } - - CYASSL_MSG("Parsed Past Key"); - - if (cert->srcIdx < cert->sigIndex) { - #ifndef ALLOW_V1_EXTENSIONS - if (cert->version < 2) { - CYASSL_MSG(" v1 and v2 certs not allowed extensions"); - return ASN_VERSION_E; - } - #endif - /* save extensions */ - cert->extensions = &cert->source[cert->srcIdx]; - cert->extensionsSz = cert->sigIndex - cert->srcIdx; - cert->extensionsIdx = cert->srcIdx; /* for potential later use */ - - if ((ret = DecodeCertExtensions(cert)) < 0) { - if (ret == ASN_CRIT_EXT_E) - criticalExt = ret; - else - return ret; - } - - /* advance past extensions */ - cert->srcIdx = cert->sigIndex; - } - - if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID, - cert->maxIdx)) < 0) - return ret; - - if ((ret = GetSignature(cert)) < 0) - return ret; - - if (confirmOID != cert->signatureOID) - return ASN_SIG_OID_E; - - #ifndef NO_SKID - if (cert->extSubjKeyIdSet == 0 - && cert->publicKey != NULL && cert->pubKeySize > 0) { - Sha sha; - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, cert->publicKey, cert->pubKeySize); - ShaFinal(&sha, cert->extSubjKeyId); - } - #endif - - if (verify && type != CA_TYPE) { - Signer* ca = NULL; - #ifndef NO_SKID - if (cert->extAuthKeyIdSet) - ca = GetCA(cm, cert->extAuthKeyId); - if (ca == NULL) - ca = GetCAByName(cm, cert->issuerHash); - #else /* NO_SKID */ - ca = GetCA(cm, cert->issuerHash); - #endif /* NO SKID */ - CYASSL_MSG("About to verify certificate signature"); - - if (ca) { -#ifdef HAVE_OCSP - /* Need the ca's public key hash for OCSP */ - { - Sha sha; - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, ca->publicKey, ca->pubKeySize); - ShaFinal(&sha, cert->issuerKeyHash); - } -#endif /* HAVE_OCSP */ - /* try to confirm/verify signature */ - if (!ConfirmSignature(cert->source + cert->certBegin, - cert->sigIndex - cert->certBegin, - ca->publicKey, ca->pubKeySize, ca->keyOID, - cert->signature, cert->sigLength, cert->signatureOID, - cert->heap)) { - CYASSL_MSG("Confirm signature failed"); - return ASN_SIG_CONFIRM_E; - } -#ifndef IGNORE_NAME_CONSTRAINTS - /* check that this cert's name is permitted by the signer's - * name constraints */ - if (!ConfirmNameConstraints(ca, cert)) { - CYASSL_MSG("Confirm name constraint failed"); - return ASN_NAME_INVALID_E; - } -#endif /* IGNORE_NAME_CONSTRAINTS */ - } - else { - /* no signer */ - CYASSL_MSG("No CA signer to verify with"); - return ASN_NO_SIGNER_E; - } - } - - if (badDate != 0) - return badDate; - - if (criticalExt != 0) - return criticalExt; - - return 0; -} - - -/* Create and init an new signer */ -Signer* MakeSigner(void* heap) -{ - Signer* signer = (Signer*) XMALLOC(sizeof(Signer), heap, - DYNAMIC_TYPE_SIGNER); - if (signer) { - signer->pubKeySize = 0; - signer->keyOID = 0; - signer->publicKey = NULL; - signer->nameLen = 0; - signer->name = NULL; - #ifndef IGNORE_NAME_CONSTRAINTS - signer->permittedNames = NULL; - signer->excludedNames = NULL; - #endif /* IGNORE_NAME_CONSTRAINTS */ - signer->next = NULL; - } - (void)heap; - - return signer; -} - - -/* Free an individual signer */ -void FreeSigner(Signer* signer, void* heap) -{ - XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN); - XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); - #ifndef IGNORE_NAME_CONSTRAINTS - if (signer->permittedNames) - FreeNameSubtrees(signer->permittedNames, heap); - if (signer->excludedNames) - FreeNameSubtrees(signer->excludedNames, heap); - #endif - XFREE(signer, heap, DYNAMIC_TYPE_SIGNER); - - (void)heap; -} - - -/* Free the whole singer table with number of rows */ -void FreeSignerTable(Signer** table, int rows, void* heap) -{ - int i; - - for (i = 0; i < rows; i++) { - Signer* signer = table[i]; - while (signer) { - Signer* next = signer->next; - FreeSigner(signer, heap); - signer = next; - } - table[i] = NULL; - } -} - - -CYASSL_LOCAL int SetMyVersion(word32 version, byte* output, int header) -{ - int i = 0; - - if (header) { - output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED; - output[i++] = ASN_BIT_STRING; - } - output[i++] = ASN_INTEGER; - output[i++] = 0x01; - output[i++] = (byte)version; - - return i; -} - - -CYASSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output) -{ - int result = 0; - - CYASSL_ENTER("SetSerialNumber"); - - if (snSz <= EXTERNAL_SERIAL_SIZE) { - output[0] = ASN_INTEGER; - /* The serial number is always positive. When encoding the - * INTEGER, if the MSB is 1, add a padding zero to keep the - * number positive. */ - if (sn[0] & 0x80) { - output[1] = (byte)snSz + 1; - output[2] = 0; - XMEMCPY(&output[3], sn, snSz); - result = snSz + 3; - } - else { - output[1] = (byte)snSz; - XMEMCPY(&output[2], sn, snSz); - result = snSz + 2; - } - } - return result; -} - - - - -#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) - -/* convert der buffer to pem into output, can't do inplace, der and output - need to be different */ -int DerToPem(const byte* der, word32 derSz, byte* output, word32 outSz, - int type) -{ - char header[80]; - char footer[80]; - - int headerLen; - int footerLen; - int i; - int err; - int outLen; /* return length or error */ - - if (der == output) /* no in place conversion */ - return BAD_FUNC_ARG; - - if (type == CERT_TYPE) { - XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", sizeof(header)); - XSTRNCPY(footer, "-----END CERTIFICATE-----\n", sizeof(footer)); - } - else if (type == PRIVATEKEY_TYPE) { - XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", sizeof(header)); - XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n", sizeof(footer)); - } - #ifdef HAVE_ECC - else if (type == ECC_PRIVATEKEY_TYPE) { - XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----\n", sizeof(header)); - XSTRNCPY(footer, "-----END EC PRIVATE KEY-----\n", sizeof(footer)); - } - #endif - #ifdef CYASSL_CERT_REQ - else if (type == CERTREQ_TYPE) - { - XSTRNCPY(header, - "-----BEGIN CERTIFICATE REQUEST-----\n", sizeof(header)); - XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----\n", sizeof(footer)); - } - #endif - else - return BAD_FUNC_ARG; - - headerLen = (int)XSTRLEN(header); - footerLen = (int)XSTRLEN(footer); - - if (!der || !output) - return BAD_FUNC_ARG; - - /* don't even try if outSz too short */ - if (outSz < headerLen + footerLen + derSz) - return BAD_FUNC_ARG; - - /* header */ - XMEMCPY(output, header, headerLen); - i = headerLen; - - /* body */ - outLen = outSz - (headerLen + footerLen); /* input to Base64_Encode */ - if ( (err = Base64_Encode(der, derSz, output + i, (word32*)&outLen)) < 0) - return err; - i += outLen; - - /* footer */ - if ( (i + footerLen) > (int)outSz) - return BAD_FUNC_ARG; - XMEMCPY(output + i, footer, footerLen); - - return outLen + headerLen + footerLen; -} - - -#endif /* CYASSL_KEY_GEN || CYASSL_CERT_GEN */ - - -#if defined(CYASSL_KEY_GEN) && !defined(NO_RSA) - - -static mp_int* GetRsaInt(RsaKey* key, int idx) -{ - if (idx == 0) - return &key->n; - if (idx == 1) - return &key->e; - if (idx == 2) - return &key->d; - if (idx == 3) - return &key->p; - if (idx == 4) - return &key->q; - if (idx == 5) - return &key->dP; - if (idx == 6) - return &key->dQ; - if (idx == 7) - return &key->u; - - return NULL; -} - - -/* Release Tmp RSA resources */ -static INLINE void FreeTmpRsas(byte** tmps, void* heap) -{ - int i; - - (void)heap; - - for (i = 0; i < RSA_INTS; i++) - XFREE(tmps[i], heap, DYNAMIC_TYPE_RSA); -} - - -/* Convert RsaKey key to DER format, write to output (inLen), return bytes - written */ -int RsaKeyToDer(RsaKey* key, byte* output, word32 inLen) -{ - word32 seqSz, verSz, rawLen, intTotalLen = 0; - word32 sizes[RSA_INTS]; - int i, j, outLen, ret = 0; - - byte seq[MAX_SEQ_SZ]; - byte ver[MAX_VERSION_SZ]; - byte* tmps[RSA_INTS]; - - if (!key || !output) - return BAD_FUNC_ARG; - - if (key->type != RSA_PRIVATE) - return BAD_FUNC_ARG; - - for (i = 0; i < RSA_INTS; i++) - tmps[i] = NULL; - - /* write all big ints from key to DER tmps */ - for (i = 0; i < RSA_INTS; i++) { - mp_int* keyInt = GetRsaInt(key, i); - rawLen = mp_unsigned_bin_size(keyInt); - tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap, - DYNAMIC_TYPE_RSA); - if (tmps[i] == NULL) { - ret = MEMORY_E; - break; - } - - tmps[i][0] = ASN_INTEGER; - sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1; /* int tag */ - - if (sizes[i] <= MAX_SEQ_SZ) { - int err = mp_to_unsigned_bin(keyInt, tmps[i] + sizes[i]); - if (err == MP_OKAY) { - sizes[i] += rawLen; - intTotalLen += sizes[i]; - } - else { - ret = err; - break; - } - } - else { - ret = ASN_INPUT_E; - break; - } - } - - if (ret != 0) { - FreeTmpRsas(tmps, key->heap); - return ret; - } - - /* make headers */ - verSz = SetMyVersion(0, ver, FALSE); - seqSz = SetSequence(verSz + intTotalLen, seq); - - outLen = seqSz + verSz + intTotalLen; - if (outLen > (int)inLen) - return BAD_FUNC_ARG; - - /* write to output */ - XMEMCPY(output, seq, seqSz); - j = seqSz; - XMEMCPY(output + j, ver, verSz); - j += verSz; - - for (i = 0; i < RSA_INTS; i++) { - XMEMCPY(output + j, tmps[i], sizes[i]); - j += sizes[i]; - } - FreeTmpRsas(tmps, key->heap); - - return outLen; -} - -#endif /* CYASSL_KEY_GEN && !NO_RSA */ - - -#if defined(CYASSL_CERT_GEN) && !defined(NO_RSA) - - -#ifndef min - - static INLINE word32 min(word32 a, word32 b) - { - return a > b ? b : a; - } - -#endif /* min */ - - -/* Initialize and Set Certficate defaults: - version = 3 (0x2) - serial = 0 - sigType = SHA_WITH_RSA - issuer = blank - daysValid = 500 - selfSigned = 1 (true) use subject as issuer - subject = blank -*/ -void InitCert(Cert* cert) -{ - cert->version = 2; /* version 3 is hex 2 */ - cert->sigType = CTC_SHAwRSA; - cert->daysValid = 500; - cert->selfSigned = 1; - cert->isCA = 0; - cert->bodySz = 0; -#ifdef CYASSL_ALT_NAMES - cert->altNamesSz = 0; - cert->beforeDateSz = 0; - cert->afterDateSz = 0; -#endif - cert->keyType = RSA_KEY; - XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE); - - cert->issuer.country[0] = '\0'; - cert->issuer.state[0] = '\0'; - cert->issuer.locality[0] = '\0'; - cert->issuer.sur[0] = '\0'; - cert->issuer.org[0] = '\0'; - cert->issuer.unit[0] = '\0'; - cert->issuer.commonName[0] = '\0'; - cert->issuer.email[0] = '\0'; - - cert->subject.country[0] = '\0'; - cert->subject.state[0] = '\0'; - cert->subject.locality[0] = '\0'; - cert->subject.sur[0] = '\0'; - cert->subject.org[0] = '\0'; - cert->subject.unit[0] = '\0'; - cert->subject.commonName[0] = '\0'; - cert->subject.email[0] = '\0'; - -#ifdef CYASSL_CERT_REQ - cert->challengePw[0] ='\0'; -#endif -} - - -/* DER encoded x509 Certificate */ -typedef struct DerCert { - byte size[MAX_LENGTH_SZ]; /* length encoded */ - byte version[MAX_VERSION_SZ]; /* version encoded */ - byte serial[CTC_SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */ - byte sigAlgo[MAX_ALGO_SZ]; /* signature algo encoded */ - byte issuer[ASN_NAME_MAX]; /* issuer encoded */ - byte subject[ASN_NAME_MAX]; /* subject encoded */ - byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2]; /* before and after dates */ - byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */ - byte ca[MAX_CA_SZ]; /* basic constraint CA true size */ - byte extensions[MAX_EXTENSIONS_SZ]; /* all extensions */ -#ifdef CYASSL_CERT_REQ - byte attrib[MAX_ATTRIB_SZ]; /* Cert req attributes encoded */ -#endif - int sizeSz; /* encoded size length */ - int versionSz; /* encoded version length */ - int serialSz; /* encoded serial length */ - int sigAlgoSz; /* enocded sig alog length */ - int issuerSz; /* encoded issuer length */ - int subjectSz; /* encoded subject length */ - int validitySz; /* encoded validity length */ - int publicKeySz; /* encoded public key length */ - int caSz; /* encoded CA extension length */ - int extensionsSz; /* encoded extensions total length */ - int total; /* total encoded lengths */ -#ifdef CYASSL_CERT_REQ - int attribSz; -#endif -} DerCert; - - -#ifdef CYASSL_CERT_REQ - -/* Write a set header to output */ -static word32 SetUTF8String(word32 len, byte* output) -{ - output[0] = ASN_UTF8STRING; - return SetLength(len, output + 1) + 1; -} - -#endif /* CYASSL_CERT_REQ */ - - -/* Write a serial number to output */ -static int SetSerial(const byte* serial, byte* output) -{ - int length = 0; - - output[length++] = ASN_INTEGER; - length += SetLength(CTC_SERIAL_SIZE, &output[length]); - XMEMCPY(&output[length], serial, CTC_SERIAL_SIZE); - - return length + CTC_SERIAL_SIZE; -} - - -#ifdef HAVE_ECC - -/* Write a public ECC key to output */ -static int SetEccPublicKey(byte* output, ecc_key* key) -{ - byte algo[MAX_ALGO_SZ]; - byte curve[MAX_ALGO_SZ]; - byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ - byte pub[ECC_BUFSIZE]; - int algoSz; - int curveSz; - int lenSz; - int idx; - word32 pubSz = sizeof(pub); - - int ret = ecc_export_x963(key, pub, &pubSz); - if (ret != 0) return ret; - - /* headers */ - curveSz = SetCurve(key, curve); - if (curveSz <= 0) return curveSz; - - algoSz = SetAlgoID(ECDSAk, algo, keyType, curveSz); - lenSz = SetLength(pubSz + 1, len); - len[lenSz++] = 0; /* trailing 0 */ - - /* write */ - idx = SetSequence(pubSz + curveSz + lenSz + 1 + algoSz, output); - /* 1 is for ASN_BIT_STRING */ - /* algo */ - XMEMCPY(output + idx, algo, algoSz); - idx += algoSz; - /* curve */ - XMEMCPY(output + idx, curve, curveSz); - idx += curveSz; - /* bit string */ - output[idx++] = ASN_BIT_STRING; - /* length */ - XMEMCPY(output + idx, len, lenSz); - idx += lenSz; - /* pub */ - XMEMCPY(output + idx, pub, pubSz); - idx += pubSz; - - return idx; -} - - -#endif /* HAVE_ECC */ - - -/* Write a public RSA key to output */ -static int SetRsaPublicKey(byte* output, RsaKey* key) -{ - byte n[MAX_RSA_INT_SZ]; - byte e[MAX_RSA_E_SZ]; - byte algo[MAX_ALGO_SZ]; - byte seq[MAX_SEQ_SZ]; - byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ - int nSz; - int eSz; - int algoSz; - int seqSz; - int lenSz; - int idx; - int rawLen; - int leadingBit; - int err; - - /* n */ - leadingBit = mp_leading_bit(&key->n); - rawLen = mp_unsigned_bin_size(&key->n) + leadingBit; - n[0] = ASN_INTEGER; - nSz = SetLength(rawLen, n + 1) + 1; /* int tag */ - - if ( (nSz + rawLen) < (int)sizeof(n)) { - if (leadingBit) - n[nSz] = 0; - err = mp_to_unsigned_bin(&key->n, n + nSz + leadingBit); - if (err == MP_OKAY) - nSz += rawLen; - else - return MP_TO_E; - } - else - return BUFFER_E; - - /* e */ - leadingBit = mp_leading_bit(&key->e); - rawLen = mp_unsigned_bin_size(&key->e) + leadingBit; - e[0] = ASN_INTEGER; - eSz = SetLength(rawLen, e + 1) + 1; /* int tag */ - - if ( (eSz + rawLen) < (int)sizeof(e)) { - if (leadingBit) - e[eSz] = 0; - err = mp_to_unsigned_bin(&key->e, e + eSz + leadingBit); - if (err == MP_OKAY) - eSz += rawLen; - else - return MP_TO_E; - } - else - return BUFFER_E; - - /* headers */ - algoSz = SetAlgoID(RSAk, algo, keyType, 0); - seqSz = SetSequence(nSz + eSz, seq); - lenSz = SetLength(seqSz + nSz + eSz + 1, len); - len[lenSz++] = 0; /* trailing 0 */ - - /* write */ - idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output); - /* 1 is for ASN_BIT_STRING */ - /* algo */ - XMEMCPY(output + idx, algo, algoSz); - idx += algoSz; - /* bit string */ - output[idx++] = ASN_BIT_STRING; - /* length */ - XMEMCPY(output + idx, len, lenSz); - idx += lenSz; - /* seq */ - XMEMCPY(output + idx, seq, seqSz); - idx += seqSz; - /* n */ - XMEMCPY(output + idx, n, nSz); - idx += nSz; - /* e */ - XMEMCPY(output + idx, e, eSz); - idx += eSz; - - return idx; -} - - -static INLINE byte itob(int number) -{ - return (byte)number + 0x30; -} - - -/* write time to output, format */ -static void SetTime(struct tm* date, byte* output) -{ - int i = 0; - - output[i++] = itob((date->tm_year % 10000) / 1000); - output[i++] = itob((date->tm_year % 1000) / 100); - output[i++] = itob((date->tm_year % 100) / 10); - output[i++] = itob( date->tm_year % 10); - - output[i++] = itob(date->tm_mon / 10); - output[i++] = itob(date->tm_mon % 10); - - output[i++] = itob(date->tm_mday / 10); - output[i++] = itob(date->tm_mday % 10); - - output[i++] = itob(date->tm_hour / 10); - output[i++] = itob(date->tm_hour % 10); - - output[i++] = itob(date->tm_min / 10); - output[i++] = itob(date->tm_min % 10); - - output[i++] = itob(date->tm_sec / 10); - output[i++] = itob(date->tm_sec % 10); - - output[i] = 'Z'; /* Zulu profile */ -} - - -#ifdef CYASSL_ALT_NAMES - -/* Copy Dates from cert, return bytes written */ -static int CopyValidity(byte* output, Cert* cert) -{ - int seqSz; - - CYASSL_ENTER("CopyValidity"); - - /* headers and output */ - seqSz = SetSequence(cert->beforeDateSz + cert->afterDateSz, output); - XMEMCPY(output + seqSz, cert->beforeDate, cert->beforeDateSz); - XMEMCPY(output + seqSz + cert->beforeDateSz, cert->afterDate, - cert->afterDateSz); - return seqSz + cert->beforeDateSz + cert->afterDateSz; -} - -#endif - - -/* Set Date validity from now until now + daysValid */ -static int SetValidity(byte* output, int daysValid) -{ - byte before[MAX_DATE_SIZE]; - byte after[MAX_DATE_SIZE]; - - int beforeSz; - int afterSz; - int seqSz; - - time_t ticks; - struct tm* now; - struct tm local; - - ticks = XTIME(0); - now = XGMTIME(&ticks); - - /* before now */ - local = *now; - before[0] = ASN_GENERALIZED_TIME; - beforeSz = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1; /* gen tag */ - - /* subtract 1 day for more compliance */ - local.tm_mday -= 1; - mktime(&local); - - /* adjust */ - local.tm_year += 1900; - local.tm_mon += 1; - - SetTime(&local, before + beforeSz); - beforeSz += ASN_GEN_TIME_SZ; - - /* after now + daysValid */ - local = *now; - after[0] = ASN_GENERALIZED_TIME; - afterSz = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1; /* gen tag */ - - /* add daysValid */ - local.tm_mday += daysValid; - mktime(&local); - - /* adjust */ - local.tm_year += 1900; - local.tm_mon += 1; - - SetTime(&local, after + afterSz); - afterSz += ASN_GEN_TIME_SZ; - - /* headers and output */ - seqSz = SetSequence(beforeSz + afterSz, output); - XMEMCPY(output + seqSz, before, beforeSz); - XMEMCPY(output + seqSz + beforeSz, after, afterSz); - - return seqSz + beforeSz + afterSz; -} - - -/* ASN Encoded Name field */ -typedef struct EncodedName { - int nameLen; /* actual string value length */ - int totalLen; /* total encoded length */ - int type; /* type of name */ - int used; /* are we actually using this one */ - byte encoded[CTC_NAME_SIZE * 2]; /* encoding */ -} EncodedName; - - -/* Get Which Name from index */ -static const char* GetOneName(CertName* name, int idx) -{ - switch (idx) { - case 0: - return name->country; - - case 1: - return name->state; - - case 2: - return name->locality; - - case 3: - return name->sur; - - case 4: - return name->org; - - case 5: - return name->unit; - - case 6: - return name->commonName; - - case 7: - return name->email; - - default: - return 0; - } -} - - -/* Get ASN Name from index */ -static byte GetNameId(int idx) -{ - switch (idx) { - case 0: - return ASN_COUNTRY_NAME; - - case 1: - return ASN_STATE_NAME; - - case 2: - return ASN_LOCALITY_NAME; - - case 3: - return ASN_SUR_NAME; - - case 4: - return ASN_ORG_NAME; - - case 5: - return ASN_ORGUNIT_NAME; - - case 6: - return ASN_COMMON_NAME; - - case 7: - /* email uses different id type */ - return 0; - - default: - return 0; - } -} - - -/* encode all extensions, return total bytes written */ -static int SetExtensions(byte* output, const byte* ext, int extSz, int header) -{ - byte sequence[MAX_SEQ_SZ]; - byte len[MAX_LENGTH_SZ]; - - int sz = 0; - int seqSz = SetSequence(extSz, sequence); - - if (header) { - int lenSz = SetLength(seqSz + extSz, len); - output[0] = ASN_EXTENSIONS; /* extensions id */ - sz++; - XMEMCPY(&output[sz], len, lenSz); /* length */ - sz += lenSz; - } - XMEMCPY(&output[sz], sequence, seqSz); /* sequence */ - sz += seqSz; - XMEMCPY(&output[sz], ext, extSz); /* extensions */ - sz += extSz; - - return sz; -} - - -/* encode CA basic constraint true, return total bytes written */ -static int SetCa(byte* output) -{ - static const byte ca[] = { 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, - 0x05, 0x30, 0x03, 0x01, 0x01, 0xff }; - - XMEMCPY(output, ca, sizeof(ca)); - - return (int)sizeof(ca); -} - - -/* encode CertName into output, return total bytes written */ -static int SetName(byte* output, CertName* name) -{ - int totalBytes = 0, i, idx; - EncodedName names[NAME_ENTRIES]; - - for (i = 0; i < NAME_ENTRIES; i++) { - const char* nameStr = GetOneName(name, i); - if (nameStr) { - /* bottom up */ - byte firstLen[MAX_LENGTH_SZ]; - byte secondLen[MAX_LENGTH_SZ]; - byte sequence[MAX_SEQ_SZ]; - byte set[MAX_SET_SZ]; - - int email = i == (NAME_ENTRIES - 1) ? 1 : 0; - int strLen = (int)XSTRLEN(nameStr); - int thisLen = strLen; - int firstSz, secondSz, seqSz, setSz; - - if (strLen == 0) { /* no user data for this item */ - names[i].used = 0; - continue; - } - - secondSz = SetLength(strLen, secondLen); - thisLen += secondSz; - if (email) { - thisLen += EMAIL_JOINT_LEN; - thisLen ++; /* id type */ - firstSz = SetLength(EMAIL_JOINT_LEN, firstLen); - } - else { - thisLen++; /* str type */ - thisLen++; /* id type */ - thisLen += JOINT_LEN; - firstSz = SetLength(JOINT_LEN + 1, firstLen); - } - thisLen += firstSz; - thisLen++; /* object id */ - - seqSz = SetSequence(thisLen, sequence); - thisLen += seqSz; - setSz = SetSet(thisLen, set); - thisLen += setSz; - - if (thisLen > (int)sizeof(names[i].encoded)) - return BUFFER_E; - - /* store it */ - idx = 0; - /* set */ - XMEMCPY(names[i].encoded, set, setSz); - idx += setSz; - /* seq */ - XMEMCPY(names[i].encoded + idx, sequence, seqSz); - idx += seqSz; - /* asn object id */ - names[i].encoded[idx++] = ASN_OBJECT_ID; - /* first length */ - XMEMCPY(names[i].encoded + idx, firstLen, firstSz); - idx += firstSz; - if (email) { - const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x09, 0x01, 0x16 }; - /* email joint id */ - XMEMCPY(names[i].encoded + idx, EMAIL_OID, sizeof(EMAIL_OID)); - idx += (int)sizeof(EMAIL_OID); - } - else { - /* joint id */ - byte bType = GetNameId(i); - names[i].encoded[idx++] = 0x55; - names[i].encoded[idx++] = 0x04; - /* id type */ - names[i].encoded[idx++] = bType; - /* str type */ - if (bType == ASN_COUNTRY_NAME) - names[i].encoded[idx++] = 0x13; /* printable */ - else - names[i].encoded[idx++] = 0x0c; /* utf8 */ - } - /* second length */ - XMEMCPY(names[i].encoded + idx, secondLen, secondSz); - idx += secondSz; - /* str value */ - XMEMCPY(names[i].encoded + idx, nameStr, strLen); - idx += strLen; - - totalBytes += idx; - names[i].totalLen = idx; - names[i].used = 1; - } - else - names[i].used = 0; - } - - /* header */ - idx = SetSequence(totalBytes, output); - totalBytes += idx; - if (totalBytes > ASN_NAME_MAX) - return BUFFER_E; - - for (i = 0; i < NAME_ENTRIES; i++) { - if (names[i].used) { - XMEMCPY(output + idx, names[i].encoded, names[i].totalLen); - idx += names[i].totalLen; - } - } - return totalBytes; -} - -/* encode info from cert into DER encoded format */ -static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, - RNG* rng, const byte* ntruKey, word16 ntruSz) -{ - int ret; - - (void)eccKey; - (void)ntruKey; - (void)ntruSz; - - /* init */ - XMEMSET(der, 0, sizeof(DerCert)); - - /* version */ - der->versionSz = SetMyVersion(cert->version, der->version, TRUE); - - /* serial number */ - ret = RNG_GenerateBlock(rng, cert->serial, CTC_SERIAL_SIZE); - if (ret != 0) - return ret; - - cert->serial[0] = 0x01; /* ensure positive */ - der->serialSz = SetSerial(cert->serial, der->serial); - - /* signature algo */ - der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType, 0); - if (der->sigAlgoSz == 0) - return ALGO_ID_E; - - /* public key */ - if (cert->keyType == RSA_KEY) { - if (rsaKey == NULL) - return PUBLIC_KEY_E; - der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey); - if (der->publicKeySz <= 0) - return PUBLIC_KEY_E; - } - -#ifdef HAVE_ECC - if (cert->keyType == ECC_KEY) { - if (eccKey == NULL) - return PUBLIC_KEY_E; - der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey); - if (der->publicKeySz <= 0) - return PUBLIC_KEY_E; - } -#endif /* HAVE_ECC */ - -#ifdef HAVE_NTRU - if (cert->keyType == NTRU_KEY) { - word32 rc; - word16 encodedSz; - - rc = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz, - ntruKey, &encodedSz, NULL); - if (rc != NTRU_OK) - return PUBLIC_KEY_E; - if (encodedSz > MAX_PUBLIC_KEY_SZ) - return PUBLIC_KEY_E; - - rc = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz, - ntruKey, &encodedSz, der->publicKey); - if (rc != NTRU_OK) - return PUBLIC_KEY_E; - - der->publicKeySz = encodedSz; - } -#endif /* HAVE_NTRU */ - - der->validitySz = 0; -#ifdef CYASSL_ALT_NAMES - /* date validity copy ? */ - if (cert->beforeDateSz && cert->afterDateSz) { - der->validitySz = CopyValidity(der->validity, cert); - if (der->validitySz == 0) - return DATE_E; - } -#endif - - /* date validity */ - if (der->validitySz == 0) { - der->validitySz = SetValidity(der->validity, cert->daysValid); - if (der->validitySz == 0) - return DATE_E; - } - - /* subject name */ - der->subjectSz = SetName(der->subject, &cert->subject); - if (der->subjectSz == 0) - return SUBJECT_E; - - /* issuer name */ - der->issuerSz = SetName(der->issuer, cert->selfSigned ? - &cert->subject : &cert->issuer); - if (der->issuerSz == 0) - return ISSUER_E; - - /* CA */ - if (cert->isCA) { - der->caSz = SetCa(der->ca); - if (der->caSz == 0) - return CA_TRUE_E; - } - else - der->caSz = 0; - - /* extensions, just CA now */ - if (cert->isCA) { - der->extensionsSz = SetExtensions(der->extensions, - der->ca, der->caSz, TRUE); - if (der->extensionsSz == 0) - return EXTENSIONS_E; - } - else - der->extensionsSz = 0; - -#ifdef CYASSL_ALT_NAMES - if (der->extensionsSz == 0 && cert->altNamesSz) { - der->extensionsSz = SetExtensions(der->extensions, cert->altNames, - cert->altNamesSz, TRUE); - if (der->extensionsSz == 0) - return EXTENSIONS_E; - } -#endif - - der->total = der->versionSz + der->serialSz + der->sigAlgoSz + - der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz + - der->extensionsSz; - - return 0; -} - - -/* write DER encoded cert to buffer, size already checked */ -static int WriteCertBody(DerCert* der, byte* buffer) -{ - int idx; - - /* signed part header */ - idx = SetSequence(der->total, buffer); - /* version */ - XMEMCPY(buffer + idx, der->version, der->versionSz); - idx += der->versionSz; - /* serial */ - XMEMCPY(buffer + idx, der->serial, der->serialSz); - idx += der->serialSz; - /* sig algo */ - XMEMCPY(buffer + idx, der->sigAlgo, der->sigAlgoSz); - idx += der->sigAlgoSz; - /* issuer */ - XMEMCPY(buffer + idx, der->issuer, der->issuerSz); - idx += der->issuerSz; - /* validity */ - XMEMCPY(buffer + idx, der->validity, der->validitySz); - idx += der->validitySz; - /* subject */ - XMEMCPY(buffer + idx, der->subject, der->subjectSz); - idx += der->subjectSz; - /* public key */ - XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz); - idx += der->publicKeySz; - if (der->extensionsSz) { - /* extensions */ - XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz, - sizeof(der->extensions))); - idx += der->extensionsSz; - } - - return idx; -} - - -/* Make RSA signature from buffer (sz), write to sig (sigSz) */ -static int MakeSignature(const byte* buffer, int sz, byte* sig, int sigSz, - RsaKey* rsaKey, ecc_key* eccKey, RNG* rng, - int sigAlgoType) -{ - byte digest[SHA256_DIGEST_SIZE]; /* max size */ - byte encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ]; - int encSigSz, digestSz, typeH, ret = 0; - - (void)eccKey; - - if (sigAlgoType == CTC_MD5wRSA) { - Md5 md5; - - InitMd5(&md5); - Md5Update(&md5, buffer, sz); - Md5Final(&md5, digest); - - digestSz = MD5_DIGEST_SIZE; - typeH = MD5h; - } - else if (sigAlgoType == CTC_SHAwRSA || sigAlgoType == CTC_SHAwECDSA) { - Sha sha; - - ret = InitSha(&sha); - if (ret != 0) - return ret; - - ShaUpdate(&sha, buffer, sz); - ShaFinal(&sha, digest); - - digestSz = SHA_DIGEST_SIZE; - typeH = SHAh; - } - else if (sigAlgoType == CTC_SHA256wRSA || sigAlgoType == CTC_SHA256wECDSA) { - Sha256 sha256; - - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - - ret = Sha256Update(&sha256, buffer, sz); - if (ret != 0) - return ret; - - ret = Sha256Final(&sha256, digest); - if (ret != 0) - return ret; - - digestSz = SHA256_DIGEST_SIZE; - typeH = SHA256h; - } - else - return ALGO_ID_E; - - if (rsaKey) { - /* signature */ - encSigSz = EncodeSignature(encSig, digest, digestSz, typeH); - return RsaSSL_Sign(encSig, encSigSz, sig, sigSz, rsaKey, rng); - } -#ifdef HAVE_ECC - else if (eccKey) { - word32 outSz = sigSz; - ret = ecc_sign_hash(digest, digestSz, sig, &outSz, rng, eccKey); - - if (ret != 0) - return ret; - return outSz; - } -#endif /* HAVE_ECC */ - - return ALGO_ID_E; -} - - -/* add signature to end of buffer, size of buffer assumed checked, return - new length */ -static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz, - int sigAlgoType) -{ - byte seq[MAX_SEQ_SZ]; - int idx = bodySz, seqSz; - - /* algo */ - idx += SetAlgoID(sigAlgoType, buffer + idx, sigType, 0); - /* bit string */ - buffer[idx++] = ASN_BIT_STRING; - /* length */ - idx += SetLength(sigSz + 1, buffer + idx); - buffer[idx++] = 0; /* trailing 0 */ - /* signature */ - XMEMCPY(buffer + idx, sig, sigSz); - idx += sigSz; - - /* make room for overall header */ - seqSz = SetSequence(idx, seq); - XMEMMOVE(buffer + seqSz, buffer, idx); - XMEMCPY(buffer, seq, seqSz); - - return idx + seqSz; -} - - -/* Make an x509 Certificate v3 any key type from cert input, write to buffer */ -static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, - RsaKey* rsaKey, ecc_key* eccKey, RNG* rng, - const byte* ntruKey, word16 ntruSz) -{ - DerCert der; - int ret; - - if (eccKey) - cert->keyType = ECC_KEY; - else - cert->keyType = rsaKey ? RSA_KEY : NTRU_KEY; - ret = EncodeCert(cert, &der, rsaKey, eccKey, rng, ntruKey, ntruSz); - if (ret != 0) - return ret; - - if (der.total + MAX_SEQ_SZ * 2 > (int)derSz) - return BUFFER_E; - - return cert->bodySz = WriteCertBody(&der, derBuffer); -} - - -/* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */ -int MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, - ecc_key* eccKey, RNG* rng) -{ - return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, 0); -} - - -#ifdef HAVE_NTRU - -int MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz, - const byte* ntruKey, word16 keySz, RNG* rng) -{ - return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz); -} - -#endif /* HAVE_NTRU */ - - -#ifdef CYASSL_CERT_REQ - -static int SetReqAttrib(byte* output, char* pw, int extSz) -{ - static const byte cpOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x07 }; - static const byte erOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x0e }; - - int sz = 0; /* overall size */ - int cpSz = 0; /* Challenge Password section size */ - int cpSeqSz = 0; - int cpSetSz = 0; - int cpStrSz = 0; - int pwSz = 0; - int erSz = 0; /* Extension Request section size */ - int erSeqSz = 0; - int erSetSz = 0; - byte cpSeq[MAX_SEQ_SZ]; - byte cpSet[MAX_SET_SZ]; - byte cpStr[MAX_PRSTR_SZ]; - byte erSeq[MAX_SEQ_SZ]; - byte erSet[MAX_SET_SZ]; - - output[0] = 0xa0; - sz++; - - if (pw && pw[0]) { - pwSz = (int)XSTRLEN(pw); - cpStrSz = SetUTF8String(pwSz, cpStr); - cpSetSz = SetSet(cpStrSz + pwSz, cpSet); - cpSeqSz = SetSequence(sizeof(cpOid) + cpSetSz + cpStrSz + pwSz, cpSeq); - cpSz = cpSeqSz + sizeof(cpOid) + cpSetSz + cpStrSz + pwSz; - } - - if (extSz) { - erSetSz = SetSet(extSz, erSet); - erSeqSz = SetSequence(erSetSz + sizeof(erOid) + extSz, erSeq); - erSz = extSz + erSetSz + erSeqSz + sizeof(erOid); - } - - /* Put the pieces together. */ - sz += SetLength(cpSz + erSz, &output[sz]); - - if (cpSz) { - XMEMCPY(&output[sz], cpSeq, cpSeqSz); - sz += cpSeqSz; - XMEMCPY(&output[sz], cpOid, sizeof(cpOid)); - sz += sizeof(cpOid); - XMEMCPY(&output[sz], cpSet, cpSetSz); - sz += cpSetSz; - XMEMCPY(&output[sz], cpStr, cpStrSz); - sz += cpStrSz; - XMEMCPY(&output[sz], pw, pwSz); - sz += pwSz; - } - - if (erSz) { - XMEMCPY(&output[sz], erSeq, erSeqSz); - sz += erSeqSz; - XMEMCPY(&output[sz], erOid, sizeof(erOid)); - sz += sizeof(erOid); - XMEMCPY(&output[sz], erSet, erSetSz); - sz += erSetSz; - /* The actual extension data will be tacked onto the output later. */ - } - - return sz; -} - - -/* encode info from cert into DER encoded format */ -static int EncodeCertReq(Cert* cert, DerCert* der, - RsaKey* rsaKey, ecc_key* eccKey) -{ - (void)eccKey; - - /* init */ - XMEMSET(der, 0, sizeof(DerCert)); - - /* version */ - der->versionSz = SetMyVersion(cert->version, der->version, FALSE); - - /* subject name */ - der->subjectSz = SetName(der->subject, &cert->subject); - if (der->subjectSz == 0) - return SUBJECT_E; - - /* public key */ - if (cert->keyType == RSA_KEY) { - if (rsaKey == NULL) - return PUBLIC_KEY_E; - der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey); - if (der->publicKeySz <= 0) - return PUBLIC_KEY_E; - } - -#ifdef HAVE_ECC - if (cert->keyType == ECC_KEY) { - if (eccKey == NULL) - return PUBLIC_KEY_E; - der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey); - if (der->publicKeySz <= 0) - return PUBLIC_KEY_E; - } -#endif /* HAVE_ECC */ - - /* CA */ - if (cert->isCA) { - der->caSz = SetCa(der->ca); - if (der->caSz == 0) - return CA_TRUE_E; - } - else - der->caSz = 0; - - /* extensions, just CA now */ - if (cert->isCA) { - der->extensionsSz = SetExtensions(der->extensions, - der->ca, der->caSz, FALSE); - if (der->extensionsSz == 0) - return EXTENSIONS_E; - } - else - der->extensionsSz = 0; - - der->attribSz = SetReqAttrib(der->attrib, - cert->challengePw, der->extensionsSz); - if (der->attribSz == 0) - return REQ_ATTRIBUTE_E; - - der->total = der->versionSz + der->subjectSz + der->publicKeySz + - der->extensionsSz + der->attribSz; - - return 0; -} - - -/* write DER encoded cert req to buffer, size already checked */ -static int WriteCertReqBody(DerCert* der, byte* buffer) -{ - int idx; - - /* signed part header */ - idx = SetSequence(der->total, buffer); - /* version */ - XMEMCPY(buffer + idx, der->version, der->versionSz); - idx += der->versionSz; - /* subject */ - XMEMCPY(buffer + idx, der->subject, der->subjectSz); - idx += der->subjectSz; - /* public key */ - XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz); - idx += der->publicKeySz; - /* attributes */ - XMEMCPY(buffer + idx, der->attrib, der->attribSz); - idx += der->attribSz; - /* extensions */ - if (der->extensionsSz) { - XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz, - sizeof(der->extensions))); - idx += der->extensionsSz; - } - - return idx; -} - - -int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, - RsaKey* rsaKey, ecc_key* eccKey) -{ - DerCert der; - int ret; - - cert->keyType = (eccKey != NULL) ? ECC_KEY : RSA_KEY; - ret = EncodeCertReq(cert, &der, rsaKey, eccKey); - if (ret != 0) - return ret; - - if (der.total + MAX_SEQ_SZ * 2 > (int)derSz) - return BUFFER_E; - - return cert->bodySz = WriteCertReqBody(&der, derBuffer); -} - -#endif /* CYASSL_CERT_REQ */ - - -int SignCert(int requestSz, int sType, byte* buffer, word32 buffSz, - RsaKey* rsaKey, ecc_key* eccKey, RNG* rng) -{ - byte sig[MAX_ENCODED_SIG_SZ]; - int sigSz; - - if (requestSz < 0) - return requestSz; - - sigSz = MakeSignature(buffer, requestSz, sig, sizeof(sig), rsaKey, eccKey, - rng, sType); - if (sigSz < 0) - return sigSz; - - if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz) - return BUFFER_E; - - return AddSignature(buffer, requestSz, sig, sigSz, sType); -} - - -int MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng) -{ - int ret = MakeCert(cert, buffer, buffSz, key, NULL, rng); - - if (ret < 0) - return ret; - - return SignCert(cert->bodySz, cert->sigType, buffer, buffSz, key, NULL,rng); -} - - -#ifdef CYASSL_ALT_NAMES - -/* Set Alt Names from der cert, return 0 on success */ -static int SetAltNamesFromCert(Cert* cert, const byte* der, int derSz) -{ - DecodedCert decoded; - int ret; - - if (derSz < 0) - return derSz; - - InitDecodedCert(&decoded, (byte*)der, derSz, 0); - ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0); - - if (ret < 0) { - FreeDecodedCert(&decoded); - return ret; - } - - if (decoded.extensions) { - byte b; - int length; - word32 maxExtensionsIdx; - - decoded.srcIdx = decoded.extensionsIdx; - b = decoded.source[decoded.srcIdx++]; - if (b != ASN_EXTENSIONS) { - FreeDecodedCert(&decoded); - return ASN_PARSE_E; - } - - if (GetLength(decoded.source, &decoded.srcIdx, &length, - decoded.maxIdx) < 0) { - FreeDecodedCert(&decoded); - return ASN_PARSE_E; - } - - if (GetSequence(decoded.source, &decoded.srcIdx, &length, - decoded.maxIdx) < 0) { - FreeDecodedCert(&decoded); - return ASN_PARSE_E; - } - - maxExtensionsIdx = decoded.srcIdx + length; - - while (decoded.srcIdx < maxExtensionsIdx) { - word32 oid; - word32 startIdx = decoded.srcIdx; - word32 tmpIdx; - - if (GetSequence(decoded.source, &decoded.srcIdx, &length, - decoded.maxIdx) < 0) { - FreeDecodedCert(&decoded); - return ASN_PARSE_E; - } - - tmpIdx = decoded.srcIdx; - decoded.srcIdx = startIdx; - - if (GetAlgoId(decoded.source, &decoded.srcIdx, &oid, - decoded.maxIdx) < 0) { - FreeDecodedCert(&decoded); - return ASN_PARSE_E; - } - - if (oid == ALT_NAMES_OID) { - cert->altNamesSz = length + (tmpIdx - startIdx); - - if (cert->altNamesSz < (int)sizeof(cert->altNames)) - XMEMCPY(cert->altNames, &decoded.source[startIdx], - cert->altNamesSz); - else { - cert->altNamesSz = 0; - CYASSL_MSG("AltNames extensions too big"); - FreeDecodedCert(&decoded); - return ALT_NAME_E; - } - } - decoded.srcIdx = tmpIdx + length; - } - } - FreeDecodedCert(&decoded); - - return 0; -} - - -/* Set Dates from der cert, return 0 on success */ -static int SetDatesFromCert(Cert* cert, const byte* der, int derSz) -{ - DecodedCert decoded; - int ret; - - CYASSL_ENTER("SetDatesFromCert"); - if (derSz < 0) - return derSz; - - InitDecodedCert(&decoded, (byte*)der, derSz, 0); - ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0); - - if (ret < 0) { - CYASSL_MSG("ParseCertRelative error"); - FreeDecodedCert(&decoded); - return ret; - } - - if (decoded.beforeDate == NULL || decoded.afterDate == NULL) { - CYASSL_MSG("Couldn't extract dates"); - FreeDecodedCert(&decoded); - return -1; - } - - if (decoded.beforeDateLen > MAX_DATE_SIZE || decoded.afterDateLen > - MAX_DATE_SIZE) { - CYASSL_MSG("Bad date size"); - FreeDecodedCert(&decoded); - return -1; - } - - XMEMCPY(cert->beforeDate, decoded.beforeDate, decoded.beforeDateLen); - XMEMCPY(cert->afterDate, decoded.afterDate, decoded.afterDateLen); - - cert->beforeDateSz = decoded.beforeDateLen; - cert->afterDateSz = decoded.afterDateLen; - - return 0; -} - - -#endif /* CYASSL_ALT_NAMES && !NO_RSA */ - - -/* Set cn name from der buffer, return 0 on success */ -static int SetNameFromCert(CertName* cn, const byte* der, int derSz) -{ - DecodedCert decoded; - int ret; - int sz; - - if (derSz < 0) - return derSz; - - InitDecodedCert(&decoded, (byte*)der, derSz, 0); - ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0); - - if (ret < 0) - return ret; - - if (decoded.subjectCN) { - sz = (decoded.subjectCNLen < CTC_NAME_SIZE) ? decoded.subjectCNLen : - CTC_NAME_SIZE - 1; - strncpy(cn->commonName, decoded.subjectCN, CTC_NAME_SIZE); - cn->commonName[sz] = 0; - } - if (decoded.subjectC) { - sz = (decoded.subjectCLen < CTC_NAME_SIZE) ? decoded.subjectCLen : - CTC_NAME_SIZE - 1; - strncpy(cn->country, decoded.subjectC, CTC_NAME_SIZE); - cn->country[sz] = 0; - } - if (decoded.subjectST) { - sz = (decoded.subjectSTLen < CTC_NAME_SIZE) ? decoded.subjectSTLen : - CTC_NAME_SIZE - 1; - strncpy(cn->state, decoded.subjectST, CTC_NAME_SIZE); - cn->state[sz] = 0; - } - if (decoded.subjectL) { - sz = (decoded.subjectLLen < CTC_NAME_SIZE) ? decoded.subjectLLen : - CTC_NAME_SIZE - 1; - strncpy(cn->locality, decoded.subjectL, CTC_NAME_SIZE); - cn->locality[sz] = 0; - } - if (decoded.subjectO) { - sz = (decoded.subjectOLen < CTC_NAME_SIZE) ? decoded.subjectOLen : - CTC_NAME_SIZE - 1; - strncpy(cn->org, decoded.subjectO, CTC_NAME_SIZE); - cn->org[sz] = 0; - } - if (decoded.subjectOU) { - sz = (decoded.subjectOULen < CTC_NAME_SIZE) ? decoded.subjectOULen : - CTC_NAME_SIZE - 1; - strncpy(cn->unit, decoded.subjectOU, CTC_NAME_SIZE); - cn->unit[sz] = 0; - } - if (decoded.subjectSN) { - sz = (decoded.subjectSNLen < CTC_NAME_SIZE) ? decoded.subjectSNLen : - CTC_NAME_SIZE - 1; - strncpy(cn->sur, decoded.subjectSN, CTC_NAME_SIZE); - cn->sur[sz] = 0; - } - if (decoded.subjectEmail) { - sz = (decoded.subjectEmailLen < CTC_NAME_SIZE) ? - decoded.subjectEmailLen : CTC_NAME_SIZE - 1; - strncpy(cn->email, decoded.subjectEmail, CTC_NAME_SIZE); - cn->email[sz] = 0; - } - - FreeDecodedCert(&decoded); - - return 0; -} - - -#ifndef NO_FILESYSTEM - -/* forward from CyaSSL */ -int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz); - -/* Set cert issuer from issuerFile in PEM */ -int SetIssuer(Cert* cert, const char* issuerFile) -{ - int ret; - int derSz; - byte* der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); - - if (der == NULL) { - CYASSL_MSG("SetIssuer OOF Problem"); - return MEMORY_E; - } - derSz = CyaSSL_PemCertToDer(issuerFile, der, EIGHTK_BUF); - cert->selfSigned = 0; - ret = SetNameFromCert(&cert->issuer, der, derSz); - XFREE(der, NULL, DYNAMIC_TYPE_CERT); - - return ret; -} - - -/* Set cert subject from subjectFile in PEM */ -int SetSubject(Cert* cert, const char* subjectFile) -{ - int ret; - int derSz; - byte* der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); - - if (der == NULL) { - CYASSL_MSG("SetSubject OOF Problem"); - return MEMORY_E; - } - derSz = CyaSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF); - ret = SetNameFromCert(&cert->subject, der, derSz); - XFREE(der, NULL, DYNAMIC_TYPE_CERT); - - return ret; -} - - -#ifdef CYASSL_ALT_NAMES - -/* Set atl names from file in PEM */ -int SetAltNames(Cert* cert, const char* file) -{ - int ret; - int derSz; - byte* der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); - - if (der == NULL) { - CYASSL_MSG("SetAltNames OOF Problem"); - return MEMORY_E; - } - derSz = CyaSSL_PemCertToDer(file, der, EIGHTK_BUF); - ret = SetAltNamesFromCert(cert, der, derSz); - XFREE(der, NULL, DYNAMIC_TYPE_CERT); - - return ret; -} - -#endif /* CYASSL_ALT_NAMES */ - -#endif /* NO_FILESYSTEM */ - -/* Set cert issuer from DER buffer */ -int SetIssuerBuffer(Cert* cert, const byte* der, int derSz) -{ - cert->selfSigned = 0; - return SetNameFromCert(&cert->issuer, der, derSz); -} - - -/* Set cert subject from DER buffer */ -int SetSubjectBuffer(Cert* cert, const byte* der, int derSz) -{ - return SetNameFromCert(&cert->subject, der, derSz); -} - - -#ifdef CYASSL_ALT_NAMES - -/* Set cert alt names from DER buffer */ -int SetAltNamesBuffer(Cert* cert, const byte* der, int derSz) -{ - return SetAltNamesFromCert(cert, der, derSz); -} - -/* Set cert dates from DER buffer */ -int SetDatesBuffer(Cert* cert, const byte* der, int derSz) -{ - return SetDatesFromCert(cert, der, derSz); -} - -#endif /* CYASSL_ALT_NAMES */ - -#endif /* CYASSL_CERT_GEN */ - - -#ifdef HAVE_ECC - -/* Der Encode r & s ints into out, outLen is (in/out) size */ -int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r, mp_int* s) -{ - word32 idx = 0; - word32 rSz; /* encoding size */ - word32 sSz; - word32 headerSz = 4; /* 2*ASN_TAG + 2*LEN(ENUM) */ - - /* If the leading bit on the INTEGER is a 1, add a leading zero */ - int rLeadingZero = mp_leading_bit(r); - int sLeadingZero = mp_leading_bit(s); - int rLen = mp_unsigned_bin_size(r); /* big int size */ - int sLen = mp_unsigned_bin_size(s); - int err; - - if (*outLen < (rLen + rLeadingZero + sLen + sLeadingZero + - headerSz + 2)) /* SEQ_TAG + LEN(ENUM) */ - return BAD_FUNC_ARG; - - idx = SetSequence(rLen+rLeadingZero+sLen+sLeadingZero+headerSz, out); - - /* store r */ - out[idx++] = ASN_INTEGER; - rSz = SetLength(rLen + rLeadingZero, &out[idx]); - idx += rSz; - if (rLeadingZero) - out[idx++] = 0; - err = mp_to_unsigned_bin(r, &out[idx]); - if (err != MP_OKAY) return err; - idx += rLen; - - /* store s */ - out[idx++] = ASN_INTEGER; - sSz = SetLength(sLen + sLeadingZero, &out[idx]); - idx += sSz; - if (sLeadingZero) - out[idx++] = 0; - err = mp_to_unsigned_bin(s, &out[idx]); - if (err != MP_OKAY) return err; - idx += sLen; - - *outLen = idx; - - return 0; -} - - -/* Der Decode ECC-DSA Signautre, r & s stored as big ints */ -int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s) -{ - word32 idx = 0; - int len = 0; - - if (GetSequence(sig, &idx, &len, sigLen) < 0) - return ASN_ECC_KEY_E; - - if ((word32)len > (sigLen - idx)) - return ASN_ECC_KEY_E; - - if (GetInt(r, sig, &idx, sigLen) < 0) - return ASN_ECC_KEY_E; - - if (GetInt(s, sig, &idx, sigLen) < 0) - return ASN_ECC_KEY_E; - - return 0; -} - - -int EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key, - word32 inSz) -{ - word32 oid = 0; - int version, length; - int privSz, pubSz; - byte b; - byte priv[ECC_MAXSIZE]; - byte pub[ECC_MAXSIZE * 2 + 1]; /* public key has two parts plus header */ - - if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) - return BAD_FUNC_ARG; - - if (GetSequence(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(input, inOutIdx, &version) < 0) - return ASN_PARSE_E; - - b = input[*inOutIdx]; - *inOutIdx += 1; - - /* priv type */ - if (b != 4 && b != 6 && b != 7) - return ASN_PARSE_E; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - /* priv key */ - privSz = length; - XMEMCPY(priv, &input[*inOutIdx], privSz); - *inOutIdx += length; - - /* prefix 0, may have */ - b = input[*inOutIdx]; - if (b == ECC_PREFIX_0) { - *inOutIdx += 1; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - /* object id */ - b = input[*inOutIdx]; - *inOutIdx += 1; - - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - while(length--) { - oid += input[*inOutIdx]; - *inOutIdx += 1; - } - if (CheckCurve(oid) < 0) - return ECC_CURVE_OID_E; - } - - /* prefix 1 */ - b = input[*inOutIdx]; - *inOutIdx += 1; - if (b != ECC_PREFIX_1) - return ASN_ECC_KEY_E; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - - /* key header */ - b = input[*inOutIdx]; - *inOutIdx += 1; - if (b != ASN_BIT_STRING) - return ASN_BITSTR_E; - - if (GetLength(input, inOutIdx, &length, inSz) < 0) - return ASN_PARSE_E; - b = input[*inOutIdx]; - *inOutIdx += 1; - if (b != 0x00) - return ASN_EXPECT_0_E; - - pubSz = length - 1; /* null prefix */ - XMEMCPY(pub, &input[*inOutIdx], pubSz); - - *inOutIdx += length; - - return ecc_import_private_key(priv, privSz, pub, pubSz, key); -} - -#endif /* HAVE_ECC */ - - -#if defined(HAVE_OCSP) || defined(HAVE_CRL) - -/* Get raw Date only, no processing, 0 on success */ -static int GetBasicDate(const byte* source, word32* idx, byte* date, - byte* format, int maxIdx) -{ - int length; - - CYASSL_ENTER("GetBasicDate"); - - *format = source[*idx]; - *idx += 1; - if (*format != ASN_UTC_TIME && *format != ASN_GENERALIZED_TIME) - return ASN_TIME_E; - - if (GetLength(source, idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE) - return ASN_DATE_SZ_E; - - XMEMCPY(date, &source[*idx], length); - *idx += length; - - return 0; -} - -#endif - - -#ifdef HAVE_OCSP - -static int GetEnumerated(const byte* input, word32* inOutIdx, int *value) -{ - word32 idx = *inOutIdx; - word32 len; - - CYASSL_ENTER("GetEnumerated"); - - *value = 0; - - if (input[idx++] != ASN_ENUMERATED) - return ASN_PARSE_E; - - len = input[idx++]; - if (len > 4) - return ASN_PARSE_E; - - while (len--) { - *value = *value << 8 | input[idx++]; - } - - *inOutIdx = idx; - - return *value; -} - - -static int DecodeSingleResponse(byte* source, - word32* ioIndex, OcspResponse* resp, word32 size) -{ - word32 idx = *ioIndex, prevIndex, oid; - int length, wrapperSz; - CertStatus* cs = resp->status; - - CYASSL_ENTER("DecodeSingleResponse"); - - /* Outer wrapper of the SEQUENCE OF Single Responses. */ - if (GetSequence(source, &idx, &wrapperSz, size) < 0) - return ASN_PARSE_E; - - prevIndex = idx; - - /* When making a request, we only request one status on one certificate - * at a time. There should only be one SingleResponse */ - - /* Wrapper around the Single Response */ - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - /* Wrapper around the CertID */ - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - /* Skip the hash algorithm */ - if (GetAlgoId(source, &idx, &oid, size) < 0) - return ASN_PARSE_E; - /* Save reference to the hash of CN */ - if (source[idx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - resp->issuerHash = source + idx; - idx += length; - /* Save reference to the hash of the issuer public key */ - if (source[idx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - resp->issuerKeyHash = source + idx; - idx += length; - - /* Read the serial number, it is handled as a string, not as a - * proper number. Just XMEMCPY the data over, rather than load it - * as an mp_int. */ - if (source[idx++] != ASN_INTEGER) - return ASN_PARSE_E; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - if (length <= EXTERNAL_SERIAL_SIZE) - { - if (source[idx] == 0) - { - idx++; - length--; - } - XMEMCPY(cs->serial, source + idx, length); - cs->serialSz = length; - } - else - { - return ASN_GETINT_E; - } - idx += length; - - /* CertStatus */ - switch (source[idx++]) - { - case (ASN_CONTEXT_SPECIFIC | CERT_GOOD): - cs->status = CERT_GOOD; - idx++; - break; - case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_REVOKED): - cs->status = CERT_REVOKED; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - idx += length; - break; - case (ASN_CONTEXT_SPECIFIC | CERT_UNKNOWN): - cs->status = CERT_UNKNOWN; - idx++; - break; - default: - return ASN_PARSE_E; - } - - if (GetBasicDate(source, &idx, cs->thisDate, - &cs->thisDateFormat, size) < 0) - return ASN_PARSE_E; - if (!XVALIDATE_DATE(cs->thisDate, cs->thisDateFormat, BEFORE)) - return ASN_BEFORE_DATE_E; - - /* The following items are optional. Only check for them if there is more - * unprocessed data in the singleResponse wrapper. */ - - if (((int)(idx - prevIndex) < wrapperSz) && - (source[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))) - { - idx++; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - if (GetBasicDate(source, &idx, cs->nextDate, - &cs->nextDateFormat, size) < 0) - return ASN_PARSE_E; - } - if (((int)(idx - prevIndex) < wrapperSz) && - (source[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))) - { - idx++; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - idx += length; - } - - *ioIndex = idx; - - return 0; -} - -static int DecodeOcspRespExtensions(byte* source, - word32* ioIndex, OcspResponse* resp, word32 sz) -{ - word32 idx = *ioIndex; - int length; - int ext_bound; /* boundary index for the sequence of extensions */ - word32 oid; - - CYASSL_ENTER("DecodeOcspRespExtensions"); - - if (source[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) - return ASN_PARSE_E; - - if (GetLength(source, &idx, &length, sz) < 0) return ASN_PARSE_E; - - if (GetSequence(source, &idx, &length, sz) < 0) return ASN_PARSE_E; - - ext_bound = idx + length; - - while (idx < (word32)ext_bound) { - if (GetSequence(source, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: should be a SEQUENCE"); - return ASN_PARSE_E; - } - - oid = 0; - if (GetObjectId(source, &idx, &oid, sz) < 0) { - CYASSL_MSG("\tfail: OBJECT ID"); - return ASN_PARSE_E; - } - - /* check for critical flag */ - if (source[idx] == ASN_BOOLEAN) { - CYASSL_MSG("\tfound optional critical flag, moving past"); - idx += (ASN_BOOL_SIZE + 1); - } - - /* process the extension based on the OID */ - if (source[idx++] != ASN_OCTET_STRING) { - CYASSL_MSG("\tfail: should be an OCTET STRING"); - return ASN_PARSE_E; - } - - if (GetLength(source, &idx, &length, sz) < 0) { - CYASSL_MSG("\tfail: extension data length"); - return ASN_PARSE_E; - } - - if (oid == OCSP_NONCE_OID) { - resp->nonce = source + idx; - resp->nonceSz = length; - } - - idx += length; - } - - *ioIndex = idx; - return 0; -} - - -static int DecodeResponseData(byte* source, - word32* ioIndex, OcspResponse* resp, word32 size) -{ - word32 idx = *ioIndex, prev_idx; - int length; - int version; - word32 responderId = 0; - - CYASSL_ENTER("DecodeResponseData"); - - resp->response = source + idx; - prev_idx = idx; - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - resp->responseSz = length + idx - prev_idx; - - /* Get version. It is an EXPLICIT[0] DEFAULT(0) value. If this - * item isn't an EXPLICIT[0], then set version to zero and move - * onto the next item. - */ - if (source[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) - { - idx += 2; /* Eat the value and length */ - if (GetMyVersion(source, &idx, &version) < 0) - return ASN_PARSE_E; - } else - version = 0; - - responderId = source[idx++]; - if ((responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) || - (responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2))) - { - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - idx += length; - } - else - return ASN_PARSE_E; - - /* save pointer to the producedAt time */ - if (GetBasicDate(source, &idx, resp->producedDate, - &resp->producedDateFormat, size) < 0) - return ASN_PARSE_E; - - if (DecodeSingleResponse(source, &idx, resp, size) < 0) - return ASN_PARSE_E; - - if (DecodeOcspRespExtensions(source, &idx, resp, size) < 0) - return ASN_PARSE_E; - - *ioIndex = idx; - return 0; -} - - -static int DecodeCerts(byte* source, - word32* ioIndex, OcspResponse* resp, word32 size) -{ - word32 idx = *ioIndex; - - CYASSL_ENTER("DecodeCerts"); - - if (source[idx++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) - { - int length; - - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - resp->cert = source + idx; - resp->certSz = length; - - idx += length; - } - *ioIndex = idx; - return 0; -} - -static int DecodeBasicOcspResponse(byte* source, - word32* ioIndex, OcspResponse* resp, word32 size) -{ - int length; - word32 idx = *ioIndex; - word32 end_index; - - CYASSL_ENTER("DecodeBasicOcspResponse"); - - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - if (idx + length > size) - return ASN_INPUT_E; - end_index = idx + length; - - if (DecodeResponseData(source, &idx, resp, size) < 0) - return ASN_PARSE_E; - - /* Get the signature algorithm */ - if (GetAlgoId(source, &idx, &resp->sigOID, size) < 0) - return ASN_PARSE_E; - - /* Obtain pointer to the start of the signature, and save the size */ - if (source[idx++] == ASN_BIT_STRING) - { - int sigLength = 0; - if (GetLength(source, &idx, &sigLength, size) < 0) - return ASN_PARSE_E; - resp->sigSz = sigLength; - resp->sig = source + idx; - idx += sigLength; - } - - /* - * Check the length of the BasicOcspResponse against the current index to - * see if there are certificates, they are optional. - */ - if (idx < end_index) - { - DecodedCert cert; - int ret; - - if (DecodeCerts(source, &idx, resp, size) < 0) - return ASN_PARSE_E; - - InitDecodedCert(&cert, resp->cert, resp->certSz, 0); - ret = ParseCertRelative(&cert, CA_TYPE, NO_VERIFY, 0); - if (ret < 0) - return ret; - - ret = ConfirmSignature(resp->response, resp->responseSz, - cert.publicKey, cert.pubKeySize, cert.keyOID, - resp->sig, resp->sigSz, resp->sigOID, NULL); - FreeDecodedCert(&cert); - - if (ret == 0) - { - CYASSL_MSG("\tOCSP Confirm signature failed"); - return ASN_OCSP_CONFIRM_E; - } - } - - *ioIndex = idx; - return 0; -} - - -void InitOcspResponse(OcspResponse* resp, CertStatus* status, - byte* source, word32 inSz) -{ - CYASSL_ENTER("InitOcspResponse"); - - resp->responseStatus = -1; - resp->response = NULL; - resp->responseSz = 0; - resp->producedDateFormat = 0; - resp->issuerHash = NULL; - resp->issuerKeyHash = NULL; - resp->sig = NULL; - resp->sigSz = 0; - resp->sigOID = 0; - resp->status = status; - resp->nonce = NULL; - resp->nonceSz = 0; - resp->source = source; - resp->maxIdx = inSz; -} - - -int OcspResponseDecode(OcspResponse* resp) -{ - int length = 0; - word32 idx = 0; - byte* source = resp->source; - word32 size = resp->maxIdx; - word32 oid; - - CYASSL_ENTER("OcspResponseDecode"); - - /* peel the outer SEQUENCE wrapper */ - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - /* First get the responseStatus, an ENUMERATED */ - if (GetEnumerated(source, &idx, &resp->responseStatus) < 0) - return ASN_PARSE_E; - - if (resp->responseStatus != OCSP_SUCCESSFUL) - return 0; - - /* Next is an EXPLICIT record called ResponseBytes, OPTIONAL */ - if (idx >= size) - return ASN_INPUT_E; - if (source[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) - return ASN_PARSE_E; - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - /* Get the responseBytes SEQUENCE */ - if (GetSequence(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - /* Check ObjectID for the resposeBytes */ - if (GetObjectId(source, &idx, &oid, size) < 0) - return ASN_PARSE_E; - if (oid != OCSP_BASIC_OID) - return ASN_PARSE_E; - if (source[idx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(source, &idx, &length, size) < 0) - return ASN_PARSE_E; - - if (DecodeBasicOcspResponse(source, &idx, resp, size) < 0) - return ASN_PARSE_E; - - return 0; -} - - -static word32 SetOcspReqExtensions(word32 extSz, byte* output, - const byte* nonce, word32 nonceSz) -{ - static const byte NonceObjId[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, - 0x30, 0x01, 0x02 }; - byte seqArray[5][MAX_SEQ_SZ]; - word32 seqSz[5], totalSz; - - CYASSL_ENTER("SetOcspReqExtensions"); - - if (nonce == NULL || nonceSz == 0) return 0; - - seqArray[0][0] = ASN_OCTET_STRING; - seqSz[0] = 1 + SetLength(nonceSz, &seqArray[0][1]); - - seqArray[1][0] = ASN_OBJECT_ID; - seqSz[1] = 1 + SetLength(sizeof(NonceObjId), &seqArray[1][1]); - - totalSz = seqSz[0] + seqSz[1] + nonceSz + (word32)sizeof(NonceObjId); - - seqSz[2] = SetSequence(totalSz, seqArray[2]); - totalSz += seqSz[2]; - - seqSz[3] = SetSequence(totalSz, seqArray[3]); - totalSz += seqSz[3]; - - seqArray[4][0] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2); - seqSz[4] = 1 + SetLength(totalSz, &seqArray[4][1]); - totalSz += seqSz[4]; - - if (totalSz < extSz) - { - totalSz = 0; - XMEMCPY(output + totalSz, seqArray[4], seqSz[4]); - totalSz += seqSz[4]; - XMEMCPY(output + totalSz, seqArray[3], seqSz[3]); - totalSz += seqSz[3]; - XMEMCPY(output + totalSz, seqArray[2], seqSz[2]); - totalSz += seqSz[2]; - XMEMCPY(output + totalSz, seqArray[1], seqSz[1]); - totalSz += seqSz[1]; - XMEMCPY(output + totalSz, NonceObjId, sizeof(NonceObjId)); - totalSz += (word32)sizeof(NonceObjId); - XMEMCPY(output + totalSz, seqArray[0], seqSz[0]); - totalSz += seqSz[0]; - XMEMCPY(output + totalSz, nonce, nonceSz); - totalSz += nonceSz; - } - - return totalSz; -} - - -int EncodeOcspRequest(OcspRequest* req) -{ - byte seqArray[5][MAX_SEQ_SZ]; - /* The ASN.1 of the OCSP Request is an onion of sequences */ - byte algoArray[MAX_ALGO_SZ]; - byte issuerArray[MAX_ENCODED_DIG_SZ]; - byte issuerKeyArray[MAX_ENCODED_DIG_SZ]; - byte snArray[MAX_SN_SZ]; - byte extArray[MAX_OCSP_EXT_SZ]; - byte* output = req->dest; - word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, extSz, totalSz; - int i; - - CYASSL_ENTER("EncodeOcspRequest"); - - algoSz = SetAlgoID(SHAh, algoArray, hashType, 0); - - req->issuerHash = req->cert->issuerHash; - issuerSz = SetDigest(req->cert->issuerHash, SHA_SIZE, issuerArray); - - req->issuerKeyHash = req->cert->issuerKeyHash; - issuerKeySz = SetDigest(req->cert->issuerKeyHash, SHA_SIZE, issuerKeyArray); - - req->serial = req->cert->serial; - req->serialSz = req->cert->serialSz; - snSz = SetSerialNumber(req->cert->serial, req->cert->serialSz, snArray); - - extSz = 0; - if (req->useNonce) { - RNG rng; - if (InitRng(&rng) != 0) { - CYASSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce."); - } else { - if (RNG_GenerateBlock(&rng, req->nonce, MAX_OCSP_NONCE_SZ) != 0) - CYASSL_MSG("\tCannot run RNG. Skipping the OSCP Nonce."); - else { - req->nonceSz = MAX_OCSP_NONCE_SZ; - extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray, - req->nonce, req->nonceSz); - } - } - } - - totalSz = algoSz + issuerSz + issuerKeySz + snSz; - - for (i = 4; i >= 0; i--) { - seqSz[i] = SetSequence(totalSz, seqArray[i]); - totalSz += seqSz[i]; - if (i == 2) totalSz += extSz; - } - totalSz = 0; - for (i = 0; i < 5; i++) { - XMEMCPY(output + totalSz, seqArray[i], seqSz[i]); - totalSz += seqSz[i]; - } - XMEMCPY(output + totalSz, algoArray, algoSz); - totalSz += algoSz; - XMEMCPY(output + totalSz, issuerArray, issuerSz); - totalSz += issuerSz; - XMEMCPY(output + totalSz, issuerKeyArray, issuerKeySz); - totalSz += issuerKeySz; - XMEMCPY(output + totalSz, snArray, snSz); - totalSz += snSz; - if (extSz != 0) { - XMEMCPY(output + totalSz, extArray, extSz); - totalSz += extSz; - } - - return totalSz; -} - - -void InitOcspRequest(OcspRequest* req, DecodedCert* cert, byte useNonce, - byte* dest, word32 destSz) -{ - CYASSL_ENTER("InitOcspRequest"); - - req->cert = cert; - req->useNonce = useNonce; - req->nonceSz = 0; - req->issuerHash = NULL; - req->issuerKeyHash = NULL; - req->serial = NULL; - req->dest = dest; - req->destSz = destSz; -} - - -int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp) -{ - int cmp; - - CYASSL_ENTER("CompareOcspReqResp"); - - if (req == NULL) - { - CYASSL_MSG("\tReq missing"); - return -1; - } - - if (resp == NULL) - { - CYASSL_MSG("\tResp missing"); - return 1; - } - - /* Nonces are not critical. The responder may not necessarily add - * the nonce to the response. */ - if (req->useNonce && resp->nonceSz != 0) { - cmp = req->nonceSz - resp->nonceSz; - if (cmp != 0) - { - CYASSL_MSG("\tnonceSz mismatch"); - return cmp; - } - - cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz); - if (cmp != 0) - { - CYASSL_MSG("\tnonce mismatch"); - return cmp; - } - } - - cmp = XMEMCMP(req->issuerHash, resp->issuerHash, SHA_DIGEST_SIZE); - if (cmp != 0) - { - CYASSL_MSG("\tissuerHash mismatch"); - return cmp; - } - - cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, SHA_DIGEST_SIZE); - if (cmp != 0) - { - CYASSL_MSG("\tissuerKeyHash mismatch"); - return cmp; - } - - cmp = req->serialSz - resp->status->serialSz; - if (cmp != 0) - { - CYASSL_MSG("\tserialSz mismatch"); - return cmp; - } - - cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz); - if (cmp != 0) - { - CYASSL_MSG("\tserial mismatch"); - return cmp; - } - - return 0; -} - -#endif - - -/* store SHA1 hash of NAME */ -CYASSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash, - int maxIdx) -{ - Sha sha; - int length; /* length of all distinguished names */ - int ret = 0; - word32 dummy; - - CYASSL_ENTER("GetNameHash"); - - if (source[*idx] == ASN_OBJECT_ID) { - CYASSL_MSG("Trying optional prefix..."); - - if (GetLength(source, idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - *idx += length; - CYASSL_MSG("Got optional prefix"); - } - - /* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be - * calculated over the entire DER encoding of the Name field, including - * the tag and length. */ - dummy = *idx; - if (GetSequence(source, idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, source + dummy, length + *idx - dummy); - ShaFinal(&sha, hash); - - *idx += length; - - return 0; -} - - -#ifdef HAVE_CRL - -/* initialize decoded CRL */ -void InitDecodedCRL(DecodedCRL* dcrl) -{ - CYASSL_MSG("InitDecodedCRL"); - - dcrl->certBegin = 0; - dcrl->sigIndex = 0; - dcrl->sigLength = 0; - dcrl->signatureOID = 0; - dcrl->certs = NULL; - dcrl->totalCerts = 0; -} - - -/* free decoded CRL resources */ -void FreeDecodedCRL(DecodedCRL* dcrl) -{ - RevokedCert* tmp = dcrl->certs; - - CYASSL_MSG("FreeDecodedCRL"); - - while(tmp) { - RevokedCert* next = tmp->next; - XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED); - tmp = next; - } -} - - -/* Get Revoked Cert list, 0 on success */ -static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, - int maxIdx) -{ - int len; - word32 end; - byte b; - RevokedCert* rc; - - CYASSL_ENTER("GetRevoked"); - - if (GetSequence(buff, idx, &len, maxIdx) < 0) - return ASN_PARSE_E; - - end = *idx + len; - - /* get serial number */ - b = buff[*idx]; - *idx += 1; - - if (b != ASN_INTEGER) { - CYASSL_MSG("Expecting Integer"); - return ASN_PARSE_E; - } - - if (GetLength(buff, idx, &len, maxIdx) < 0) - return ASN_PARSE_E; - - if (len > EXTERNAL_SERIAL_SIZE) { - CYASSL_MSG("Serial Size too big"); - return ASN_PARSE_E; - } - - rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), NULL, DYNAMIC_TYPE_CRL); - if (rc == NULL) { - CYASSL_MSG("Alloc Revoked Cert failed"); - return MEMORY_E; - } - - XMEMCPY(rc->serialNumber, &buff[*idx], len); - rc->serialSz = len; - - /* add to list */ - rc->next = dcrl->certs; - dcrl->certs = rc; - dcrl->totalCerts++; - - *idx += len; - - /* get date */ - b = buff[*idx]; - *idx += 1; - - if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) { - CYASSL_MSG("Expecting Date"); - return ASN_PARSE_E; - } - - if (GetLength(buff, idx, &len, maxIdx) < 0) - return ASN_PARSE_E; - - /* skip for now */ - *idx += len; - - if (*idx != end) /* skip extensions */ - *idx = end; - - return 0; -} - - -/* Get CRL Signature, 0 on success */ -static int GetCRL_Signature(const byte* source, word32* idx, DecodedCRL* dcrl, - int maxIdx) -{ - int length; - byte b; - - CYASSL_ENTER("GetCRL_Signature"); - - b = source[*idx]; - *idx += 1; - if (b != ASN_BIT_STRING) - return ASN_BITSTR_E; - - if (GetLength(source, idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - dcrl->sigLength = length; - - b = source[*idx]; - *idx += 1; - if (b != 0x00) - return ASN_EXPECT_0_E; - - dcrl->sigLength--; - dcrl->signature = (byte*)&source[*idx]; - - *idx += dcrl->sigLength; - - return 0; -} - - -/* prase crl buffer into decoded state, 0 on success */ -int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm) -{ - int version, len; - word32 oid, idx = 0; - Signer* ca = NULL; - - CYASSL_MSG("ParseCRL"); - - /* raw crl hash */ - /* hash here if needed for optimized comparisons - * Sha sha; - * InitSha(&sha); - * ShaUpdate(&sha, buff, sz); - * ShaFinal(&sha, dcrl->crlHash); */ - - if (GetSequence(buff, &idx, &len, sz) < 0) - return ASN_PARSE_E; - - dcrl->certBegin = idx; - - if (GetSequence(buff, &idx, &len, sz) < 0) - return ASN_PARSE_E; - dcrl->sigIndex = len + idx; - - /* may have version */ - if (buff[idx] == ASN_INTEGER) { - if (GetMyVersion(buff, &idx, &version) < 0) - return ASN_PARSE_E; - } - - if (GetAlgoId(buff, &idx, &oid, sz) < 0) - return ASN_PARSE_E; - - if (GetNameHash(buff, &idx, dcrl->issuerHash, sz) < 0) - return ASN_PARSE_E; - - if (GetBasicDate(buff, &idx, dcrl->lastDate, &dcrl->lastDateFormat, sz) < 0) - return ASN_PARSE_E; - - if (GetBasicDate(buff, &idx, dcrl->nextDate, &dcrl->nextDateFormat, sz) < 0) - return ASN_PARSE_E; - - if (!XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, AFTER)) { - CYASSL_MSG("CRL after date is no longer valid"); - return ASN_AFTER_DATE_E; - } - - if (idx != dcrl->sigIndex && buff[idx] != CRL_EXTENSIONS) { - if (GetSequence(buff, &idx, &len, sz) < 0) - return ASN_PARSE_E; - - len += idx; - - while (idx < (word32)len) { - if (GetRevoked(buff, &idx, dcrl, sz) < 0) - return ASN_PARSE_E; - } - } - - if (idx != dcrl->sigIndex) - idx = dcrl->sigIndex; /* skip extensions */ - - if (GetAlgoId(buff, &idx, &dcrl->signatureOID, sz) < 0) - return ASN_PARSE_E; - - if (GetCRL_Signature(buff, &idx, dcrl, sz) < 0) - return ASN_PARSE_E; - - /* openssl doesn't add skid by default for CRLs cause firefox chokes - we're not assuming it's available yet */ - #if !defined(NO_SKID) && defined(CRL_SKID_READY) - if (dcrl->extAuthKeyIdSet) - ca = GetCA(cm, dcrl->extAuthKeyId); - if (ca == NULL) - ca = GetCAByName(cm, dcrl->issuerHash); - #else /* NO_SKID */ - ca = GetCA(cm, dcrl->issuerHash); - #endif /* NO_SKID */ - CYASSL_MSG("About to verify CRL signature"); - - if (ca) { - CYASSL_MSG("Found CRL issuer CA"); - /* try to confirm/verify signature */ - #ifndef IGNORE_KEY_EXTENSIONS - if ((ca->keyUsage & KEYUSE_CRL_SIGN) == 0) { - CYASSL_MSG("CA cannot sign CRLs"); - return ASN_CRL_NO_SIGNER_E; - } - #endif /* IGNORE_KEY_EXTENSIONS */ - if (!ConfirmSignature(buff + dcrl->certBegin, - dcrl->sigIndex - dcrl->certBegin, - ca->publicKey, ca->pubKeySize, ca->keyOID, - dcrl->signature, dcrl->sigLength, dcrl->signatureOID, NULL)) { - CYASSL_MSG("CRL Confirm signature failed"); - return ASN_CRL_CONFIRM_E; - } - } - else { - CYASSL_MSG("Did NOT find CRL issuer CA"); - return ASN_CRL_NO_SIGNER_E; - } - - return 0; -} - -#endif /* HAVE_CRL */ -#endif - -#ifdef CYASSL_SEP - - - -#endif /* CYASSL_SEP */ - - +/* asn.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <cyassl/ctaocrypt/settings.h> + +#ifndef NO_ASN + +#ifdef HAVE_RTP_SYS + #include "os.h" /* dc_rtc_api needs */ + #include "dc_rtc_api.h" /* to get current time */ +#endif + +#include <cyassl/ctaocrypt/integer.h> +#include <cyassl/ctaocrypt/asn.h> +#include <cyassl/ctaocrypt/coding.h> +#include <cyassl/ctaocrypt/sha.h> +#include <cyassl/ctaocrypt/md5.h> +#include <cyassl/ctaocrypt/md2.h> +#include <cyassl/ctaocrypt/error-crypt.h> +#include <cyassl/ctaocrypt/pwdbased.h> +#include <cyassl/ctaocrypt/des3.h> +#include <cyassl/ctaocrypt/sha256.h> +#include <cyassl/ctaocrypt/sha512.h> +#include <cyassl/ctaocrypt/logging.h> + +#include <cyassl/ctaocrypt/random.h> + + +#ifndef NO_RC4 + #include <cyassl/ctaocrypt/arc4.h> +#endif + +#ifdef HAVE_NTRU + #include "crypto_ntru.h" +#endif + +#ifdef HAVE_ECC + #include <cyassl/ctaocrypt/ecc.h> +#endif + +#ifdef CYASSL_DEBUG_ENCODING + #ifdef FREESCALE_MQX + #include <fio.h> + #else + #include <stdio.h> + #endif +#endif + +#ifdef _MSC_VER + /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */ + #pragma warning(disable: 4996) +#endif + + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + + +#ifdef HAVE_RTP_SYS + /* uses parital <time.h> structures */ + #define XTIME(tl) (0) + #define XGMTIME(c) my_gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#elif defined(MICRIUM) + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + #define XVALIDATE_DATE(d,f,t) NetSecure_ValidateDateHandler((d),(f),(t)) + #else + #define XVALIDATE_DATE(d, f, t) (0) + #endif + #define NO_TIME_H + /* since Micrium not defining XTIME or XGMTIME, CERT_GEN not available */ +#elif defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP) + #include <time.h> + #define XTIME(t1) pic32_time((t1)) + #define XGMTIME(c) gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#elif defined(FREESCALE_MQX) + #include <time.h> + #define XTIME(t1) mqx_time((t1)) + #define XGMTIME(c) gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#elif defined(CYASSL_MDK_ARM) + #if defined(CYASSL_MDK5) + #include "cmsis_os.h" + #else + #include <rtl.h> + #endif + #undef RNG + #include "cyassl_MDK_ARM.h" + #undef RNG + #define RNG CyaSSL_RNG /*for avoiding name conflict in "stm32f2xx.h" */ + #define XTIME(tl) (0) + #define XGMTIME(c) Cyassl_MDK_gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#elif defined(USER_TIME) + /* user time, and gmtime compatible functions, there is a gmtime + implementation here that WINCE uses, so really just need some ticks + since the EPOCH + */ + + struct tm { + int tm_sec; /* seconds after the minute [0-60] */ + int tm_min; /* minutes after the hour [0-59] */ + int tm_hour; /* hours since midnight [0-23] */ + int tm_mday; /* day of the month [1-31] */ + int tm_mon; /* months since January [0-11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday [0-6] */ + int tm_yday; /* days since January 1 [0-365] */ + int tm_isdst; /* Daylight Savings Time flag */ + long tm_gmtoff; /* offset from CUT in seconds */ + char *tm_zone; /* timezone abbreviation */ + }; + typedef long time_t; + + /* forward declaration */ + struct tm* gmtime(const time_t* timer); + time_t XTIME(time_t * timer) { + return time(timer); + } + + #define XGMTIME(c) gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) + + #ifdef STACK_TRAP + /* for stack trap tracking, don't call os gmtime on OS X/linux, + uses a lot of stack spce */ + extern time_t time(time_t * timer); + #define XTIME(tl) time((tl)) + #endif /* STACK_TRAP */ + +#else + /* default */ + /* uses complete <time.h> facility */ + #include <time.h> + #define XTIME(tl) time((tl)) + #define XGMTIME(c) gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#endif + + +#ifdef _WIN32_WCE +/* no time() or gmtime() even though in time.h header?? */ + +#include <windows.h> + + +time_t time(time_t* timer) +{ + SYSTEMTIME sysTime; + FILETIME fTime; + ULARGE_INTEGER intTime; + time_t localTime; + + if (timer == NULL) + timer = &localTime; + + GetSystemTime(&sysTime); + SystemTimeToFileTime(&sysTime, &fTime); + + XMEMCPY(&intTime, &fTime, sizeof(FILETIME)); + /* subtract EPOCH */ + intTime.QuadPart -= 0x19db1ded53e8000; + /* to secs */ + intTime.QuadPart /= 10000000; + *timer = (time_t)intTime.QuadPart; + + return *timer; +} + +#endif /* _WIN32_WCE */ +#if defined( _WIN32_WCE ) || defined( USER_TIME ) + +struct tm* gmtime(const time_t* timer) +{ + #define YEAR0 1900 + #define EPOCH_YEAR 1970 + #define SECS_DAY (24L * 60L * 60L) + #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400))) + #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) + + static const int _ytab[2][12] = + { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + }; + + static struct tm st_time; + struct tm* ret = &st_time; + time_t secs = *timer; + unsigned long dayclock, dayno; + int year = EPOCH_YEAR; + + dayclock = (unsigned long)secs % SECS_DAY; + dayno = (unsigned long)secs / SECS_DAY; + + ret->tm_sec = (int) dayclock % 60; + ret->tm_min = (int)(dayclock % 3600) / 60; + ret->tm_hour = (int) dayclock / 3600; + ret->tm_wday = (int) (dayno + 4) % 7; /* day 0 a Thursday */ + + while(dayno >= (unsigned long)YEARSIZE(year)) { + dayno -= YEARSIZE(year); + year++; + } + + ret->tm_year = year - YEAR0; + ret->tm_yday = (int)dayno; + ret->tm_mon = 0; + + while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) { + dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon]; + ret->tm_mon++; + } + + ret->tm_mday = (int)++dayno; + ret->tm_isdst = 0; + + return ret; +} + +#endif /* _WIN32_WCE || USER_TIME */ + + +#ifdef HAVE_RTP_SYS + +#define YEAR0 1900 + +struct tm* my_gmtime(const time_t* timer) /* has a gmtime() but hangs */ +{ + static struct tm st_time; + struct tm* ret = &st_time; + + DC_RTC_CALENDAR cal; + dc_rtc_time_get(&cal, TRUE); + + ret->tm_year = cal.year - YEAR0; /* gm starts at 1900 */ + ret->tm_mon = cal.month - 1; /* gm starts at 0 */ + ret->tm_mday = cal.day; + ret->tm_hour = cal.hour; + ret->tm_min = cal.minute; + ret->tm_sec = cal.second; + + return ret; +} + +#endif /* HAVE_RTP_SYS */ + + +#if defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP) + +/* + * time() is just a stub in Microchip libraries. We need our own + * implementation. Use SNTP client to get seconds since epoch. + */ +time_t pic32_time(time_t* timer) +{ +#ifdef MICROCHIP_TCPIP_V5 + DWORD sec = 0; +#else + uint32_t sec = 0; +#endif + time_t localTime; + + if (timer == NULL) + timer = &localTime; + +#ifdef MICROCHIP_MPLAB_HARMONY + sec = TCPIP_SNTP_UTCSecondsGet(); +#else + sec = SNTPGetUTCSeconds(); +#endif + *timer = (time_t) sec; + + return *timer; +} + +#endif /* MICROCHIP_TCPIP */ + + +#ifdef FREESCALE_MQX + +time_t mqx_time(time_t* timer) +{ + time_t localTime; + TIME_STRUCT time_s; + + if (timer == NULL) + timer = &localTime; + + _time_get(&time_s); + *timer = (time_t) time_s.SECONDS; + + return *timer; +} + +#endif /* FREESCALE_MQX */ + + +static INLINE word32 btoi(byte b) +{ + return b - 0x30; +} + + +/* two byte date/time, add to value */ +static INLINE void GetTime(int* value, const byte* date, int* idx) +{ + int i = *idx; + + *value += btoi(date[i++]) * 10; + *value += btoi(date[i++]); + + *idx = i; +} + + +#if defined(MICRIUM) + +CPU_INT32S NetSecure_ValidateDateHandler(CPU_INT08U *date, CPU_INT08U format, + CPU_INT08U dateType) +{ + CPU_BOOLEAN rtn_code; + CPU_INT32S i; + CPU_INT32S val; + CPU_INT16U year; + CPU_INT08U month; + CPU_INT16U day; + CPU_INT08U hour; + CPU_INT08U min; + CPU_INT08U sec; + + i = 0; + year = 0u; + + if (format == ASN_UTC_TIME) { + if (btoi(date[0]) >= 5) + year = 1900; + else + year = 2000; + } + else { /* format == GENERALIZED_TIME */ + year += btoi(date[i++]) * 1000; + year += btoi(date[i++]) * 100; + } + + val = year; + GetTime(&val, date, &i); + year = (CPU_INT16U)val; + + val = 0; + GetTime(&val, date, &i); + month = (CPU_INT08U)val; + + val = 0; + GetTime(&val, date, &i); + day = (CPU_INT16U)val; + + val = 0; + GetTime(&val, date, &i); + hour = (CPU_INT08U)val; + + val = 0; + GetTime(&val, date, &i); + min = (CPU_INT08U)val; + + val = 0; + GetTime(&val, date, &i); + sec = (CPU_INT08U)val; + + return NetSecure_ValidateDate(year, month, day, hour, min, sec, dateType); +} + +#endif /* MICRIUM */ + + +CYASSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx) +{ + int length = 0; + word32 i = *inOutIdx; + byte b; + + if ( (i+1) > maxIdx) { /* for first read */ + CYASSL_MSG("GetLength bad index on input"); + return BUFFER_E; + } + + b = input[i++]; + if (b >= ASN_LONG_LENGTH) { + word32 bytes = b & 0x7F; + + if ( (i+bytes) > maxIdx) { /* for reading bytes */ + CYASSL_MSG("GetLength bad long length"); + return BUFFER_E; + } + + while (bytes--) { + b = input[i++]; + length = (length << 8) | b; + } + } + else + length = b; + + if ( (i+length) > maxIdx) { /* for user of length */ + CYASSL_MSG("GetLength value exceeds buffer length"); + return BUFFER_E; + } + + *inOutIdx = i; + *len = length; + + return length; +} + + +CYASSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx) +{ + int length = -1; + word32 idx = *inOutIdx; + + if (input[idx++] != (ASN_SEQUENCE | ASN_CONSTRUCTED) || + GetLength(input, &idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + *len = length; + *inOutIdx = idx; + + return length; +} + + +CYASSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx) +{ + int length = -1; + word32 idx = *inOutIdx; + + if (input[idx++] != (ASN_SET | ASN_CONSTRUCTED) || + GetLength(input, &idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + *len = length; + *inOutIdx = idx; + + return length; +} + + +/* winodws header clash for WinCE using GetVersion */ +CYASSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx, int* version) +{ + word32 idx = *inOutIdx; + + CYASSL_ENTER("GetMyVersion"); + + if (input[idx++] != ASN_INTEGER) + return ASN_PARSE_E; + + if (input[idx++] != 0x01) + return ASN_VERSION_E; + + *version = input[idx++]; + *inOutIdx = idx; + + return *version; +} + + +#ifndef NO_PWDBASED +/* Get small count integer, 32 bits or less */ +static int GetShortInt(const byte* input, word32* inOutIdx, int* number) +{ + word32 idx = *inOutIdx; + word32 len; + + *number = 0; + + if (input[idx++] != ASN_INTEGER) + return ASN_PARSE_E; + + len = input[idx++]; + if (len > 4) + return ASN_PARSE_E; + + while (len--) { + *number = *number << 8 | input[idx++]; + } + + *inOutIdx = idx; + + return *number; +} +#endif /* !NO_PWDBASED */ + + +/* May not have one, not an error */ +static int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version) +{ + word32 idx = *inOutIdx; + + CYASSL_ENTER("GetExplicitVersion"); + if (input[idx++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { + *inOutIdx = ++idx; /* eat header */ + return GetMyVersion(input, inOutIdx, version); + } + + /* go back as is */ + *version = 0; + + return 0; +} + + +CYASSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, + word32 maxIdx) +{ + word32 i = *inOutIdx; + byte b = input[i++]; + int length; + + if (b != ASN_INTEGER) + return ASN_PARSE_E; + + if (GetLength(input, &i, &length, maxIdx) < 0) + return ASN_PARSE_E; + + if ( (b = input[i++]) == 0x00) + length--; + else + i--; + + if (mp_init(mpi) != MP_OKAY) + return MP_INIT_E; + + if (mp_read_unsigned_bin(mpi, (byte*)input + i, length) != 0) { + mp_clear(mpi); + return ASN_GETINT_E; + } + + *inOutIdx = i + length; + return 0; +} + + +static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) +{ + int length; + word32 i = *inOutIdx; + byte b; + *oid = 0; + + b = input[i++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, &i, &length, maxIdx) < 0) + return ASN_PARSE_E; + + while(length--) + *oid += input[i++]; + /* just sum it up for now */ + + *inOutIdx = i; + + return 0; +} + + +CYASSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) +{ + int length; + word32 i = *inOutIdx; + byte b; + *oid = 0; + + CYASSL_ENTER("GetAlgoId"); + + if (GetSequence(input, &i, &length, maxIdx) < 0) + return ASN_PARSE_E; + + b = input[i++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, &i, &length, maxIdx) < 0) + return ASN_PARSE_E; + + while(length--) { + /* odd HC08 compiler behavior here when input[i++] */ + *oid += input[i]; + i++; + } + /* just sum it up for now */ + + /* could have NULL tag and 0 terminator, but may not */ + b = input[i++]; + + if (b == ASN_TAG_NULL) { + b = input[i++]; + if (b != 0) + return ASN_EXPECT_0_E; + } + else + /* go back, didn't have it */ + i--; + + *inOutIdx = i; + + return 0; +} + +#ifndef NO_RSA + + +#ifdef HAVE_CAVIUM + +static int GetCaviumInt(byte** buff, word16* buffSz, const byte* input, + word32* inOutIdx, word32 maxIdx, void* heap) +{ + word32 i = *inOutIdx; + byte b = input[i++]; + int length; + + if (b != ASN_INTEGER) + return ASN_PARSE_E; + + if (GetLength(input, &i, &length, maxIdx) < 0) + return ASN_PARSE_E; + + if ( (b = input[i++]) == 0x00) + length--; + else + i--; + + *buffSz = (word16)length; + *buff = XMALLOC(*buffSz, heap, DYNAMIC_TYPE_CAVIUM_RSA); + if (*buff == NULL) + return MEMORY_E; + + XMEMCPY(*buff, input + i, *buffSz); + + *inOutIdx = i + length; + return 0; +} + +static int CaviumRsaPrivateKeyDecode(const byte* input, word32* inOutIdx, + RsaKey* key, word32 inSz) +{ + int version, length; + void* h = key->heap; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + key->type = RSA_PRIVATE; + + if (GetCaviumInt(&key->c_n, &key->c_nSz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_e, &key->c_eSz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_d, &key->c_dSz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_p, &key->c_pSz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_q, &key->c_qSz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_dP, &key->c_dP_Sz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_dQ, &key->c_dQ_Sz, input, inOutIdx, inSz, h) < 0 || + GetCaviumInt(&key->c_u, &key->c_uSz, input, inOutIdx, inSz, h) < 0 ) + return ASN_RSA_KEY_E; + + return 0; +} + + +#endif /* HAVE_CAVIUM */ + +int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, + word32 inSz) +{ + int version, length; + +#ifdef HAVE_CAVIUM + if (key->magic == CYASSL_RSA_CAVIUM_MAGIC) + return CaviumRsaPrivateKeyDecode(input, inOutIdx, key, inSz); +#endif + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + key->type = RSA_PRIVATE; + + if (GetInt(&key->n, input, inOutIdx, inSz) < 0 || + GetInt(&key->e, input, inOutIdx, inSz) < 0 || + GetInt(&key->d, input, inOutIdx, inSz) < 0 || + GetInt(&key->p, input, inOutIdx, inSz) < 0 || + GetInt(&key->q, input, inOutIdx, inSz) < 0 || + GetInt(&key->dP, input, inOutIdx, inSz) < 0 || + GetInt(&key->dQ, input, inOutIdx, inSz) < 0 || + GetInt(&key->u, input, inOutIdx, inSz) < 0 ) return ASN_RSA_KEY_E; + + return 0; +} + +#endif /* NO_RSA */ + +/* Remove PKCS8 header, move beginning of traditional to beginning of input */ +int ToTraditional(byte* input, word32 sz) +{ + word32 inOutIdx = 0, oid; + int version, length; + + if (GetSequence(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(input, &inOutIdx, &version) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) + return ASN_PARSE_E; + + if (input[inOutIdx] == ASN_OBJECT_ID) { + /* pkcs8 ecc uses slightly different format */ + inOutIdx++; /* past id */ + if (GetLength(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + inOutIdx += length; /* over sub id, key input will verify */ + } + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + XMEMMOVE(input, input + inOutIdx, length); + + return length; +} + + +#ifndef NO_PWDBASED + +/* Check To see if PKCS version algo is supported, set id if it is return 0 + < 0 on error */ +static int CheckAlgo(int first, int second, int* id, int* version) +{ + *id = ALGO_ID_E; + *version = PKCS5; /* default */ + + if (first == 1) { + switch (second) { + case 1: + *id = PBE_SHA1_RC4_128; + *version = PKCS12; + return 0; + case 3: + *id = PBE_SHA1_DES3; + *version = PKCS12; + return 0; + default: + return ALGO_ID_E; + } + } + + if (first != PKCS5) + return ASN_INPUT_E; /* VERSION ERROR */ + + if (second == PBES2) { + *version = PKCS5v2; + return 0; + } + + switch (second) { + case 3: /* see RFC 2898 for ids */ + *id = PBE_MD5_DES; + return 0; + case 10: + *id = PBE_SHA1_DES; + return 0; + default: + return ALGO_ID_E; + + } +} + + +/* Check To see if PKCS v2 algo is supported, set id if it is return 0 + < 0 on error */ +static int CheckAlgoV2(int oid, int* id) +{ + switch (oid) { + case 69: + *id = PBE_SHA1_DES; + return 0; + case 652: + *id = PBE_SHA1_DES3; + return 0; + default: + return ALGO_ID_E; + + } +} + + +/* Decrypt intput in place from parameters based on id */ +static int DecryptKey(const char* password, int passwordSz, byte* salt, + int saltSz, int iterations, int id, byte* input, + int length, int version, byte* cbcIv) +{ + byte key[MAX_KEY_SIZE]; + int typeH; + int derivedLen; + int decryptionType; + int ret = 0; + + switch (id) { + case PBE_MD5_DES: + typeH = MD5; + derivedLen = 16; /* may need iv for v1.5 */ + decryptionType = DES_TYPE; + break; + + case PBE_SHA1_DES: + typeH = SHA; + derivedLen = 16; /* may need iv for v1.5 */ + decryptionType = DES_TYPE; + break; + + case PBE_SHA1_DES3: + typeH = SHA; + derivedLen = 32; /* may need iv for v1.5 */ + decryptionType = DES3_TYPE; + break; + + case PBE_SHA1_RC4_128: + typeH = SHA; + derivedLen = 16; + decryptionType = RC4_TYPE; + break; + + default: + return ALGO_ID_E; + } + + if (version == PKCS5v2) + ret = PBKDF2(key, (byte*)password, passwordSz, salt, saltSz, iterations, + derivedLen, typeH); + else if (version == PKCS5) + ret = PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations, + derivedLen, typeH); + else if (version == PKCS12) { + int i, idx = 0; + byte unicodePasswd[MAX_UNICODE_SZ]; + + if ( (passwordSz * 2 + 2) > (int)sizeof(unicodePasswd)) + return UNICODE_SIZE_E; + + for (i = 0; i < passwordSz; i++) { + unicodePasswd[idx++] = 0x00; + unicodePasswd[idx++] = (byte)password[i]; + } + /* add trailing NULL */ + unicodePasswd[idx++] = 0x00; + unicodePasswd[idx++] = 0x00; + + ret = PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz, + iterations, derivedLen, typeH, 1); + if (decryptionType != RC4_TYPE) + ret += PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz, + iterations, 8, typeH, 2); + } + else + return ALGO_ID_E; + + if (ret != 0) + return ret; + + switch (decryptionType) { +#ifndef NO_DES3 + case DES_TYPE: + { + Des dec; + byte* desIv = key + 8; + + if (version == PKCS5v2 || version == PKCS12) + desIv = cbcIv; + + ret = Des_SetKey(&dec, key, desIv, DES_DECRYPTION); + if (ret != 0) + return ret; + + Des_CbcDecrypt(&dec, input, input, length); + break; + } + + case DES3_TYPE: + { + Des3 dec; + byte* desIv = key + 24; + + if (version == PKCS5v2 || version == PKCS12) + desIv = cbcIv; + ret = Des3_SetKey(&dec, key, desIv, DES_DECRYPTION); + if (ret != 0) + return ret; + ret = Des3_CbcDecrypt(&dec, input, input, length); + if (ret != 0) + return ret; + break; + } +#endif +#ifndef NO_RC4 + case RC4_TYPE: + { + Arc4 dec; + + Arc4SetKey(&dec, key, derivedLen); + Arc4Process(&dec, input, input, length); + break; + } +#endif + + default: + return ALGO_ID_E; + } + + return 0; +} + + +/* Remove Encrypted PKCS8 header, move beginning of traditional to beginning + of input */ +int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) +{ + word32 inOutIdx = 0, oid; + int first, second, length, version, saltSz, id; + int iterations = 0; + byte salt[MAX_SALT_SIZE]; + byte cbcIv[MAX_IV_SIZE]; + + if (GetSequence(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) + return ASN_PARSE_E; + + first = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */ + second = input[inOutIdx - 1]; /* version.algo, algo id last byte */ + + if (CheckAlgo(first, second, &id, &version) < 0) + return ASN_INPUT_E; /* Algo ID error */ + + if (version == PKCS5v2) { + + if (GetSequence(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) + return ASN_PARSE_E; + + if (oid != PBKDF2_OID) + return ASN_PARSE_E; + } + + if (GetSequence(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &saltSz, sz) < 0) + return ASN_PARSE_E; + + if (saltSz > MAX_SALT_SIZE) + return ASN_PARSE_E; + + XMEMCPY(salt, &input[inOutIdx], saltSz); + inOutIdx += saltSz; + + if (GetShortInt(input, &inOutIdx, &iterations) < 0) + return ASN_PARSE_E; + + if (version == PKCS5v2) { + /* get encryption algo */ + if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) + return ASN_PARSE_E; + + if (CheckAlgoV2(oid, &id) < 0) + return ASN_PARSE_E; /* PKCS v2 algo id error */ + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + XMEMCPY(cbcIv, &input[inOutIdx], length); + inOutIdx += length; + } + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &length, sz) < 0) + return ASN_PARSE_E; + + if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id, + input + inOutIdx, length, version, cbcIv) < 0) + return ASN_INPUT_E; /* decrypt failure */ + + XMEMMOVE(input, input + inOutIdx, length); + return ToTraditional(input, length); +} + +#endif /* NO_PWDBASED */ + +#ifndef NO_RSA + +int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, + word32 inSz) +{ + int length; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + key->type = RSA_PUBLIC; + +#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA) + { + byte b = input[*inOutIdx]; + if (b != ASN_INTEGER) { + /* not from decoded cert, will have algo id, skip past */ + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + b = input[(*inOutIdx)++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + *inOutIdx += length; /* skip past */ + + /* could have NULL tag and 0 terminator, but may not */ + b = input[(*inOutIdx)++]; + + if (b == ASN_TAG_NULL) { + b = input[(*inOutIdx)++]; + if (b != 0) + return ASN_EXPECT_0_E; + } + else + /* go back, didn't have it */ + (*inOutIdx)--; + + /* should have bit tag length and seq next */ + b = input[(*inOutIdx)++]; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + /* could have 0 */ + b = input[(*inOutIdx)++]; + if (b != 0) + (*inOutIdx)--; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + } /* end if */ + } /* openssl var block */ +#endif /* OPENSSL_EXTRA */ + + if (GetInt(&key->n, input, inOutIdx, inSz) < 0 || + GetInt(&key->e, input, inOutIdx, inSz) < 0 ) return ASN_RSA_KEY_E; + + return 0; +} + +#endif + +#ifndef NO_DH + +int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) +{ + int length; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || + GetInt(&key->g, input, inOutIdx, inSz) < 0 ) return ASN_DH_KEY_E; + + return 0; +} + +int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz) +{ + if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) + return BAD_FUNC_ARG; + + /* may have leading 0 */ + if (p[0] == 0) { + pSz--; p++; + } + + if (g[0] == 0) { + gSz--; g++; + } + + if (mp_init(&key->p) != MP_OKAY) + return MP_INIT_E; + if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) { + mp_clear(&key->p); + return ASN_DH_KEY_E; + } + + if (mp_init(&key->g) != MP_OKAY) { + mp_clear(&key->p); + return MP_INIT_E; + } + if (mp_read_unsigned_bin(&key->g, g, gSz) != 0) { + mp_clear(&key->g); + mp_clear(&key->p); + return ASN_DH_KEY_E; + } + + return 0; +} + + +#ifdef OPENSSL_EXTRA + +int DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz, + byte* g, word32* gInOutSz) +{ + word32 i = 0; + byte b; + int length; + + if (GetSequence(input, &i, &length, inSz) < 0) + return ASN_PARSE_E; + + b = input[i++]; + if (b != ASN_INTEGER) + return ASN_PARSE_E; + + if (GetLength(input, &i, &length, inSz) < 0) + return ASN_PARSE_E; + + if ( (b = input[i++]) == 0x00) + length--; + else + i--; + + if (length <= (int)*pInOutSz) { + XMEMCPY(p, &input[i], length); + *pInOutSz = length; + } + else + return BUFFER_E; + + i += length; + + b = input[i++]; + if (b != ASN_INTEGER) + return ASN_PARSE_E; + + if (GetLength(input, &i, &length, inSz) < 0) + return ASN_PARSE_E; + + if (length <= (int)*gInOutSz) { + XMEMCPY(g, &input[i], length); + *gInOutSz = length; + } + else + return BUFFER_E; + + return 0; +} + +#endif /* OPENSSL_EXTRA */ +#endif /* NO_DH */ + + +#ifndef NO_DSA + +int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key, + word32 inSz) +{ + int length; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || + GetInt(&key->q, input, inOutIdx, inSz) < 0 || + GetInt(&key->g, input, inOutIdx, inSz) < 0 || + GetInt(&key->y, input, inOutIdx, inSz) < 0 ) return ASN_DH_KEY_E; + + key->type = DSA_PUBLIC; + return 0; +} + + +int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key, + word32 inSz) +{ + int length, version; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || + GetInt(&key->q, input, inOutIdx, inSz) < 0 || + GetInt(&key->g, input, inOutIdx, inSz) < 0 || + GetInt(&key->y, input, inOutIdx, inSz) < 0 || + GetInt(&key->x, input, inOutIdx, inSz) < 0 ) return ASN_DH_KEY_E; + + key->type = DSA_PRIVATE; + return 0; +} + +#endif /* NO_DSA */ + + +void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) +{ + cert->publicKey = 0; + cert->pubKeySize = 0; + cert->pubKeyStored = 0; + cert->version = 0; + cert->signature = 0; + cert->subjectCN = 0; + cert->subjectCNLen = 0; + cert->subjectCNStored = 0; + cert->altNames = NULL; +#ifndef IGNORE_NAME_CONSTRAINTS + cert->altEmailNames = NULL; + cert->permittedNames = NULL; + cert->excludedNames = NULL; +#endif /* IGNORE_NAME_CONSTRAINTS */ + cert->issuer[0] = '\0'; + cert->subject[0] = '\0'; + cert->source = source; /* don't own */ + cert->srcIdx = 0; + cert->maxIdx = inSz; /* can't go over this index */ + cert->heap = heap; + XMEMSET(cert->serial, 0, EXTERNAL_SERIAL_SIZE); + cert->serialSz = 0; + cert->extensions = 0; + cert->extensionsSz = 0; + cert->extensionsIdx = 0; + cert->extAuthInfo = NULL; + cert->extAuthInfoSz = 0; + cert->extCrlInfo = NULL; + cert->extCrlInfoSz = 0; + XMEMSET(cert->extSubjKeyId, 0, SHA_SIZE); + cert->extSubjKeyIdSet = 0; + XMEMSET(cert->extAuthKeyId, 0, SHA_SIZE); + cert->extAuthKeyIdSet = 0; + cert->extKeyUsageSet = 0; + cert->extKeyUsage = 0; + cert->extExtKeyUsageSet = 0; + cert->extExtKeyUsage = 0; + cert->isCA = 0; +#ifdef HAVE_PKCS7 + cert->issuerRaw = NULL; + cert->issuerRawLen = 0; +#endif +#ifdef CYASSL_CERT_GEN + cert->subjectSN = 0; + cert->subjectSNLen = 0; + cert->subjectC = 0; + cert->subjectCLen = 0; + cert->subjectL = 0; + cert->subjectLLen = 0; + cert->subjectST = 0; + cert->subjectSTLen = 0; + cert->subjectO = 0; + cert->subjectOLen = 0; + cert->subjectOU = 0; + cert->subjectOULen = 0; + cert->subjectEmail = 0; + cert->subjectEmailLen = 0; +#endif /* CYASSL_CERT_GEN */ + cert->beforeDate = NULL; + cert->beforeDateLen = 0; + cert->afterDate = NULL; + cert->afterDateLen = 0; +#ifdef OPENSSL_EXTRA + XMEMSET(&cert->issuerName, 0, sizeof(DecodedName)); + XMEMSET(&cert->subjectName, 0, sizeof(DecodedName)); + cert->extBasicConstSet = 0; + cert->extBasicConstCrit = 0; + cert->extBasicConstPlSet = 0; + cert->pathLength = 0; + cert->extSubjAltNameSet = 0; + cert->extSubjAltNameCrit = 0; + cert->extAuthKeyIdCrit = 0; + cert->extSubjKeyIdCrit = 0; + cert->extKeyUsageCrit = 0; + cert->extExtKeyUsageCrit = 0; + cert->extExtKeyUsageSrc = NULL; + cert->extExtKeyUsageSz = 0; + cert->extExtKeyUsageCount = 0; + cert->extAuthKeyIdSrc = NULL; + cert->extAuthKeyIdSz = 0; + cert->extSubjKeyIdSrc = NULL; + cert->extSubjKeyIdSz = 0; +#endif /* OPENSSL_EXTRA */ +#if defined(OPENSSL_EXTRA) || !defined(IGNORE_NAME_CONSTRAINTS) + cert->extNameConstraintSet = 0; +#endif /* OPENSSL_EXTRA || !IGNORE_NAME_CONSTRAINTS */ +#ifdef HAVE_ECC + cert->pkCurveOID = 0; +#endif /* HAVE_ECC */ +#ifdef CYASSL_SEP + cert->deviceTypeSz = 0; + cert->deviceType = NULL; + cert->hwTypeSz = 0; + cert->hwType = NULL; + cert->hwSerialNumSz = 0; + cert->hwSerialNum = NULL; + #ifdef OPENSSL_EXTRA + cert->extCertPolicySet = 0; + cert->extCertPolicyCrit = 0; + #endif /* OPENSSL_EXTRA */ +#endif /* CYASSL_SEP */ +} + + +void FreeAltNames(DNS_entry* altNames, void* heap) +{ + (void)heap; + + while (altNames) { + DNS_entry* tmp = altNames->next; + + XFREE(altNames->name, heap, DYNAMIC_TYPE_ALTNAME); + XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME); + altNames = tmp; + } +} + +#ifndef IGNORE_NAME_CONSTRAINTS + +void FreeNameSubtrees(Base_entry* names, void* heap) +{ + (void)heap; + + while (names) { + Base_entry* tmp = names->next; + + XFREE(names->name, heap, DYNAMIC_TYPE_ALTNAME); + XFREE(names, heap, DYNAMIC_TYPE_ALTNAME); + names = tmp; + } +} + +#endif /* IGNORE_NAME_CONSTRAINTS */ + +void FreeDecodedCert(DecodedCert* cert) +{ + if (cert->subjectCNStored == 1) + XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN); + if (cert->pubKeyStored == 1) + XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (cert->altNames) + FreeAltNames(cert->altNames, cert->heap); +#ifndef IGNORE_NAME_CONSTRAINTS + if (cert->altEmailNames) + FreeAltNames(cert->altEmailNames, cert->heap); + if (cert->permittedNames) + FreeNameSubtrees(cert->permittedNames, cert->heap); + if (cert->excludedNames) + FreeNameSubtrees(cert->excludedNames, cert->heap); +#endif /* IGNORE_NAME_CONSTRAINTS */ +#ifdef CYASSL_SEP + XFREE(cert->deviceType, cert->heap, 0); + XFREE(cert->hwType, cert->heap, 0); + XFREE(cert->hwSerialNum, cert->heap, 0); +#endif /* CYASSL_SEP */ +#ifdef OPENSSL_EXTRA + if (cert->issuerName.fullName != NULL) + XFREE(cert->issuerName.fullName, NULL, DYNAMIC_TYPE_X509); + if (cert->subjectName.fullName != NULL) + XFREE(cert->subjectName.fullName, NULL, DYNAMIC_TYPE_X509); +#endif /* OPENSSL_EXTRA */ +} + + +static int GetCertHeader(DecodedCert* cert) +{ + int ret = 0, len; + byte serialTmp[EXTERNAL_SERIAL_SIZE]; + mp_int mpi; + + if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0) + return ASN_PARSE_E; + + cert->certBegin = cert->srcIdx; + + if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0) + return ASN_PARSE_E; + cert->sigIndex = len + cert->srcIdx; + + if (GetExplicitVersion(cert->source, &cert->srcIdx, &cert->version) < 0) + return ASN_PARSE_E; + + if (GetInt(&mpi, cert->source, &cert->srcIdx, cert->maxIdx) < 0) + return ASN_PARSE_E; + + len = mp_unsigned_bin_size(&mpi); + if (len < (int)sizeof(serialTmp)) { + if ( (ret = mp_to_unsigned_bin(&mpi, serialTmp)) == MP_OKAY) { + if (len > EXTERNAL_SERIAL_SIZE) + len = EXTERNAL_SERIAL_SIZE; + XMEMCPY(cert->serial, serialTmp, len); + cert->serialSz = len; + } + } + mp_clear(&mpi); + return ret; +} + +#if !defined(NO_RSA) +/* Store Rsa Key, may save later, Dsa could use in future */ +static int StoreRsaKey(DecodedCert* cert) +{ + int length; + word32 recvd = cert->srcIdx; + + if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + recvd = cert->srcIdx - recvd; + length += recvd; + + while (recvd--) + cert->srcIdx--; + + cert->pubKeySize = length; + cert->publicKey = cert->source + cert->srcIdx; + cert->srcIdx += length; + + return 0; +} +#endif + + +#ifdef HAVE_ECC + + /* return 0 on sucess if the ECC curve oid sum is supported */ + static int CheckCurve(word32 oid) + { + if (oid != ECC_256R1 && oid != ECC_384R1 && oid != ECC_521R1 && oid != + ECC_160R1 && oid != ECC_192R1 && oid != ECC_224R1) + return ALGO_ID_E; + + return 0; + } + +#endif /* HAVE_ECC */ + + +static int GetKey(DecodedCert* cert) +{ + int length; +#ifdef HAVE_NTRU + int tmpIdx = cert->srcIdx; +#endif + + if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(cert->source, &cert->srcIdx, &cert->keyOID, cert->maxIdx) < 0) + return ASN_PARSE_E; + + switch (cert->keyOID) { + #ifndef NO_RSA + case RSAk: + { + byte b = cert->source[cert->srcIdx++]; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0) + return ASN_PARSE_E; + b = cert->source[cert->srcIdx++]; + if (b != 0x00) + return ASN_EXPECT_0_E; + + return StoreRsaKey(cert); + } + + #endif /* NO_RSA */ + #ifdef HAVE_NTRU + case NTRUk: + { + const byte* key = &cert->source[tmpIdx]; + byte* next = (byte*)key; + word16 keyLen; + byte keyBlob[MAX_NTRU_KEY_SZ]; + + word32 rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, + &keyLen, NULL, &next); + + if (rc != NTRU_OK) + return ASN_NTRU_KEY_E; + if (keyLen > sizeof(keyBlob)) + return ASN_NTRU_KEY_E; + + rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,&keyLen, + keyBlob, &next); + if (rc != NTRU_OK) + return ASN_NTRU_KEY_E; + + if ( (next - key) < 0) + return ASN_NTRU_KEY_E; + + cert->srcIdx = tmpIdx + (int)(next - key); + + cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (cert->publicKey == NULL) + return MEMORY_E; + XMEMCPY(cert->publicKey, keyBlob, keyLen); + cert->pubKeyStored = 1; + cert->pubKeySize = keyLen; + + return 0; + } + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ECDSAk: + { + int oidSz = 0; + byte b = cert->source[cert->srcIdx++]; + + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(cert->source,&cert->srcIdx,&oidSz,cert->maxIdx) < 0) + return ASN_PARSE_E; + + while(oidSz--) + cert->pkCurveOID += cert->source[cert->srcIdx++]; + + if (CheckCurve(cert->pkCurveOID) < 0) + return ECC_CURVE_OID_E; + + /* key header */ + b = cert->source[cert->srcIdx++]; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0) + return ASN_PARSE_E; + b = cert->source[cert->srcIdx++]; + if (b != 0x00) + return ASN_EXPECT_0_E; + + /* actual key, use length - 1 since ate preceding 0 */ + length -= 1; + + cert->publicKey = (byte*) XMALLOC(length, cert->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (cert->publicKey == NULL) + return MEMORY_E; + XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length); + cert->pubKeyStored = 1; + cert->pubKeySize = length; + + cert->srcIdx += length; + + return 0; + } + #endif /* HAVE_ECC */ + default: + return ASN_UNKNOWN_OID_E; + } +} + + +/* process NAME, either issuer or subject */ +static int GetName(DecodedCert* cert, int nameType) +{ + Sha sha; /* MUST have SHA-1 hash for cert names */ + int length; /* length of all distinguished names */ + int dummy; + int ret; + char* full = (nameType == ISSUER) ? cert->issuer : cert->subject; + word32 idx; + #ifdef OPENSSL_EXTRA + DecodedName* dName = + (nameType == ISSUER) ? &cert->issuerName : &cert->subjectName; + #endif /* OPENSSL_EXTRA */ + + CYASSL_MSG("Getting Cert Name"); + + if (cert->source[cert->srcIdx] == ASN_OBJECT_ID) { + CYASSL_MSG("Trying optional prefix..."); + + if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + cert->srcIdx += length; + CYASSL_MSG("Got optional prefix"); + } + + /* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be + * calculated over the entire DER encoding of the Name field, including + * the tag and length. */ + idx = cert->srcIdx; + if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, &cert->source[idx], length + cert->srcIdx - idx); + if (nameType == ISSUER) + ShaFinal(&sha, cert->issuerHash); + else + ShaFinal(&sha, cert->subjectHash); + + length += cert->srcIdx; + idx = 0; + +#ifdef HAVE_PKCS7 + /* store pointer to raw issuer */ + if (nameType == ISSUER) { + cert->issuerRaw = &cert->source[cert->srcIdx]; + cert->issuerRawLen = length - cert->srcIdx; + } +#endif +#ifndef IGNORE_NAME_CONSTRAINTS + if (nameType == SUBJECT) { + cert->subjectRaw = &cert->source[cert->srcIdx]; + cert->subjectRawLen = length - cert->srcIdx; + } +#endif + + while (cert->srcIdx < (word32)length) { + byte b; + byte joint[2]; + byte tooBig = FALSE; + int oidSz; + + if (GetSet(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0) { + CYASSL_MSG("Cert name lacks set header, trying sequence"); + } + + if (GetSequence(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0) + return ASN_PARSE_E; + + b = cert->source[cert->srcIdx++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(cert->source, &cert->srcIdx, &oidSz, cert->maxIdx) < 0) + return ASN_PARSE_E; + + XMEMCPY(joint, &cert->source[cert->srcIdx], sizeof(joint)); + + /* v1 name types */ + if (joint[0] == 0x55 && joint[1] == 0x04) { + byte id; + byte copy = FALSE; + int strLen; + + cert->srcIdx += 2; + id = cert->source[cert->srcIdx++]; + b = cert->source[cert->srcIdx++]; /* strType */ + (void)b; /* may want to validate? */ + + if (GetLength(cert->source, &cert->srcIdx, &strLen, + cert->maxIdx) < 0) + return ASN_PARSE_E; + + if ( (strLen + 14) > (int)(ASN_NAME_MAX - idx)) { + /* include biggest pre fix header too 4 = "/serialNumber=" */ + CYASSL_MSG("ASN Name too big, skipping"); + tooBig = TRUE; + } + + if (id == ASN_COMMON_NAME) { + if (nameType == SUBJECT) { + cert->subjectCN = (char *)&cert->source[cert->srcIdx]; + cert->subjectCNLen = strLen; + } + + if (!tooBig) { + XMEMCPY(&full[idx], "/CN=", 4); + idx += 4; + copy = TRUE; + } + #ifdef OPENSSL_EXTRA + dName->cnIdx = cert->srcIdx; + dName->cnLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_SUR_NAME) { + if (!tooBig) { + XMEMCPY(&full[idx], "/SN=", 4); + idx += 4; + copy = TRUE; + } + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectSN = (char*)&cert->source[cert->srcIdx]; + cert->subjectSNLen = strLen; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->snIdx = cert->srcIdx; + dName->snLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_COUNTRY_NAME) { + if (!tooBig) { + XMEMCPY(&full[idx], "/C=", 3); + idx += 3; + copy = TRUE; + } + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectC = (char*)&cert->source[cert->srcIdx]; + cert->subjectCLen = strLen; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->cIdx = cert->srcIdx; + dName->cLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_LOCALITY_NAME) { + if (!tooBig) { + XMEMCPY(&full[idx], "/L=", 3); + idx += 3; + copy = TRUE; + } + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectL = (char*)&cert->source[cert->srcIdx]; + cert->subjectLLen = strLen; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->lIdx = cert->srcIdx; + dName->lLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_STATE_NAME) { + if (!tooBig) { + XMEMCPY(&full[idx], "/ST=", 4); + idx += 4; + copy = TRUE; + } + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectST = (char*)&cert->source[cert->srcIdx]; + cert->subjectSTLen = strLen; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->stIdx = cert->srcIdx; + dName->stLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_ORG_NAME) { + if (!tooBig) { + XMEMCPY(&full[idx], "/O=", 3); + idx += 3; + copy = TRUE; + } + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectO = (char*)&cert->source[cert->srcIdx]; + cert->subjectOLen = strLen; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->oIdx = cert->srcIdx; + dName->oLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_ORGUNIT_NAME) { + if (!tooBig) { + XMEMCPY(&full[idx], "/OU=", 4); + idx += 4; + copy = TRUE; + } + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectOU = (char*)&cert->source[cert->srcIdx]; + cert->subjectOULen = strLen; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->ouIdx = cert->srcIdx; + dName->ouLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + else if (id == ASN_SERIAL_NUMBER) { + if (!tooBig) { + XMEMCPY(&full[idx], "/serialNumber=", 14); + idx += 14; + copy = TRUE; + } + #ifdef OPENSSL_EXTRA + dName->snIdx = cert->srcIdx; + dName->snLen = strLen; + #endif /* OPENSSL_EXTRA */ + } + + if (copy && !tooBig) { + XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen); + idx += strLen; + } + + cert->srcIdx += strLen; + } + else { + /* skip */ + byte email = FALSE; + byte uid = FALSE; + int adv; + + if (joint[0] == 0x2a && joint[1] == 0x86) /* email id hdr */ + email = TRUE; + + if (joint[0] == 0x9 && joint[1] == 0x92) /* uid id hdr */ + uid = TRUE; + + cert->srcIdx += oidSz + 1; + + if (GetLength(cert->source, &cert->srcIdx, &adv, cert->maxIdx) < 0) + return ASN_PARSE_E; + + if (adv > (int)(ASN_NAME_MAX - idx)) { + CYASSL_MSG("ASN name too big, skipping"); + tooBig = TRUE; + } + + if (email) { + if ( (14 + adv) > (int)(ASN_NAME_MAX - idx)) { + CYASSL_MSG("ASN name too big, skipping"); + tooBig = TRUE; + } + if (!tooBig) { + XMEMCPY(&full[idx], "/emailAddress=", 14); + idx += 14; + } + + #ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectEmail = (char*)&cert->source[cert->srcIdx]; + cert->subjectEmailLen = adv; + } + #endif /* CYASSL_CERT_GEN */ + #ifdef OPENSSL_EXTRA + dName->emailIdx = cert->srcIdx; + dName->emailLen = adv; + #endif /* OPENSSL_EXTRA */ + #ifndef IGNORE_NAME_CONSTRAINTS + { + DNS_entry* emailName = NULL; + + emailName = (DNS_entry*)XMALLOC(sizeof(DNS_entry), + cert->heap, DYNAMIC_TYPE_ALTNAME); + if (emailName == NULL) { + CYASSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + emailName->name = (char*)XMALLOC(adv + 1, + cert->heap, DYNAMIC_TYPE_ALTNAME); + if (emailName->name == NULL) { + CYASSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + XMEMCPY(emailName->name, + &cert->source[cert->srcIdx], adv); + emailName->name[adv] = 0; + + emailName->next = cert->altEmailNames; + cert->altEmailNames = emailName; + } + #endif /* IGNORE_NAME_CONSTRAINTS */ + if (!tooBig) { + XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv); + idx += adv; + } + } + + if (uid) { + if ( (5 + adv) > (int)(ASN_NAME_MAX - idx)) { + CYASSL_MSG("ASN name too big, skipping"); + tooBig = TRUE; + } + if (!tooBig) { + XMEMCPY(&full[idx], "/UID=", 5); + idx += 5; + + XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv); + idx += adv; + } + #ifdef OPENSSL_EXTRA + dName->uidIdx = cert->srcIdx; + dName->uidLen = adv; + #endif /* OPENSSL_EXTRA */ + } + + cert->srcIdx += adv; + } + } + full[idx++] = 0; + + #ifdef OPENSSL_EXTRA + { + int totalLen = 0; + + if (dName->cnLen != 0) + totalLen += dName->cnLen + 4; + if (dName->snLen != 0) + totalLen += dName->snLen + 4; + if (dName->cLen != 0) + totalLen += dName->cLen + 3; + if (dName->lLen != 0) + totalLen += dName->lLen + 3; + if (dName->stLen != 0) + totalLen += dName->stLen + 4; + if (dName->oLen != 0) + totalLen += dName->oLen + 3; + if (dName->ouLen != 0) + totalLen += dName->ouLen + 4; + if (dName->emailLen != 0) + totalLen += dName->emailLen + 14; + if (dName->uidLen != 0) + totalLen += dName->uidLen + 5; + if (dName->serialLen != 0) + totalLen += dName->serialLen + 14; + + dName->fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509); + if (dName->fullName != NULL) { + idx = 0; + + if (dName->cnLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/CN=", 4); + idx += 4; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->cnIdx], dName->cnLen); + dName->cnIdx = idx; + idx += dName->cnLen; + } + if (dName->snLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/SN=", 4); + idx += 4; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->snIdx], dName->snLen); + dName->snIdx = idx; + idx += dName->snLen; + } + if (dName->cLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/C=", 3); + idx += 3; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->cIdx], dName->cLen); + dName->cIdx = idx; + idx += dName->cLen; + } + if (dName->lLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/L=", 3); + idx += 3; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->lIdx], dName->lLen); + dName->lIdx = idx; + idx += dName->lLen; + } + if (dName->stLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/ST=", 4); + idx += 4; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->stIdx], dName->stLen); + dName->stIdx = idx; + idx += dName->stLen; + } + if (dName->oLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/O=", 3); + idx += 3; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->oIdx], dName->oLen); + dName->oIdx = idx; + idx += dName->oLen; + } + if (dName->ouLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/OU=", 4); + idx += 4; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->ouIdx], dName->ouLen); + dName->ouIdx = idx; + idx += dName->ouLen; + } + if (dName->emailLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/emailAddress=", 14); + idx += 14; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->emailIdx], dName->emailLen); + dName->emailIdx = idx; + idx += dName->emailLen; + } + if (dName->uidLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/UID=", 5); + idx += 5; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->uidIdx], dName->uidLen); + dName->uidIdx = idx; + idx += dName->uidLen; + } + if (dName->serialLen != 0) { + dName->entryCount++; + XMEMCPY(&dName->fullName[idx], "/serialNumber=", 14); + idx += 14; + XMEMCPY(&dName->fullName[idx], + &cert->source[dName->serialIdx], dName->serialLen); + dName->serialIdx = idx; + idx += dName->serialLen; + } + dName->fullName[idx] = '\0'; + dName->fullNameLen = totalLen; + } + } + #endif /* OPENSSL_EXTRA */ + + return 0; +} + + +#ifndef NO_TIME_H + +/* to the second */ +static int DateGreaterThan(const struct tm* a, const struct tm* b) +{ + if (a->tm_year > b->tm_year) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday > b->tm_mday) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && + a->tm_min > b->tm_min) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && + a->tm_min == b->tm_min && a->tm_sec > b->tm_sec) + return 1; + + return 0; /* false */ +} + + +static INLINE int DateLessThan(const struct tm* a, const struct tm* b) +{ + return !DateGreaterThan(a,b); +} + + +/* like atoi but only use first byte */ +/* Make sure before and after dates are valid */ +int ValidateDate(const byte* date, byte format, int dateType) +{ + time_t ltime; + struct tm certTime; + struct tm* localTime; + int i = 0; + + ltime = XTIME(0); + XMEMSET(&certTime, 0, sizeof(certTime)); + + if (format == ASN_UTC_TIME) { + if (btoi(date[0]) >= 5) + certTime.tm_year = 1900; + else + certTime.tm_year = 2000; + } + else { /* format == GENERALIZED_TIME */ + certTime.tm_year += btoi(date[i++]) * 1000; + certTime.tm_year += btoi(date[i++]) * 100; + } + + GetTime(&certTime.tm_year, date, &i); certTime.tm_year -= 1900; /* adjust */ + GetTime(&certTime.tm_mon, date, &i); certTime.tm_mon -= 1; /* adjust */ + GetTime(&certTime.tm_mday, date, &i); + GetTime(&certTime.tm_hour, date, &i); + GetTime(&certTime.tm_min, date, &i); + GetTime(&certTime.tm_sec, date, &i); + + if (date[i] != 'Z') { /* only Zulu supported for this profile */ + CYASSL_MSG("Only Zulu time supported for this profile"); + return 0; + } + + localTime = XGMTIME(<ime); + + if (dateType == BEFORE) { + if (DateLessThan(localTime, &certTime)) + return 0; + } + else + if (DateGreaterThan(localTime, &certTime)) + return 0; + + return 1; +} + +#endif /* NO_TIME_H */ + + +static int GetDate(DecodedCert* cert, int dateType) +{ + int length; + byte date[MAX_DATE_SIZE]; + byte b; + word32 startIdx = 0; + + if (dateType == BEFORE) + cert->beforeDate = &cert->source[cert->srcIdx]; + else + cert->afterDate = &cert->source[cert->srcIdx]; + startIdx = cert->srcIdx; + + b = cert->source[cert->srcIdx++]; + if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) + return ASN_TIME_E; + + if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE) + return ASN_DATE_SZ_E; + + XMEMCPY(date, &cert->source[cert->srcIdx], length); + cert->srcIdx += length; + + if (dateType == BEFORE) + cert->beforeDateLen = cert->srcIdx - startIdx; + else + cert->afterDateLen = cert->srcIdx - startIdx; + + if (!XVALIDATE_DATE(date, b, dateType)) { + if (dateType == BEFORE) + return ASN_BEFORE_DATE_E; + else + return ASN_AFTER_DATE_E; + } + + return 0; +} + + +static int GetValidity(DecodedCert* cert, int verify) +{ + int length; + int badDate = 0; + + if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + if (GetDate(cert, BEFORE) < 0 && verify) + badDate = ASN_BEFORE_DATE_E; /* continue parsing */ + + if (GetDate(cert, AFTER) < 0 && verify) + return ASN_AFTER_DATE_E; + + if (badDate != 0) + return badDate; + + return 0; +} + + +int DecodeToKey(DecodedCert* cert, int verify) +{ + int badDate = 0; + int ret; + + if ( (ret = GetCertHeader(cert)) < 0) + return ret; + + CYASSL_MSG("Got Cert Header"); + + if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID, + cert->maxIdx)) < 0) + return ret; + + CYASSL_MSG("Got Algo ID"); + + if ( (ret = GetName(cert, ISSUER)) < 0) + return ret; + + if ( (ret = GetValidity(cert, verify)) < 0) + badDate = ret; + + if ( (ret = GetName(cert, SUBJECT)) < 0) + return ret; + + CYASSL_MSG("Got Subject Name"); + + if ( (ret = GetKey(cert)) < 0) + return ret; + + CYASSL_MSG("Got Key"); + + if (badDate != 0) + return badDate; + + return ret; +} + + +static int GetSignature(DecodedCert* cert) +{ + int length; + byte b = cert->source[cert->srcIdx++]; + + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + cert->sigLength = length; + + b = cert->source[cert->srcIdx++]; + if (b != 0x00) + return ASN_EXPECT_0_E; + + cert->sigLength--; + cert->signature = &cert->source[cert->srcIdx]; + cert->srcIdx += cert->sigLength; + + return 0; +} + + +static word32 SetDigest(const byte* digest, word32 digSz, byte* output) +{ + output[0] = ASN_OCTET_STRING; + output[1] = (byte)digSz; + XMEMCPY(&output[2], digest, digSz); + + return digSz + 2; +} + + +static word32 BytePrecision(word32 value) +{ + word32 i; + for (i = sizeof(value); i; --i) + if (value >> ((i - 1) * CYASSL_BIT_SIZE)) + break; + + return i; +} + + +CYASSL_LOCAL word32 SetLength(word32 length, byte* output) +{ + word32 i = 0, j; + + if (length < ASN_LONG_LENGTH) + output[i++] = (byte)length; + else { + output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH); + + for (j = BytePrecision(length); j; --j) { + output[i] = (byte)(length >> ((j - 1) * CYASSL_BIT_SIZE)); + i++; + } + } + + return i; +} + + +CYASSL_LOCAL word32 SetSequence(word32 len, byte* output) +{ + output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + +CYASSL_LOCAL word32 SetOctetString(word32 len, byte* output) +{ + output[0] = ASN_OCTET_STRING; + return SetLength(len, output + 1) + 1; +} + +/* Write a set header to output */ +CYASSL_LOCAL word32 SetSet(word32 len, byte* output) +{ + output[0] = ASN_SET | ASN_CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + +CYASSL_LOCAL word32 SetImplicit(byte tag, byte number, word32 len, byte* output) +{ + + output[0] = ((tag == ASN_SEQUENCE || tag == ASN_SET) ? ASN_CONSTRUCTED : 0) + | ASN_CONTEXT_SPECIFIC | number; + return SetLength(len, output + 1) + 1; +} + +CYASSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output) +{ + output[0] = ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | number; + return SetLength(len, output + 1) + 1; +} + + +#if defined(HAVE_ECC) && defined(CYASSL_CERT_GEN) + +static word32 SetCurve(ecc_key* key, byte* output) +{ + + /* curve types */ + static const byte ECC_192v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, + 0x03, 0x01, 0x01}; + static const byte ECC_256v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, + 0x03, 0x01, 0x07}; + static const byte ECC_160r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, + 0x02}; + static const byte ECC_224r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, + 0x21}; + static const byte ECC_384r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, + 0x22}; + static const byte ECC_521r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00, + 0x23}; + + int oidSz = 0; + int idx = 0; + int lenSz = 0; + const byte* oid = 0; + + output[0] = ASN_OBJECT_ID; + idx++; + + switch (key->dp->size) { + case 20: + oidSz = sizeof(ECC_160r1_AlgoID); + oid = ECC_160r1_AlgoID; + break; + + case 24: + oidSz = sizeof(ECC_192v1_AlgoID); + oid = ECC_192v1_AlgoID; + break; + + case 28: + oidSz = sizeof(ECC_224r1_AlgoID); + oid = ECC_224r1_AlgoID; + break; + + case 32: + oidSz = sizeof(ECC_256v1_AlgoID); + oid = ECC_256v1_AlgoID; + break; + + case 48: + oidSz = sizeof(ECC_384r1_AlgoID); + oid = ECC_384r1_AlgoID; + break; + + case 66: + oidSz = sizeof(ECC_521r1_AlgoID); + oid = ECC_521r1_AlgoID; + break; + + default: + return ASN_UNKNOWN_OID_E; + } + lenSz = SetLength(oidSz, output+idx); + idx += lenSz; + + XMEMCPY(output+idx, oid, oidSz); + idx += oidSz; + + return idx; +} + +#endif /* HAVE_ECC && CYASSL_CERT_GEN */ + + +CYASSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) +{ + /* adding TAG_NULL and 0 to end */ + + /* hashTypes */ + static const byte shaAlgoID[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00 }; + static const byte sha256AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x01, 0x05, 0x00 }; + static const byte sha384AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x02, 0x05, 0x00 }; + static const byte sha512AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x03, 0x05, 0x00 }; + static const byte md5AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x05, 0x05, 0x00 }; + static const byte md2AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x02, 0x05, 0x00}; + + /* blkTypes, no NULL tags because IV is there instead */ + static const byte desCbcAlgoID[] = { 0x2B, 0x0E, 0x03, 0x02, 0x07 }; + static const byte des3CbcAlgoID[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x03, 0x07 }; + + /* RSA sigTypes */ + #ifndef NO_RSA + static const byte md5wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00}; + static const byte shawRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00}; + static const byte sha256wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00}; + static const byte sha384wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00}; + static const byte sha512wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00}; + #endif /* NO_RSA */ + + /* ECDSA sigTypes */ + #ifdef HAVE_ECC + static const byte shawECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, + 0x04, 0x01, 0x05, 0x00}; + static const byte sha256wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d, + 0x04, 0x03, 0x02, 0x05, 0x00}; + static const byte sha384wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d, + 0x04, 0x03, 0x03, 0x05, 0x00}; + static const byte sha512wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d, + 0x04, 0x03, 0x04, 0x05, 0x00}; + #endif /* HAVE_ECC */ + + /* RSA keyType */ + #ifndef NO_RSA + static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00}; + #endif /* NO_RSA */ + + #ifdef HAVE_ECC + /* ECC keyType */ + /* no tags, so set tagSz smaller later */ + static const byte ECC_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d, + 0x02, 0x01}; + #endif /* HAVE_ECC */ + + int algoSz = 0; + int tagSz = 2; /* tag null and terminator */ + word32 idSz, seqSz; + const byte* algoName = 0; + byte ID_Length[MAX_LENGTH_SZ]; + byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */ + + if (type == hashType) { + switch (algoOID) { + case SHAh: + algoSz = sizeof(shaAlgoID); + algoName = shaAlgoID; + break; + + case SHA256h: + algoSz = sizeof(sha256AlgoID); + algoName = sha256AlgoID; + break; + + case SHA384h: + algoSz = sizeof(sha384AlgoID); + algoName = sha384AlgoID; + break; + + case SHA512h: + algoSz = sizeof(sha512AlgoID); + algoName = sha512AlgoID; + break; + + case MD2h: + algoSz = sizeof(md2AlgoID); + algoName = md2AlgoID; + break; + + case MD5h: + algoSz = sizeof(md5AlgoID); + algoName = md5AlgoID; + break; + + default: + CYASSL_MSG("Unknown Hash Algo"); + return 0; /* UNKOWN_HASH_E; */ + } + } + else if (type == blkType) { + switch (algoOID) { + case DESb: + algoSz = sizeof(desCbcAlgoID); + algoName = desCbcAlgoID; + tagSz = 0; + break; + case DES3b: + algoSz = sizeof(des3CbcAlgoID); + algoName = des3CbcAlgoID; + tagSz = 0; + break; + default: + CYASSL_MSG("Unknown Block Algo"); + return 0; + } + } + else if (type == sigType) { /* sigType */ + switch (algoOID) { + #ifndef NO_RSA + case CTC_MD5wRSA: + algoSz = sizeof(md5wRSA_AlgoID); + algoName = md5wRSA_AlgoID; + break; + + case CTC_SHAwRSA: + algoSz = sizeof(shawRSA_AlgoID); + algoName = shawRSA_AlgoID; + break; + + case CTC_SHA256wRSA: + algoSz = sizeof(sha256wRSA_AlgoID); + algoName = sha256wRSA_AlgoID; + break; + + case CTC_SHA384wRSA: + algoSz = sizeof(sha384wRSA_AlgoID); + algoName = sha384wRSA_AlgoID; + break; + + case CTC_SHA512wRSA: + algoSz = sizeof(sha512wRSA_AlgoID); + algoName = sha512wRSA_AlgoID; + break; + #endif /* NO_RSA */ + #ifdef HAVE_ECC + case CTC_SHAwECDSA: + algoSz = sizeof(shawECDSA_AlgoID); + algoName = shawECDSA_AlgoID; + break; + + case CTC_SHA256wECDSA: + algoSz = sizeof(sha256wECDSA_AlgoID); + algoName = sha256wECDSA_AlgoID; + break; + + case CTC_SHA384wECDSA: + algoSz = sizeof(sha384wECDSA_AlgoID); + algoName = sha384wECDSA_AlgoID; + break; + + case CTC_SHA512wECDSA: + algoSz = sizeof(sha512wECDSA_AlgoID); + algoName = sha512wECDSA_AlgoID; + break; + #endif /* HAVE_ECC */ + default: + CYASSL_MSG("Unknown Signature Algo"); + return 0; + } + } + else if (type == keyType) { /* keyType */ + switch (algoOID) { + #ifndef NO_RSA + case RSAk: + algoSz = sizeof(RSA_AlgoID); + algoName = RSA_AlgoID; + break; + #endif /* NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + algoSz = sizeof(ECC_AlgoID); + algoName = ECC_AlgoID; + tagSz = 0; + break; + #endif /* HAVE_ECC */ + default: + CYASSL_MSG("Unknown Key Algo"); + return 0; + } + } + else { + CYASSL_MSG("Unknown Algo type"); + return 0; + } + + idSz = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */ + seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray); + /* +1 for object id, curveID of curveSz follows for ecc */ + seqArray[seqSz++] = ASN_OBJECT_ID; + + XMEMCPY(output, seqArray, seqSz); + XMEMCPY(output + seqSz, ID_Length, idSz); + XMEMCPY(output + seqSz + idSz, algoName, algoSz); + + return seqSz + idSz + algoSz; + +} + + +word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID) +{ + byte digArray[MAX_ENCODED_DIG_SZ]; + byte algoArray[MAX_ALGO_SZ]; + byte seqArray[MAX_SEQ_SZ]; + word32 encDigSz, algoSz, seqSz; + + encDigSz = SetDigest(digest, digSz, digArray); + algoSz = SetAlgoID(hashOID, algoArray, hashType, 0); + seqSz = SetSequence(encDigSz + algoSz, seqArray); + + XMEMCPY(out, seqArray, seqSz); + XMEMCPY(out + seqSz, algoArray, algoSz); + XMEMCPY(out + seqSz + algoSz, digArray, encDigSz); + + return encDigSz + algoSz + seqSz; +} + + +/* return true (1) for Confirmation */ +static int ConfirmSignature(const byte* buf, word32 bufSz, + const byte* key, word32 keySz, word32 keyOID, + const byte* sig, word32 sigSz, word32 sigOID, + void* heap) +{ +#ifdef CYASSL_SHA512 + byte digest[SHA512_DIGEST_SIZE]; /* max size */ +#elif !defined(NO_SHA256) + byte digest[SHA256_DIGEST_SIZE]; /* max size */ +#else + byte digest[SHA_DIGEST_SIZE]; /* max size */ +#endif + int typeH, digestSz, ret = 0; + + (void)key; + (void)keySz; + (void)sig; + (void)sigSz; + (void)heap; + (void)ret; + + switch (sigOID) { +#ifndef NO_MD5 + case CTC_MD5wRSA: + { + Md5 md5; + InitMd5(&md5); + Md5Update(&md5, buf, bufSz); + Md5Final(&md5, digest); + typeH = MD5h; + digestSz = MD5_DIGEST_SIZE; + } + break; +#endif + #if defined(CYASSL_MD2) + case CTC_MD2wRSA: + { + Md2 md2; + InitMd2(&md2); + Md2Update(&md2, buf, bufSz); + Md2Final(&md2, digest); + typeH = MD2h; + digestSz = MD2_DIGEST_SIZE; + } + break; + #endif +#ifndef NO_SHA + case CTC_SHAwRSA: + case CTC_SHAwDSA: + case CTC_SHAwECDSA: + { + Sha sha; + ret = InitSha(&sha); + if (ret != 0) { + CYASSL_MSG("InitSha failed"); + return 0; /* not confirmed */ + } + ShaUpdate(&sha, buf, bufSz); + ShaFinal(&sha, digest); + typeH = SHAh; + digestSz = SHA_DIGEST_SIZE; + } + break; +#endif + #ifndef NO_SHA256 + case CTC_SHA256wRSA: + case CTC_SHA256wECDSA: + { + Sha256 sha256; + ret = InitSha256(&sha256); + if (ret != 0) { + CYASSL_MSG("InitSha256 failed"); + return 0; /* not confirmed */ + } + + ret = Sha256Update(&sha256, buf, bufSz); + if (ret != 0) { + CYASSL_MSG("Sha256Update failed"); + return 0; /* not confirmed */ + } + + ret = Sha256Final(&sha256, digest); + if (ret != 0) { + CYASSL_MSG("Sha256Final failed"); + return 0; /* not confirmed */ + } + + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + } + break; + #endif + #ifdef CYASSL_SHA512 + case CTC_SHA512wRSA: + case CTC_SHA512wECDSA: + { + Sha512 sha512; + ret = InitSha512(&sha512); + if (ret != 0) { + CYASSL_MSG("InitSha512 failed"); + return 0; /* not confirmed */ + } + + ret = Sha512Update(&sha512, buf, bufSz); + if (ret != 0) { + CYASSL_MSG("Sha512Update failed"); + return 0; /* not confirmed */ + } + + ret = Sha512Final(&sha512, digest); + if (ret != 0) { + CYASSL_MSG("Sha512Final failed"); + return 0; /* not confirmed */ + } + + typeH = SHA512h; + digestSz = SHA512_DIGEST_SIZE; + } + break; + #endif + #ifdef CYASSL_SHA384 + case CTC_SHA384wRSA: + case CTC_SHA384wECDSA: + { + Sha384 sha384; + ret = InitSha384(&sha384); + if (ret != 0) { + CYASSL_MSG("InitSha384 failed"); + return 0; /* not confirmed */ + } + + ret = Sha384Update(&sha384, buf, bufSz); + if (ret != 0) { + CYASSL_MSG("Sha384Update failed"); + return 0; /* not confirmed */ + } + + ret = Sha384Final(&sha384, digest); + if (ret != 0) { + CYASSL_MSG("Sha384Final failed"); + return 0; /* not confirmed */ + } + + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + } + break; + #endif + default: + CYASSL_MSG("Verify Signautre has unsupported type"); + return 0; + } + (void)typeH; /* some builds won't read */ + + switch (keyOID) { + #ifndef NO_RSA + case RSAk: + { + RsaKey pubKey; + byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte plain[MAX_ENCODED_SIG_SZ]; + word32 idx = 0; + int encodedSigSz, verifySz; + byte* out; + + if (sigSz > MAX_ENCODED_SIG_SZ) { + CYASSL_MSG("Verify Signautre is too big"); + return 0; + } + + ret = InitRsaKey(&pubKey, heap); + if (ret != 0) return ret; + if (RsaPublicKeyDecode(key, &idx, &pubKey, keySz) < 0) { + CYASSL_MSG("ASN Key decode error RSA"); + ret = 0; + } + else { + XMEMCPY(plain, sig, sigSz); + if ( (verifySz = RsaSSL_VerifyInline(plain, sigSz, &out, + &pubKey)) < 0) { + CYASSL_MSG("Rsa SSL verify error"); + ret = 0; + } + else { + /* make sure we're right justified */ + encodedSigSz = + EncodeSignature(encodedSig, digest, digestSz, typeH); + if (encodedSigSz != verifySz || + XMEMCMP(out, encodedSig, encodedSigSz) != 0) { + CYASSL_MSG("Rsa SSL verify match encode error"); + ret = 0; + } + else + ret = 1; /* match */ + + #ifdef CYASSL_DEBUG_ENCODING + { + int x; + printf("cyassl encodedSig:\n"); + for (x = 0; x < encodedSigSz; x++) { + printf("%02x ", encodedSig[x]); + if ( (x % 16) == 15) + printf("\n"); + } + printf("\n"); + printf("actual digest:\n"); + for (x = 0; x < verifySz; x++) { + printf("%02x ", out[x]); + if ( (x % 16) == 15) + printf("\n"); + } + printf("\n"); + } + #endif /* CYASSL_DEBUG_ENCODING */ + } + } + FreeRsaKey(&pubKey); + return ret; + } + + #endif /* NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + { + ecc_key pubKey; + int verify = 0; + + if (ecc_import_x963(key, keySz, &pubKey) < 0) { + CYASSL_MSG("ASN Key import error ECC"); + return 0; + } + + ret = ecc_verify_hash(sig,sigSz,digest,digestSz,&verify,&pubKey); + ecc_free(&pubKey); + if (ret == 0 && verify == 1) + return 1; /* match */ + + CYASSL_MSG("ECC Verify didn't match"); + return 0; + } + #endif /* HAVE_ECC */ + default: + CYASSL_MSG("Verify Key type unknown"); + return 0; + } +} + + +#ifndef IGNORE_NAME_CONSTRAINTS + +static int MatchBaseName(int type, const char* name, int nameSz, + const char* base, int baseSz) +{ + if (base == NULL || baseSz <= 0 || name == NULL || nameSz <= 0 || + name[0] == '.' || nameSz < baseSz || + (type != ASN_RFC822_TYPE && type != ASN_DNS_TYPE)) + return 0; + + /* If an email type, handle special cases where the base is only + * a domain, or is an email address itself. */ + if (type == ASN_RFC822_TYPE) { + const char* p = NULL; + int count = 0; + + if (base[0] != '.') { + p = base; + count = 0; + + /* find the '@' in the base */ + while (*p != '@' && count < baseSz) { + count++; + p++; + } + + /* No '@' in base, reset p to NULL */ + if (count >= baseSz) + p = NULL; + } + + if (p == NULL) { + /* Base isn't an email address, it is a domain name, + * wind the name forward one character past its '@'. */ + p = name; + count = 0; + while (*p != '@' && count < baseSz) { + count++; + p++; + } + + if (count < baseSz && *p == '@') { + name = p + 1; + nameSz -= count + 1; + } + } + } + + if ((type == ASN_DNS_TYPE || type == ASN_RFC822_TYPE) && base[0] == '.') { + int szAdjust = nameSz - baseSz; + name += szAdjust; + nameSz -= szAdjust; + } + + while (nameSz > 0) { + if (XTOLOWER(*name++) != XTOLOWER(*base++)) + return 0; + nameSz--; + } + + return 1; +} + + +static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) +{ + if (signer == NULL || cert == NULL) + return 0; + + /* Check against the excluded list */ + if (signer->excludedNames) { + Base_entry* base = signer->excludedNames; + + while (base != NULL) { + if (base->type == ASN_DNS_TYPE) { + DNS_entry* name = cert->altNames; + while (name != NULL) { + if (MatchBaseName(ASN_DNS_TYPE, + name->name, (int)XSTRLEN(name->name), + base->name, base->nameSz)) + return 0; + name = name->next; + } + } + else if (base->type == ASN_RFC822_TYPE) { + DNS_entry* name = cert->altEmailNames; + while (name != NULL) { + if (MatchBaseName(ASN_RFC822_TYPE, + name->name, (int)XSTRLEN(name->name), + base->name, base->nameSz)) + return 0; + + name = name->next; + } + } + else if (base->type == ASN_DIR_TYPE) { + if (cert->subjectRawLen == base->nameSz && + XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) { + + return 0; + } + } + base = base->next; + } + } + + /* Check against the permitted list */ + if (signer->permittedNames != NULL) { + int needDns = 0; + int matchDns = 0; + int needEmail = 0; + int matchEmail = 0; + int needDir = 0; + int matchDir = 0; + Base_entry* base = signer->permittedNames; + + while (base != NULL) { + if (base->type == ASN_DNS_TYPE) { + DNS_entry* name = cert->altNames; + + if (name != NULL) + needDns = 1; + + while (name != NULL) { + matchDns = MatchBaseName(ASN_DNS_TYPE, + name->name, (int)XSTRLEN(name->name), + base->name, base->nameSz); + name = name->next; + } + } + else if (base->type == ASN_RFC822_TYPE) { + DNS_entry* name = cert->altEmailNames; + + if (name != NULL) + needEmail = 1; + + while (name != NULL) { + matchEmail = MatchBaseName(ASN_DNS_TYPE, + name->name, (int)XSTRLEN(name->name), + base->name, base->nameSz); + name = name->next; + } + } + else if (base->type == ASN_DIR_TYPE) { + needDir = 1; + if (cert->subjectRaw != NULL && + cert->subjectRawLen == base->nameSz && + XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) { + + matchDir = 1; + } + } + base = base->next; + } + + if ((needDns && !matchDns) || (needEmail && !matchEmail) || + (needDir && !matchDir)) { + + return 0; + } + } + + return 1; +} + +#endif /* IGNORE_NAME_CONSTRAINTS */ + + +static int DecodeAltNames(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0; + + CYASSL_ENTER("DecodeAltNames"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tBad Sequence"); + return ASN_PARSE_E; + } + + while (length > 0) { + byte b = input[idx++]; + + length--; + + /* Save DNS Type names in the altNames list. */ + /* Save Other Type names in the cert's OidMap */ + if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) { + DNS_entry* dnsEntry; + int strLen; + word32 lenStartIdx = idx; + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfail: str length"); + return ASN_PARSE_E; + } + length -= (idx - lenStartIdx); + + dnsEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (dnsEntry == NULL) { + CYASSL_MSG("\tOut of Memory"); + return ASN_PARSE_E; + } + + dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (dnsEntry->name == NULL) { + CYASSL_MSG("\tOut of Memory"); + XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME); + return ASN_PARSE_E; + } + + XMEMCPY(dnsEntry->name, &input[idx], strLen); + dnsEntry->name[strLen] = '\0'; + + dnsEntry->next = cert->altNames; + cert->altNames = dnsEntry; + + length -= strLen; + idx += strLen; + } +#ifndef IGNORE_NAME_CONSTRAINTS + else if (b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) { + DNS_entry* emailEntry; + int strLen; + word32 lenStartIdx = idx; + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfail: str length"); + return ASN_PARSE_E; + } + length -= (idx - lenStartIdx); + + emailEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (emailEntry == NULL) { + CYASSL_MSG("\tOut of Memory"); + return ASN_PARSE_E; + } + + emailEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (emailEntry->name == NULL) { + CYASSL_MSG("\tOut of Memory"); + XFREE(emailEntry, cert->heap, DYNAMIC_TYPE_ALTNAME); + return ASN_PARSE_E; + } + + XMEMCPY(emailEntry->name, &input[idx], strLen); + emailEntry->name[strLen] = '\0'; + + emailEntry->next = cert->altEmailNames; + cert->altEmailNames = emailEntry; + + length -= strLen; + idx += strLen; + } +#endif /* IGNORE_NAME_CONSTRAINTS */ +#ifdef CYASSL_SEP + else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE)) + { + int strLen; + word32 lenStartIdx = idx; + word32 oid = 0; + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfail: other name length"); + return ASN_PARSE_E; + } + /* Consume the rest of this sequence. */ + length -= (strLen + idx - lenStartIdx); + + if (GetObjectId(input, &idx, &oid, sz) < 0) { + CYASSL_MSG("\tbad OID"); + return ASN_PARSE_E; + } + + if (oid != HW_NAME_OID) { + CYASSL_MSG("\tincorrect OID"); + return ASN_PARSE_E; + } + + if (input[idx++] != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { + CYASSL_MSG("\twrong type"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfail: str len"); + return ASN_PARSE_E; + } + + if (GetSequence(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tBad Sequence"); + return ASN_PARSE_E; + } + + if (input[idx++] != ASN_OBJECT_ID) { + CYASSL_MSG("\texpected OID"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfailed: str len"); + return ASN_PARSE_E; + } + + cert->hwType = (byte*)XMALLOC(strLen, cert->heap, 0); + if (cert->hwType == NULL) { + CYASSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + + XMEMCPY(cert->hwType, &input[idx], strLen); + cert->hwTypeSz = strLen; + idx += strLen; + + if (input[idx++] != ASN_OCTET_STRING) { + CYASSL_MSG("\texpected Octet String"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfailed: str len"); + return ASN_PARSE_E; + } + + cert->hwSerialNum = (byte*)XMALLOC(strLen + 1, cert->heap, 0); + if (cert->hwSerialNum == NULL) { + CYASSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + + XMEMCPY(cert->hwSerialNum, &input[idx], strLen); + cert->hwSerialNum[strLen] = '\0'; + cert->hwSerialNumSz = strLen; + idx += strLen; + } +#endif /* CYASSL_SEP */ + else { + int strLen; + word32 lenStartIdx = idx; + + CYASSL_MSG("\tUnsupported name type, skipping"); + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfail: unsupported name length"); + return ASN_PARSE_E; + } + length -= (strLen + idx - lenStartIdx); + idx += strLen; + } + } + return 0; +} + + +static int DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0; + + CYASSL_ENTER("DecodeBasicCaConstraint"); + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: bad SEQUENCE"); + return ASN_PARSE_E; + } + + if (length == 0) + return 0; + + /* If the basic ca constraint is false, this extension may be named, but + * left empty. So, if the length is 0, just return. */ + + if (input[idx++] != ASN_BOOLEAN) + { + CYASSL_MSG("\tfail: constraint not BOOLEAN"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) + { + CYASSL_MSG("\tfail: length"); + return ASN_PARSE_E; + } + + if (input[idx++]) + cert->isCA = 1; + + #ifdef OPENSSL_EXTRA + /* If there isn't any more data, return. */ + if (idx >= (word32)sz) + return 0; + + /* Anything left should be the optional pathlength */ + if (input[idx++] != ASN_INTEGER) { + CYASSL_MSG("\tfail: pathlen not INTEGER"); + return ASN_PARSE_E; + } + + if (input[idx++] != 1) { + CYASSL_MSG("\tfail: pathlen too long"); + return ASN_PARSE_E; + } + + cert->pathLength = input[idx]; + cert->extBasicConstPlSet = 1; + #endif /* OPENSSL_EXTRA */ + + return 0; +} + + +#define CRLDP_FULL_NAME 0 + /* From RFC3280 SS4.2.1.14, Distribution Point Name*/ +#define GENERALNAME_URI 6 + /* From RFC3280 SS4.2.1.7, GeneralName */ + +static int DecodeCrlDist(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0; + + CYASSL_ENTER("DecodeCrlDist"); + + /* Unwrap the list of Distribution Points*/ + if (GetSequence(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + /* Unwrap a single Distribution Point */ + if (GetSequence(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + /* The Distribution Point has three explicit optional members + * First check for a DistributionPointName + */ + if (input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) + { + idx++; + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + if (input[idx] == + (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CRLDP_FULL_NAME)) + { + idx++; + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + if (input[idx] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI)) + { + idx++; + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + cert->extCrlInfoSz = length; + cert->extCrlInfo = input + idx; + idx += length; + } + else + /* This isn't a URI, skip it. */ + idx += length; + } + else + /* This isn't a FULLNAME, skip it. */ + idx += length; + } + + /* Check for reasonFlags */ + if (idx < (word32)sz && + input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) + { + idx++; + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + idx += length; + } + + /* Check for cRLIssuer */ + if (idx < (word32)sz && + input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2)) + { + idx++; + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + idx += length; + } + + if (idx < (word32)sz) + { + CYASSL_MSG("\tThere are more CRL Distribution Point records, " + "but we only use the first one."); + } + + return 0; +} + + +static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert) +/* + * Read the first of the Authority Information Access records. If there are + * any issues, return without saving the record. + */ +{ + word32 idx = 0; + int length = 0; + byte b; + word32 oid; + + CYASSL_ENTER("DecodeAuthInfo"); + + /* Unwrap the list of AIAs */ + if (GetSequence(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + while (idx < (word32)sz) { + /* Unwrap a single AIA */ + if (GetSequence(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + oid = 0; + if (GetObjectId(input, &idx, &oid, sz) < 0) + return ASN_PARSE_E; + + /* Only supporting URIs right now. */ + b = input[idx++]; + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + if (b == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI) && + oid == AIA_OCSP_OID) + { + cert->extAuthInfoSz = length; + cert->extAuthInfo = input + idx; + break; + } + idx += length; + } + + return 0; +} + + +static int DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0, ret = 0; + + CYASSL_ENTER("DecodeAuthKeyId"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE\n"); + return ASN_PARSE_E; + } + + if (input[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) { + CYASSL_MSG("\tfail: wanted OPTIONAL item 0, not available\n"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: extension data length"); + return ASN_PARSE_E; + } + + #ifdef OPENSSL_EXTRA + cert->extAuthKeyIdSrc = &input[idx]; + cert->extAuthKeyIdSz = length; + #endif /* OPENSSL_EXTRA */ + + if (length == SHA_SIZE) { + XMEMCPY(cert->extAuthKeyId, input + idx, length); + } + else { + Sha sha; + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, input + idx, length); + ShaFinal(&sha, cert->extAuthKeyId); + } + + return 0; +} + + +static int DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0, ret = 0; + + CYASSL_ENTER("DecodeSubjKeyId"); + + if (input[idx++] != ASN_OCTET_STRING) { + CYASSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: extension data length"); + return ASN_PARSE_E; + } + + #ifdef OPENSSL_EXTRA + cert->extSubjKeyIdSrc = &input[idx]; + cert->extSubjKeyIdSz = length; + #endif /* OPENSSL_EXTRA */ + + if (length == SIGNER_DIGEST_SIZE) { + XMEMCPY(cert->extSubjKeyId, input + idx, length); + } + else { + Sha sha; + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, input + idx, length); + ShaFinal(&sha, cert->extSubjKeyId); + } + + return ret; +} + + +static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length; + byte unusedBits; + CYASSL_ENTER("DecodeKeyUsage"); + + if (input[idx++] != ASN_BIT_STRING) { + CYASSL_MSG("\tfail: key usage expected bit string"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: key usage bad length"); + return ASN_PARSE_E; + } + + unusedBits = input[idx++]; + length--; + + if (length == 2) { + cert->extKeyUsage = (word16)((input[idx] << 8) | input[idx+1]); + cert->extKeyUsage >>= unusedBits; + } + else if (length == 1) + cert->extKeyUsage = (word16)(input[idx] << 1); + + return 0; +} + + +static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0, oid; + int length; + + CYASSL_ENTER("DecodeExtKeyUsage"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + #ifdef OPENSSL_EXTRA + cert->extExtKeyUsageSrc = input + idx; + cert->extExtKeyUsageSz = length; + #endif + + while (idx < (word32)sz) { + if (GetObjectId(input, &idx, &oid, sz) < 0) + return ASN_PARSE_E; + + switch (oid) { + case EKU_ANY_OID: + cert->extExtKeyUsage |= EXTKEYUSE_ANY; + break; + case EKU_SERVER_AUTH_OID: + cert->extExtKeyUsage |= EXTKEYUSE_SERVER_AUTH; + break; + case EKU_CLIENT_AUTH_OID: + cert->extExtKeyUsage |= EXTKEYUSE_CLIENT_AUTH; + break; + case EKU_OCSP_SIGN_OID: + cert->extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN; + break; + } + + #ifdef OPENSSL_EXTRA + cert->extExtKeyUsageCount++; + #endif + } + + return 0; +} + + +#ifndef IGNORE_NAME_CONSTRAINTS +static int DecodeSubtree(byte* input, int sz, Base_entry** head, void* heap) +{ + word32 idx = 0; + + (void)heap; + + while (idx < (word32)sz) { + int seqLength, strLength; + word32 nameIdx; + byte b; + + if (GetSequence(input, &idx, &seqLength, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + nameIdx = idx; + b = input[nameIdx++]; + if (GetLength(input, &nameIdx, &strLength, sz) <= 0) { + CYASSL_MSG("\tinvalid length"); + return ASN_PARSE_E; + } + + if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE) || + b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE) || + b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE)) { + + Base_entry* entry = (Base_entry*)XMALLOC(sizeof(Base_entry), + heap, DYNAMIC_TYPE_ALTNAME); + + if (entry == NULL) { + CYASSL_MSG("allocate error"); + return MEMORY_E; + } + + entry->name = (char*)XMALLOC(strLength, heap, DYNAMIC_TYPE_ALTNAME); + if (entry->name == NULL) { + CYASSL_MSG("allocate error"); + return MEMORY_E; + } + + XMEMCPY(entry->name, &input[nameIdx], strLength); + entry->nameSz = strLength; + entry->type = b & 0x0F; + + entry->next = *head; + *head = entry; + } + + idx += seqLength; + } + + return 0; +} + + +static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0; + + CYASSL_ENTER("DecodeNameConstraints"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + while (idx < (word32)sz) { + byte b = input[idx++]; + Base_entry** subtree = NULL; + + if (GetLength(input, &idx, &length, sz) <= 0) { + CYASSL_MSG("\tinvalid length"); + return ASN_PARSE_E; + } + + if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) + subtree = &cert->permittedNames; + else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) + subtree = &cert->excludedNames; + else { + CYASSL_MSG("\tinvalid subtree"); + return ASN_PARSE_E; + } + + DecodeSubtree(input + idx, length, subtree, cert->heap); + + idx += length; + } + + return 0; +} +#endif /* IGNORE_NAME_CONSTRAINTS */ + + +#ifdef CYASSL_SEP + static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert) + { + word32 idx = 0; + int length = 0; + + CYASSL_ENTER("DecodeCertPolicy"); + + /* Unwrap certificatePolicies */ + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (input[idx++] != ASN_OBJECT_ID) { + CYASSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tCouldn't read length of deviceType"); + return ASN_PARSE_E; + } + + if (length > 0) { + cert->deviceType = (byte*)XMALLOC(length, cert->heap, 0); + if (cert->deviceType == NULL) { + CYASSL_MSG("\tCouldn't alloc memory for deviceType"); + return MEMORY_E; + } + cert->deviceTypeSz = length; + XMEMCPY(cert->deviceType, input + idx, length); + } + + CYASSL_LEAVE("DecodeCertPolicy", 0); + return 0; + } +#endif /* CYASSL_SEP */ + + +static int DecodeCertExtensions(DecodedCert* cert) +/* + * Processing the Certificate Extensions. This does not modify the current + * index. It is works starting with the recorded extensions pointer. + */ +{ + word32 idx = 0; + int sz = cert->extensionsSz; + byte* input = cert->extensions; + int length; + word32 oid; + byte critical = 0; + byte criticalFail = 0; + + CYASSL_ENTER("DecodeCertExtensions"); + + if (input == NULL || sz == 0) + return BAD_FUNC_ARG; + + if (input[idx++] != ASN_EXTENSIONS) + return ASN_PARSE_E; + + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + if (GetSequence(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + while (idx < (word32)sz) { + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + oid = 0; + if (GetObjectId(input, &idx, &oid, sz) < 0) { + CYASSL_MSG("\tfail: OBJECT ID"); + return ASN_PARSE_E; + } + + /* check for critical flag */ + critical = 0; + if (input[idx] == ASN_BOOLEAN) { + int boolLength = 0; + idx++; + if (GetLength(input, &idx, &boolLength, sz) < 0) { + CYASSL_MSG("\tfail: critical boolean length"); + return ASN_PARSE_E; + } + if (input[idx++]) + critical = 1; + } + + /* process the extension based on the OID */ + if (input[idx++] != ASN_OCTET_STRING) { + CYASSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: extension data length"); + return ASN_PARSE_E; + } + + switch (oid) { + case BASIC_CA_OID: + #ifdef OPENSSL_EXTRA + cert->extBasicConstSet = 1; + cert->extBasicConstCrit = critical; + #endif + if (DecodeBasicCaConstraint(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case CRL_DIST_OID: + if (DecodeCrlDist(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case AUTH_INFO_OID: + if (DecodeAuthInfo(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case ALT_NAMES_OID: + #ifdef OPENSSL_EXTRA + cert->extSubjAltNameSet = 1; + cert->extSubjAltNameCrit = critical; + #endif + if (DecodeAltNames(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case AUTH_KEY_OID: + cert->extAuthKeyIdSet = 1; + #ifdef OPENSSL_EXTRA + cert->extAuthKeyIdCrit = critical; + #endif + if (DecodeAuthKeyId(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case SUBJ_KEY_OID: + cert->extSubjKeyIdSet = 1; + #ifdef OPENSSL_EXTRA + cert->extSubjKeyIdCrit = critical; + #endif + if (DecodeSubjKeyId(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case CERT_POLICY_OID: + CYASSL_MSG("Certificate Policy extension not supported yet."); + #ifdef CYASSL_SEP + #ifdef OPENSSL_EXTRA + cert->extCertPolicySet = 1; + cert->extCertPolicyCrit = critical; + #endif + if (DecodeCertPolicy(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + #endif + break; + + case KEY_USAGE_OID: + cert->extKeyUsageSet = 1; + #ifdef OPENSSL_EXTRA + cert->extKeyUsageCrit = critical; + #endif + if (DecodeKeyUsage(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + case EXT_KEY_USAGE_OID: + cert->extExtKeyUsageSet = 1; + #ifdef OPENSSL_EXTRA + cert->extExtKeyUsageCrit = critical; + #endif + if (DecodeExtKeyUsage(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + + #ifndef IGNORE_NAME_CONSTRAINTS + case NAME_CONS_OID: + cert->extNameConstraintSet = 1; + #ifdef OPENSSL_EXTRA + cert->extNameConstraintCrit = critical; + #endif + if (DecodeNameConstraints(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + #endif /* IGNORE_NAME_CONSTRAINTS */ + + case INHIBIT_ANY_OID: + CYASSL_MSG("Inhibit anyPolicy extension not supported yet."); + break; + + default: + /* While it is a failure to not support critical extensions, + * still parse the certificate ignoring the unsupported + * extention to allow caller to accept it with the verify + * callback. */ + if (critical) + criticalFail = 1; + break; + } + idx += length; + } + + return criticalFail ? ASN_CRIT_EXT_E : 0; +} + + +int ParseCert(DecodedCert* cert, int type, int verify, void* cm) +{ + int ret; + char* ptr; + + ret = ParseCertRelative(cert, type, verify, cm); + if (ret < 0) + return ret; + + if (cert->subjectCNLen > 0) { + ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap, + DYNAMIC_TYPE_SUBJECT_CN); + if (ptr == NULL) + return MEMORY_E; + XMEMCPY(ptr, cert->subjectCN, cert->subjectCNLen); + ptr[cert->subjectCNLen] = '\0'; + cert->subjectCN = ptr; + cert->subjectCNStored = 1; + } + + if (cert->keyOID == RSAk && + cert->publicKey != NULL && cert->pubKeySize > 0) { + ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (ptr == NULL) + return MEMORY_E; + XMEMCPY(ptr, cert->publicKey, cert->pubKeySize); + cert->publicKey = (byte *)ptr; + cert->pubKeyStored = 1; + } + + return ret; +} + + +/* from SSL proper, for locking can't do find here anymore */ +#ifdef __cplusplus + extern "C" { +#endif + CYASSL_LOCAL Signer* GetCA(void* signers, byte* hash); + #ifndef NO_SKID + CYASSL_LOCAL Signer* GetCAByName(void* signers, byte* hash); + #endif +#ifdef __cplusplus + } +#endif + + +int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) +{ + word32 confirmOID; + int ret; + int badDate = 0; + int criticalExt = 0; + + if ((ret = DecodeToKey(cert, verify)) < 0) { + if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E) + badDate = ret; + else + return ret; + } + + CYASSL_MSG("Parsed Past Key"); + + if (cert->srcIdx < cert->sigIndex) { + #ifndef ALLOW_V1_EXTENSIONS + if (cert->version < 2) { + CYASSL_MSG(" v1 and v2 certs not allowed extensions"); + return ASN_VERSION_E; + } + #endif + /* save extensions */ + cert->extensions = &cert->source[cert->srcIdx]; + cert->extensionsSz = cert->sigIndex - cert->srcIdx; + cert->extensionsIdx = cert->srcIdx; /* for potential later use */ + + if ((ret = DecodeCertExtensions(cert)) < 0) { + if (ret == ASN_CRIT_EXT_E) + criticalExt = ret; + else + return ret; + } + + /* advance past extensions */ + cert->srcIdx = cert->sigIndex; + } + + if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID, + cert->maxIdx)) < 0) + return ret; + + if ((ret = GetSignature(cert)) < 0) + return ret; + + if (confirmOID != cert->signatureOID) + return ASN_SIG_OID_E; + + #ifndef NO_SKID + if (cert->extSubjKeyIdSet == 0 + && cert->publicKey != NULL && cert->pubKeySize > 0) { + Sha sha; + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, cert->publicKey, cert->pubKeySize); + ShaFinal(&sha, cert->extSubjKeyId); + } + #endif + + if (verify && type != CA_TYPE) { + Signer* ca = NULL; + #ifndef NO_SKID + if (cert->extAuthKeyIdSet) + ca = GetCA(cm, cert->extAuthKeyId); + if (ca == NULL) + ca = GetCAByName(cm, cert->issuerHash); + #else /* NO_SKID */ + ca = GetCA(cm, cert->issuerHash); + #endif /* NO SKID */ + CYASSL_MSG("About to verify certificate signature"); + + if (ca) { +#ifdef HAVE_OCSP + /* Need the ca's public key hash for OCSP */ + { + Sha sha; + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, ca->publicKey, ca->pubKeySize); + ShaFinal(&sha, cert->issuerKeyHash); + } +#endif /* HAVE_OCSP */ + /* try to confirm/verify signature */ + if (!ConfirmSignature(cert->source + cert->certBegin, + cert->sigIndex - cert->certBegin, + ca->publicKey, ca->pubKeySize, ca->keyOID, + cert->signature, cert->sigLength, cert->signatureOID, + cert->heap)) { + CYASSL_MSG("Confirm signature failed"); + return ASN_SIG_CONFIRM_E; + } +#ifndef IGNORE_NAME_CONSTRAINTS + /* check that this cert's name is permitted by the signer's + * name constraints */ + if (!ConfirmNameConstraints(ca, cert)) { + CYASSL_MSG("Confirm name constraint failed"); + return ASN_NAME_INVALID_E; + } +#endif /* IGNORE_NAME_CONSTRAINTS */ + } + else { + /* no signer */ + CYASSL_MSG("No CA signer to verify with"); + return ASN_NO_SIGNER_E; + } + } + + if (badDate != 0) + return badDate; + + if (criticalExt != 0) + return criticalExt; + + return 0; +} + + +/* Create and init an new signer */ +Signer* MakeSigner(void* heap) +{ + Signer* signer = (Signer*) XMALLOC(sizeof(Signer), heap, + DYNAMIC_TYPE_SIGNER); + if (signer) { + signer->pubKeySize = 0; + signer->keyOID = 0; + signer->publicKey = NULL; + signer->nameLen = 0; + signer->name = NULL; + #ifndef IGNORE_NAME_CONSTRAINTS + signer->permittedNames = NULL; + signer->excludedNames = NULL; + #endif /* IGNORE_NAME_CONSTRAINTS */ + signer->next = NULL; + } + (void)heap; + + return signer; +} + + +/* Free an individual signer */ +void FreeSigner(Signer* signer, void* heap) +{ + XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN); + XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); + #ifndef IGNORE_NAME_CONSTRAINTS + if (signer->permittedNames) + FreeNameSubtrees(signer->permittedNames, heap); + if (signer->excludedNames) + FreeNameSubtrees(signer->excludedNames, heap); + #endif + XFREE(signer, heap, DYNAMIC_TYPE_SIGNER); + + (void)heap; +} + + +/* Free the whole singer table with number of rows */ +void FreeSignerTable(Signer** table, int rows, void* heap) +{ + int i; + + for (i = 0; i < rows; i++) { + Signer* signer = table[i]; + while (signer) { + Signer* next = signer->next; + FreeSigner(signer, heap); + signer = next; + } + table[i] = NULL; + } +} + + +CYASSL_LOCAL int SetMyVersion(word32 version, byte* output, int header) +{ + int i = 0; + + if (header) { + output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED; + output[i++] = ASN_BIT_STRING; + } + output[i++] = ASN_INTEGER; + output[i++] = 0x01; + output[i++] = (byte)version; + + return i; +} + + +CYASSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output) +{ + int result = 0; + + CYASSL_ENTER("SetSerialNumber"); + + if (snSz <= EXTERNAL_SERIAL_SIZE) { + output[0] = ASN_INTEGER; + /* The serial number is always positive. When encoding the + * INTEGER, if the MSB is 1, add a padding zero to keep the + * number positive. */ + if (sn[0] & 0x80) { + output[1] = (byte)snSz + 1; + output[2] = 0; + XMEMCPY(&output[3], sn, snSz); + result = snSz + 3; + } + else { + output[1] = (byte)snSz; + XMEMCPY(&output[2], sn, snSz); + result = snSz + 2; + } + } + return result; +} + + + + +#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) + +/* convert der buffer to pem into output, can't do inplace, der and output + need to be different */ +int DerToPem(const byte* der, word32 derSz, byte* output, word32 outSz, + int type) +{ + char header[80]; + char footer[80]; + + int headerLen; + int footerLen; + int i; + int err; + int outLen; /* return length or error */ + + if (der == output) /* no in place conversion */ + return BAD_FUNC_ARG; + + if (type == CERT_TYPE) { + XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", sizeof(header)); + XSTRNCPY(footer, "-----END CERTIFICATE-----\n", sizeof(footer)); + } + else if (type == PRIVATEKEY_TYPE) { + XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", sizeof(header)); + XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n", sizeof(footer)); + } + #ifdef HAVE_ECC + else if (type == ECC_PRIVATEKEY_TYPE) { + XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----\n", sizeof(header)); + XSTRNCPY(footer, "-----END EC PRIVATE KEY-----\n", sizeof(footer)); + } + #endif + #ifdef CYASSL_CERT_REQ + else if (type == CERTREQ_TYPE) + { + XSTRNCPY(header, + "-----BEGIN CERTIFICATE REQUEST-----\n", sizeof(header)); + XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----\n", sizeof(footer)); + } + #endif + else + return BAD_FUNC_ARG; + + headerLen = (int)XSTRLEN(header); + footerLen = (int)XSTRLEN(footer); + + if (!der || !output) + return BAD_FUNC_ARG; + + /* don't even try if outSz too short */ + if (outSz < headerLen + footerLen + derSz) + return BAD_FUNC_ARG; + + /* header */ + XMEMCPY(output, header, headerLen); + i = headerLen; + + /* body */ + outLen = outSz - (headerLen + footerLen); /* input to Base64_Encode */ + if ( (err = Base64_Encode(der, derSz, output + i, (word32*)&outLen)) < 0) + return err; + i += outLen; + + /* footer */ + if ( (i + footerLen) > (int)outSz) + return BAD_FUNC_ARG; + XMEMCPY(output + i, footer, footerLen); + + return outLen + headerLen + footerLen; +} + + +#endif /* CYASSL_KEY_GEN || CYASSL_CERT_GEN */ + + +#if defined(CYASSL_KEY_GEN) && !defined(NO_RSA) + + +static mp_int* GetRsaInt(RsaKey* key, int idx) +{ + if (idx == 0) + return &key->n; + if (idx == 1) + return &key->e; + if (idx == 2) + return &key->d; + if (idx == 3) + return &key->p; + if (idx == 4) + return &key->q; + if (idx == 5) + return &key->dP; + if (idx == 6) + return &key->dQ; + if (idx == 7) + return &key->u; + + return NULL; +} + + +/* Release Tmp RSA resources */ +static INLINE void FreeTmpRsas(byte** tmps, void* heap) +{ + int i; + + (void)heap; + + for (i = 0; i < RSA_INTS; i++) + XFREE(tmps[i], heap, DYNAMIC_TYPE_RSA); +} + + +/* Convert RsaKey key to DER format, write to output (inLen), return bytes + written */ +int RsaKeyToDer(RsaKey* key, byte* output, word32 inLen) +{ + word32 seqSz, verSz, rawLen, intTotalLen = 0; + word32 sizes[RSA_INTS]; + int i, j, outLen, ret = 0; + + byte seq[MAX_SEQ_SZ]; + byte ver[MAX_VERSION_SZ]; + byte* tmps[RSA_INTS]; + + if (!key || !output) + return BAD_FUNC_ARG; + + if (key->type != RSA_PRIVATE) + return BAD_FUNC_ARG; + + for (i = 0; i < RSA_INTS; i++) + tmps[i] = NULL; + + /* write all big ints from key to DER tmps */ + for (i = 0; i < RSA_INTS; i++) { + mp_int* keyInt = GetRsaInt(key, i); + rawLen = mp_unsigned_bin_size(keyInt); + tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap, + DYNAMIC_TYPE_RSA); + if (tmps[i] == NULL) { + ret = MEMORY_E; + break; + } + + tmps[i][0] = ASN_INTEGER; + sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1; /* int tag */ + + if (sizes[i] <= MAX_SEQ_SZ) { + int err = mp_to_unsigned_bin(keyInt, tmps[i] + sizes[i]); + if (err == MP_OKAY) { + sizes[i] += rawLen; + intTotalLen += sizes[i]; + } + else { + ret = err; + break; + } + } + else { + ret = ASN_INPUT_E; + break; + } + } + + if (ret != 0) { + FreeTmpRsas(tmps, key->heap); + return ret; + } + + /* make headers */ + verSz = SetMyVersion(0, ver, FALSE); + seqSz = SetSequence(verSz + intTotalLen, seq); + + outLen = seqSz + verSz + intTotalLen; + if (outLen > (int)inLen) + return BAD_FUNC_ARG; + + /* write to output */ + XMEMCPY(output, seq, seqSz); + j = seqSz; + XMEMCPY(output + j, ver, verSz); + j += verSz; + + for (i = 0; i < RSA_INTS; i++) { + XMEMCPY(output + j, tmps[i], sizes[i]); + j += sizes[i]; + } + FreeTmpRsas(tmps, key->heap); + + return outLen; +} + +#endif /* CYASSL_KEY_GEN && !NO_RSA */ + + +#if defined(CYASSL_CERT_GEN) && !defined(NO_RSA) + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +/* Initialize and Set Certficate defaults: + version = 3 (0x2) + serial = 0 + sigType = SHA_WITH_RSA + issuer = blank + daysValid = 500 + selfSigned = 1 (true) use subject as issuer + subject = blank +*/ +void InitCert(Cert* cert) +{ + cert->version = 2; /* version 3 is hex 2 */ + cert->sigType = CTC_SHAwRSA; + cert->daysValid = 500; + cert->selfSigned = 1; + cert->isCA = 0; + cert->bodySz = 0; +#ifdef CYASSL_ALT_NAMES + cert->altNamesSz = 0; + cert->beforeDateSz = 0; + cert->afterDateSz = 0; +#endif + cert->keyType = RSA_KEY; + XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE); + + cert->issuer.country[0] = '\0'; + cert->issuer.state[0] = '\0'; + cert->issuer.locality[0] = '\0'; + cert->issuer.sur[0] = '\0'; + cert->issuer.org[0] = '\0'; + cert->issuer.unit[0] = '\0'; + cert->issuer.commonName[0] = '\0'; + cert->issuer.email[0] = '\0'; + + cert->subject.country[0] = '\0'; + cert->subject.state[0] = '\0'; + cert->subject.locality[0] = '\0'; + cert->subject.sur[0] = '\0'; + cert->subject.org[0] = '\0'; + cert->subject.unit[0] = '\0'; + cert->subject.commonName[0] = '\0'; + cert->subject.email[0] = '\0'; + +#ifdef CYASSL_CERT_REQ + cert->challengePw[0] ='\0'; +#endif +} + + +/* DER encoded x509 Certificate */ +typedef struct DerCert { + byte size[MAX_LENGTH_SZ]; /* length encoded */ + byte version[MAX_VERSION_SZ]; /* version encoded */ + byte serial[CTC_SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */ + byte sigAlgo[MAX_ALGO_SZ]; /* signature algo encoded */ + byte issuer[ASN_NAME_MAX]; /* issuer encoded */ + byte subject[ASN_NAME_MAX]; /* subject encoded */ + byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2]; /* before and after dates */ + byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */ + byte ca[MAX_CA_SZ]; /* basic constraint CA true size */ + byte extensions[MAX_EXTENSIONS_SZ]; /* all extensions */ +#ifdef CYASSL_CERT_REQ + byte attrib[MAX_ATTRIB_SZ]; /* Cert req attributes encoded */ +#endif + int sizeSz; /* encoded size length */ + int versionSz; /* encoded version length */ + int serialSz; /* encoded serial length */ + int sigAlgoSz; /* enocded sig alog length */ + int issuerSz; /* encoded issuer length */ + int subjectSz; /* encoded subject length */ + int validitySz; /* encoded validity length */ + int publicKeySz; /* encoded public key length */ + int caSz; /* encoded CA extension length */ + int extensionsSz; /* encoded extensions total length */ + int total; /* total encoded lengths */ +#ifdef CYASSL_CERT_REQ + int attribSz; +#endif +} DerCert; + + +#ifdef CYASSL_CERT_REQ + +/* Write a set header to output */ +static word32 SetUTF8String(word32 len, byte* output) +{ + output[0] = ASN_UTF8STRING; + return SetLength(len, output + 1) + 1; +} + +#endif /* CYASSL_CERT_REQ */ + + +/* Write a serial number to output */ +static int SetSerial(const byte* serial, byte* output) +{ + int length = 0; + + output[length++] = ASN_INTEGER; + length += SetLength(CTC_SERIAL_SIZE, &output[length]); + XMEMCPY(&output[length], serial, CTC_SERIAL_SIZE); + + return length + CTC_SERIAL_SIZE; +} + + +#ifdef HAVE_ECC + +/* Write a public ECC key to output */ +static int SetEccPublicKey(byte* output, ecc_key* key) +{ + byte algo[MAX_ALGO_SZ]; + byte curve[MAX_ALGO_SZ]; + byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ + byte pub[ECC_BUFSIZE]; + int algoSz; + int curveSz; + int lenSz; + int idx; + word32 pubSz = sizeof(pub); + + int ret = ecc_export_x963(key, pub, &pubSz); + if (ret != 0) return ret; + + /* headers */ + curveSz = SetCurve(key, curve); + if (curveSz <= 0) return curveSz; + + algoSz = SetAlgoID(ECDSAk, algo, keyType, curveSz); + lenSz = SetLength(pubSz + 1, len); + len[lenSz++] = 0; /* trailing 0 */ + + /* write */ + idx = SetSequence(pubSz + curveSz + lenSz + 1 + algoSz, output); + /* 1 is for ASN_BIT_STRING */ + /* algo */ + XMEMCPY(output + idx, algo, algoSz); + idx += algoSz; + /* curve */ + XMEMCPY(output + idx, curve, curveSz); + idx += curveSz; + /* bit string */ + output[idx++] = ASN_BIT_STRING; + /* length */ + XMEMCPY(output + idx, len, lenSz); + idx += lenSz; + /* pub */ + XMEMCPY(output + idx, pub, pubSz); + idx += pubSz; + + return idx; +} + + +#endif /* HAVE_ECC */ + + +/* Write a public RSA key to output */ +static int SetRsaPublicKey(byte* output, RsaKey* key) +{ + byte n[MAX_RSA_INT_SZ]; + byte e[MAX_RSA_E_SZ]; + byte algo[MAX_ALGO_SZ]; + byte seq[MAX_SEQ_SZ]; + byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ + int nSz; + int eSz; + int algoSz; + int seqSz; + int lenSz; + int idx; + int rawLen; + int leadingBit; + int err; + + /* n */ + leadingBit = mp_leading_bit(&key->n); + rawLen = mp_unsigned_bin_size(&key->n) + leadingBit; + n[0] = ASN_INTEGER; + nSz = SetLength(rawLen, n + 1) + 1; /* int tag */ + + if ( (nSz + rawLen) < (int)sizeof(n)) { + if (leadingBit) + n[nSz] = 0; + err = mp_to_unsigned_bin(&key->n, n + nSz + leadingBit); + if (err == MP_OKAY) + nSz += rawLen; + else + return MP_TO_E; + } + else + return BUFFER_E; + + /* e */ + leadingBit = mp_leading_bit(&key->e); + rawLen = mp_unsigned_bin_size(&key->e) + leadingBit; + e[0] = ASN_INTEGER; + eSz = SetLength(rawLen, e + 1) + 1; /* int tag */ + + if ( (eSz + rawLen) < (int)sizeof(e)) { + if (leadingBit) + e[eSz] = 0; + err = mp_to_unsigned_bin(&key->e, e + eSz + leadingBit); + if (err == MP_OKAY) + eSz += rawLen; + else + return MP_TO_E; + } + else + return BUFFER_E; + + /* headers */ + algoSz = SetAlgoID(RSAk, algo, keyType, 0); + seqSz = SetSequence(nSz + eSz, seq); + lenSz = SetLength(seqSz + nSz + eSz + 1, len); + len[lenSz++] = 0; /* trailing 0 */ + + /* write */ + idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output); + /* 1 is for ASN_BIT_STRING */ + /* algo */ + XMEMCPY(output + idx, algo, algoSz); + idx += algoSz; + /* bit string */ + output[idx++] = ASN_BIT_STRING; + /* length */ + XMEMCPY(output + idx, len, lenSz); + idx += lenSz; + /* seq */ + XMEMCPY(output + idx, seq, seqSz); + idx += seqSz; + /* n */ + XMEMCPY(output + idx, n, nSz); + idx += nSz; + /* e */ + XMEMCPY(output + idx, e, eSz); + idx += eSz; + + return idx; +} + + +static INLINE byte itob(int number) +{ + return (byte)number + 0x30; +} + + +/* write time to output, format */ +static void SetTime(struct tm* date, byte* output) +{ + int i = 0; + + output[i++] = itob((date->tm_year % 10000) / 1000); + output[i++] = itob((date->tm_year % 1000) / 100); + output[i++] = itob((date->tm_year % 100) / 10); + output[i++] = itob( date->tm_year % 10); + + output[i++] = itob(date->tm_mon / 10); + output[i++] = itob(date->tm_mon % 10); + + output[i++] = itob(date->tm_mday / 10); + output[i++] = itob(date->tm_mday % 10); + + output[i++] = itob(date->tm_hour / 10); + output[i++] = itob(date->tm_hour % 10); + + output[i++] = itob(date->tm_min / 10); + output[i++] = itob(date->tm_min % 10); + + output[i++] = itob(date->tm_sec / 10); + output[i++] = itob(date->tm_sec % 10); + + output[i] = 'Z'; /* Zulu profile */ +} + + +#ifdef CYASSL_ALT_NAMES + +/* Copy Dates from cert, return bytes written */ +static int CopyValidity(byte* output, Cert* cert) +{ + int seqSz; + + CYASSL_ENTER("CopyValidity"); + + /* headers and output */ + seqSz = SetSequence(cert->beforeDateSz + cert->afterDateSz, output); + XMEMCPY(output + seqSz, cert->beforeDate, cert->beforeDateSz); + XMEMCPY(output + seqSz + cert->beforeDateSz, cert->afterDate, + cert->afterDateSz); + return seqSz + cert->beforeDateSz + cert->afterDateSz; +} + +#endif + + +/* Set Date validity from now until now + daysValid */ +static int SetValidity(byte* output, int daysValid) +{ + byte before[MAX_DATE_SIZE]; + byte after[MAX_DATE_SIZE]; + + int beforeSz; + int afterSz; + int seqSz; + + time_t ticks; + struct tm* now; + struct tm local; + + ticks = XTIME(0); + now = XGMTIME(&ticks); + + /* before now */ + local = *now; + before[0] = ASN_GENERALIZED_TIME; + beforeSz = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1; /* gen tag */ + + /* subtract 1 day for more compliance */ + local.tm_mday -= 1; + mktime(&local); + + /* adjust */ + local.tm_year += 1900; + local.tm_mon += 1; + + SetTime(&local, before + beforeSz); + beforeSz += ASN_GEN_TIME_SZ; + + /* after now + daysValid */ + local = *now; + after[0] = ASN_GENERALIZED_TIME; + afterSz = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1; /* gen tag */ + + /* add daysValid */ + local.tm_mday += daysValid; + mktime(&local); + + /* adjust */ + local.tm_year += 1900; + local.tm_mon += 1; + + SetTime(&local, after + afterSz); + afterSz += ASN_GEN_TIME_SZ; + + /* headers and output */ + seqSz = SetSequence(beforeSz + afterSz, output); + XMEMCPY(output + seqSz, before, beforeSz); + XMEMCPY(output + seqSz + beforeSz, after, afterSz); + + return seqSz + beforeSz + afterSz; +} + + +/* ASN Encoded Name field */ +typedef struct EncodedName { + int nameLen; /* actual string value length */ + int totalLen; /* total encoded length */ + int type; /* type of name */ + int used; /* are we actually using this one */ + byte encoded[CTC_NAME_SIZE * 2]; /* encoding */ +} EncodedName; + + +/* Get Which Name from index */ +static const char* GetOneName(CertName* name, int idx) +{ + switch (idx) { + case 0: + return name->country; + + case 1: + return name->state; + + case 2: + return name->locality; + + case 3: + return name->sur; + + case 4: + return name->org; + + case 5: + return name->unit; + + case 6: + return name->commonName; + + case 7: + return name->email; + + default: + return 0; + } +} + + +/* Get ASN Name from index */ +static byte GetNameId(int idx) +{ + switch (idx) { + case 0: + return ASN_COUNTRY_NAME; + + case 1: + return ASN_STATE_NAME; + + case 2: + return ASN_LOCALITY_NAME; + + case 3: + return ASN_SUR_NAME; + + case 4: + return ASN_ORG_NAME; + + case 5: + return ASN_ORGUNIT_NAME; + + case 6: + return ASN_COMMON_NAME; + + case 7: + /* email uses different id type */ + return 0; + + default: + return 0; + } +} + + +/* encode all extensions, return total bytes written */ +static int SetExtensions(byte* output, const byte* ext, int extSz, int header) +{ + byte sequence[MAX_SEQ_SZ]; + byte len[MAX_LENGTH_SZ]; + + int sz = 0; + int seqSz = SetSequence(extSz, sequence); + + if (header) { + int lenSz = SetLength(seqSz + extSz, len); + output[0] = ASN_EXTENSIONS; /* extensions id */ + sz++; + XMEMCPY(&output[sz], len, lenSz); /* length */ + sz += lenSz; + } + XMEMCPY(&output[sz], sequence, seqSz); /* sequence */ + sz += seqSz; + XMEMCPY(&output[sz], ext, extSz); /* extensions */ + sz += extSz; + + return sz; +} + + +/* encode CA basic constraint true, return total bytes written */ +static int SetCa(byte* output) +{ + static const byte ca[] = { 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff }; + + XMEMCPY(output, ca, sizeof(ca)); + + return (int)sizeof(ca); +} + + +/* encode CertName into output, return total bytes written */ +static int SetName(byte* output, CertName* name) +{ + int totalBytes = 0, i, idx; + EncodedName names[NAME_ENTRIES]; + + for (i = 0; i < NAME_ENTRIES; i++) { + const char* nameStr = GetOneName(name, i); + if (nameStr) { + /* bottom up */ + byte firstLen[MAX_LENGTH_SZ]; + byte secondLen[MAX_LENGTH_SZ]; + byte sequence[MAX_SEQ_SZ]; + byte set[MAX_SET_SZ]; + + int email = i == (NAME_ENTRIES - 1) ? 1 : 0; + int strLen = (int)XSTRLEN(nameStr); + int thisLen = strLen; + int firstSz, secondSz, seqSz, setSz; + + if (strLen == 0) { /* no user data for this item */ + names[i].used = 0; + continue; + } + + secondSz = SetLength(strLen, secondLen); + thisLen += secondSz; + if (email) { + thisLen += EMAIL_JOINT_LEN; + thisLen ++; /* id type */ + firstSz = SetLength(EMAIL_JOINT_LEN, firstLen); + } + else { + thisLen++; /* str type */ + thisLen++; /* id type */ + thisLen += JOINT_LEN; + firstSz = SetLength(JOINT_LEN + 1, firstLen); + } + thisLen += firstSz; + thisLen++; /* object id */ + + seqSz = SetSequence(thisLen, sequence); + thisLen += seqSz; + setSz = SetSet(thisLen, set); + thisLen += setSz; + + if (thisLen > (int)sizeof(names[i].encoded)) + return BUFFER_E; + + /* store it */ + idx = 0; + /* set */ + XMEMCPY(names[i].encoded, set, setSz); + idx += setSz; + /* seq */ + XMEMCPY(names[i].encoded + idx, sequence, seqSz); + idx += seqSz; + /* asn object id */ + names[i].encoded[idx++] = ASN_OBJECT_ID; + /* first length */ + XMEMCPY(names[i].encoded + idx, firstLen, firstSz); + idx += firstSz; + if (email) { + const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x09, 0x01, 0x16 }; + /* email joint id */ + XMEMCPY(names[i].encoded + idx, EMAIL_OID, sizeof(EMAIL_OID)); + idx += (int)sizeof(EMAIL_OID); + } + else { + /* joint id */ + byte bType = GetNameId(i); + names[i].encoded[idx++] = 0x55; + names[i].encoded[idx++] = 0x04; + /* id type */ + names[i].encoded[idx++] = bType; + /* str type */ + if (bType == ASN_COUNTRY_NAME) + names[i].encoded[idx++] = 0x13; /* printable */ + else + names[i].encoded[idx++] = 0x0c; /* utf8 */ + } + /* second length */ + XMEMCPY(names[i].encoded + idx, secondLen, secondSz); + idx += secondSz; + /* str value */ + XMEMCPY(names[i].encoded + idx, nameStr, strLen); + idx += strLen; + + totalBytes += idx; + names[i].totalLen = idx; + names[i].used = 1; + } + else + names[i].used = 0; + } + + /* header */ + idx = SetSequence(totalBytes, output); + totalBytes += idx; + if (totalBytes > ASN_NAME_MAX) + return BUFFER_E; + + for (i = 0; i < NAME_ENTRIES; i++) { + if (names[i].used) { + XMEMCPY(output + idx, names[i].encoded, names[i].totalLen); + idx += names[i].totalLen; + } + } + return totalBytes; +} + +/* encode info from cert into DER encoded format */ +static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, + RNG* rng, const byte* ntruKey, word16 ntruSz) +{ + int ret; + + (void)eccKey; + (void)ntruKey; + (void)ntruSz; + + /* init */ + XMEMSET(der, 0, sizeof(DerCert)); + + /* version */ + der->versionSz = SetMyVersion(cert->version, der->version, TRUE); + + /* serial number */ + ret = RNG_GenerateBlock(rng, cert->serial, CTC_SERIAL_SIZE); + if (ret != 0) + return ret; + + cert->serial[0] = 0x01; /* ensure positive */ + der->serialSz = SetSerial(cert->serial, der->serial); + + /* signature algo */ + der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType, 0); + if (der->sigAlgoSz == 0) + return ALGO_ID_E; + + /* public key */ + if (cert->keyType == RSA_KEY) { + if (rsaKey == NULL) + return PUBLIC_KEY_E; + der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey); + if (der->publicKeySz <= 0) + return PUBLIC_KEY_E; + } + +#ifdef HAVE_ECC + if (cert->keyType == ECC_KEY) { + if (eccKey == NULL) + return PUBLIC_KEY_E; + der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey); + if (der->publicKeySz <= 0) + return PUBLIC_KEY_E; + } +#endif /* HAVE_ECC */ + +#ifdef HAVE_NTRU + if (cert->keyType == NTRU_KEY) { + word32 rc; + word16 encodedSz; + + rc = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz, + ntruKey, &encodedSz, NULL); + if (rc != NTRU_OK) + return PUBLIC_KEY_E; + if (encodedSz > MAX_PUBLIC_KEY_SZ) + return PUBLIC_KEY_E; + + rc = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz, + ntruKey, &encodedSz, der->publicKey); + if (rc != NTRU_OK) + return PUBLIC_KEY_E; + + der->publicKeySz = encodedSz; + } +#endif /* HAVE_NTRU */ + + der->validitySz = 0; +#ifdef CYASSL_ALT_NAMES + /* date validity copy ? */ + if (cert->beforeDateSz && cert->afterDateSz) { + der->validitySz = CopyValidity(der->validity, cert); + if (der->validitySz == 0) + return DATE_E; + } +#endif + + /* date validity */ + if (der->validitySz == 0) { + der->validitySz = SetValidity(der->validity, cert->daysValid); + if (der->validitySz == 0) + return DATE_E; + } + + /* subject name */ + der->subjectSz = SetName(der->subject, &cert->subject); + if (der->subjectSz == 0) + return SUBJECT_E; + + /* issuer name */ + der->issuerSz = SetName(der->issuer, cert->selfSigned ? + &cert->subject : &cert->issuer); + if (der->issuerSz == 0) + return ISSUER_E; + + /* CA */ + if (cert->isCA) { + der->caSz = SetCa(der->ca); + if (der->caSz == 0) + return CA_TRUE_E; + } + else + der->caSz = 0; + + /* extensions, just CA now */ + if (cert->isCA) { + der->extensionsSz = SetExtensions(der->extensions, + der->ca, der->caSz, TRUE); + if (der->extensionsSz == 0) + return EXTENSIONS_E; + } + else + der->extensionsSz = 0; + +#ifdef CYASSL_ALT_NAMES + if (der->extensionsSz == 0 && cert->altNamesSz) { + der->extensionsSz = SetExtensions(der->extensions, cert->altNames, + cert->altNamesSz, TRUE); + if (der->extensionsSz == 0) + return EXTENSIONS_E; + } +#endif + + der->total = der->versionSz + der->serialSz + der->sigAlgoSz + + der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz + + der->extensionsSz; + + return 0; +} + + +/* write DER encoded cert to buffer, size already checked */ +static int WriteCertBody(DerCert* der, byte* buffer) +{ + int idx; + + /* signed part header */ + idx = SetSequence(der->total, buffer); + /* version */ + XMEMCPY(buffer + idx, der->version, der->versionSz); + idx += der->versionSz; + /* serial */ + XMEMCPY(buffer + idx, der->serial, der->serialSz); + idx += der->serialSz; + /* sig algo */ + XMEMCPY(buffer + idx, der->sigAlgo, der->sigAlgoSz); + idx += der->sigAlgoSz; + /* issuer */ + XMEMCPY(buffer + idx, der->issuer, der->issuerSz); + idx += der->issuerSz; + /* validity */ + XMEMCPY(buffer + idx, der->validity, der->validitySz); + idx += der->validitySz; + /* subject */ + XMEMCPY(buffer + idx, der->subject, der->subjectSz); + idx += der->subjectSz; + /* public key */ + XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz); + idx += der->publicKeySz; + if (der->extensionsSz) { + /* extensions */ + XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz, + sizeof(der->extensions))); + idx += der->extensionsSz; + } + + return idx; +} + + +/* Make RSA signature from buffer (sz), write to sig (sigSz) */ +static int MakeSignature(const byte* buffer, int sz, byte* sig, int sigSz, + RsaKey* rsaKey, ecc_key* eccKey, RNG* rng, + int sigAlgoType) +{ + byte digest[SHA256_DIGEST_SIZE]; /* max size */ + byte encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ]; + int encSigSz, digestSz, typeH, ret = 0; + + (void)eccKey; + + if (sigAlgoType == CTC_MD5wRSA) { + Md5 md5; + + InitMd5(&md5); + Md5Update(&md5, buffer, sz); + Md5Final(&md5, digest); + + digestSz = MD5_DIGEST_SIZE; + typeH = MD5h; + } + else if (sigAlgoType == CTC_SHAwRSA || sigAlgoType == CTC_SHAwECDSA) { + Sha sha; + + ret = InitSha(&sha); + if (ret != 0) + return ret; + + ShaUpdate(&sha, buffer, sz); + ShaFinal(&sha, digest); + + digestSz = SHA_DIGEST_SIZE; + typeH = SHAh; + } + else if (sigAlgoType == CTC_SHA256wRSA || sigAlgoType == CTC_SHA256wECDSA) { + Sha256 sha256; + + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + + ret = Sha256Update(&sha256, buffer, sz); + if (ret != 0) + return ret; + + ret = Sha256Final(&sha256, digest); + if (ret != 0) + return ret; + + digestSz = SHA256_DIGEST_SIZE; + typeH = SHA256h; + } + else + return ALGO_ID_E; + + if (rsaKey) { + /* signature */ + encSigSz = EncodeSignature(encSig, digest, digestSz, typeH); + return RsaSSL_Sign(encSig, encSigSz, sig, sigSz, rsaKey, rng); + } +#ifdef HAVE_ECC + else if (eccKey) { + word32 outSz = sigSz; + ret = ecc_sign_hash(digest, digestSz, sig, &outSz, rng, eccKey); + + if (ret != 0) + return ret; + return outSz; + } +#endif /* HAVE_ECC */ + + return ALGO_ID_E; +} + + +/* add signature to end of buffer, size of buffer assumed checked, return + new length */ +static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz, + int sigAlgoType) +{ + byte seq[MAX_SEQ_SZ]; + int idx = bodySz, seqSz; + + /* algo */ + idx += SetAlgoID(sigAlgoType, buffer + idx, sigType, 0); + /* bit string */ + buffer[idx++] = ASN_BIT_STRING; + /* length */ + idx += SetLength(sigSz + 1, buffer + idx); + buffer[idx++] = 0; /* trailing 0 */ + /* signature */ + XMEMCPY(buffer + idx, sig, sigSz); + idx += sigSz; + + /* make room for overall header */ + seqSz = SetSequence(idx, seq); + XMEMMOVE(buffer + seqSz, buffer, idx); + XMEMCPY(buffer, seq, seqSz); + + return idx + seqSz; +} + + +/* Make an x509 Certificate v3 any key type from cert input, write to buffer */ +static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, + RsaKey* rsaKey, ecc_key* eccKey, RNG* rng, + const byte* ntruKey, word16 ntruSz) +{ + DerCert der; + int ret; + + if (eccKey) + cert->keyType = ECC_KEY; + else + cert->keyType = rsaKey ? RSA_KEY : NTRU_KEY; + ret = EncodeCert(cert, &der, rsaKey, eccKey, rng, ntruKey, ntruSz); + if (ret != 0) + return ret; + + if (der.total + MAX_SEQ_SZ * 2 > (int)derSz) + return BUFFER_E; + + return cert->bodySz = WriteCertBody(&der, derBuffer); +} + + +/* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */ +int MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, + ecc_key* eccKey, RNG* rng) +{ + return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, 0); +} + + +#ifdef HAVE_NTRU + +int MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz, + const byte* ntruKey, word16 keySz, RNG* rng) +{ + return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz); +} + +#endif /* HAVE_NTRU */ + + +#ifdef CYASSL_CERT_REQ + +static int SetReqAttrib(byte* output, char* pw, int extSz) +{ + static const byte cpOid[] = + { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x07 }; + static const byte erOid[] = + { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x0e }; + + int sz = 0; /* overall size */ + int cpSz = 0; /* Challenge Password section size */ + int cpSeqSz = 0; + int cpSetSz = 0; + int cpStrSz = 0; + int pwSz = 0; + int erSz = 0; /* Extension Request section size */ + int erSeqSz = 0; + int erSetSz = 0; + byte cpSeq[MAX_SEQ_SZ]; + byte cpSet[MAX_SET_SZ]; + byte cpStr[MAX_PRSTR_SZ]; + byte erSeq[MAX_SEQ_SZ]; + byte erSet[MAX_SET_SZ]; + + output[0] = 0xa0; + sz++; + + if (pw && pw[0]) { + pwSz = (int)XSTRLEN(pw); + cpStrSz = SetUTF8String(pwSz, cpStr); + cpSetSz = SetSet(cpStrSz + pwSz, cpSet); + cpSeqSz = SetSequence(sizeof(cpOid) + cpSetSz + cpStrSz + pwSz, cpSeq); + cpSz = cpSeqSz + sizeof(cpOid) + cpSetSz + cpStrSz + pwSz; + } + + if (extSz) { + erSetSz = SetSet(extSz, erSet); + erSeqSz = SetSequence(erSetSz + sizeof(erOid) + extSz, erSeq); + erSz = extSz + erSetSz + erSeqSz + sizeof(erOid); + } + + /* Put the pieces together. */ + sz += SetLength(cpSz + erSz, &output[sz]); + + if (cpSz) { + XMEMCPY(&output[sz], cpSeq, cpSeqSz); + sz += cpSeqSz; + XMEMCPY(&output[sz], cpOid, sizeof(cpOid)); + sz += sizeof(cpOid); + XMEMCPY(&output[sz], cpSet, cpSetSz); + sz += cpSetSz; + XMEMCPY(&output[sz], cpStr, cpStrSz); + sz += cpStrSz; + XMEMCPY(&output[sz], pw, pwSz); + sz += pwSz; + } + + if (erSz) { + XMEMCPY(&output[sz], erSeq, erSeqSz); + sz += erSeqSz; + XMEMCPY(&output[sz], erOid, sizeof(erOid)); + sz += sizeof(erOid); + XMEMCPY(&output[sz], erSet, erSetSz); + sz += erSetSz; + /* The actual extension data will be tacked onto the output later. */ + } + + return sz; +} + + +/* encode info from cert into DER encoded format */ +static int EncodeCertReq(Cert* cert, DerCert* der, + RsaKey* rsaKey, ecc_key* eccKey) +{ + (void)eccKey; + + /* init */ + XMEMSET(der, 0, sizeof(DerCert)); + + /* version */ + der->versionSz = SetMyVersion(cert->version, der->version, FALSE); + + /* subject name */ + der->subjectSz = SetName(der->subject, &cert->subject); + if (der->subjectSz == 0) + return SUBJECT_E; + + /* public key */ + if (cert->keyType == RSA_KEY) { + if (rsaKey == NULL) + return PUBLIC_KEY_E; + der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey); + if (der->publicKeySz <= 0) + return PUBLIC_KEY_E; + } + +#ifdef HAVE_ECC + if (cert->keyType == ECC_KEY) { + if (eccKey == NULL) + return PUBLIC_KEY_E; + der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey); + if (der->publicKeySz <= 0) + return PUBLIC_KEY_E; + } +#endif /* HAVE_ECC */ + + /* CA */ + if (cert->isCA) { + der->caSz = SetCa(der->ca); + if (der->caSz == 0) + return CA_TRUE_E; + } + else + der->caSz = 0; + + /* extensions, just CA now */ + if (cert->isCA) { + der->extensionsSz = SetExtensions(der->extensions, + der->ca, der->caSz, FALSE); + if (der->extensionsSz == 0) + return EXTENSIONS_E; + } + else + der->extensionsSz = 0; + + der->attribSz = SetReqAttrib(der->attrib, + cert->challengePw, der->extensionsSz); + if (der->attribSz == 0) + return REQ_ATTRIBUTE_E; + + der->total = der->versionSz + der->subjectSz + der->publicKeySz + + der->extensionsSz + der->attribSz; + + return 0; +} + + +/* write DER encoded cert req to buffer, size already checked */ +static int WriteCertReqBody(DerCert* der, byte* buffer) +{ + int idx; + + /* signed part header */ + idx = SetSequence(der->total, buffer); + /* version */ + XMEMCPY(buffer + idx, der->version, der->versionSz); + idx += der->versionSz; + /* subject */ + XMEMCPY(buffer + idx, der->subject, der->subjectSz); + idx += der->subjectSz; + /* public key */ + XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz); + idx += der->publicKeySz; + /* attributes */ + XMEMCPY(buffer + idx, der->attrib, der->attribSz); + idx += der->attribSz; + /* extensions */ + if (der->extensionsSz) { + XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz, + sizeof(der->extensions))); + idx += der->extensionsSz; + } + + return idx; +} + + +int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, + RsaKey* rsaKey, ecc_key* eccKey) +{ + DerCert der; + int ret; + + cert->keyType = (eccKey != NULL) ? ECC_KEY : RSA_KEY; + ret = EncodeCertReq(cert, &der, rsaKey, eccKey); + if (ret != 0) + return ret; + + if (der.total + MAX_SEQ_SZ * 2 > (int)derSz) + return BUFFER_E; + + return cert->bodySz = WriteCertReqBody(&der, derBuffer); +} + +#endif /* CYASSL_CERT_REQ */ + + +int SignCert(int requestSz, int sType, byte* buffer, word32 buffSz, + RsaKey* rsaKey, ecc_key* eccKey, RNG* rng) +{ + byte sig[MAX_ENCODED_SIG_SZ]; + int sigSz; + + if (requestSz < 0) + return requestSz; + + sigSz = MakeSignature(buffer, requestSz, sig, sizeof(sig), rsaKey, eccKey, + rng, sType); + if (sigSz < 0) + return sigSz; + + if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz) + return BUFFER_E; + + return AddSignature(buffer, requestSz, sig, sigSz, sType); +} + + +int MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng) +{ + int ret = MakeCert(cert, buffer, buffSz, key, NULL, rng); + + if (ret < 0) + return ret; + + return SignCert(cert->bodySz, cert->sigType, buffer, buffSz, key, NULL,rng); +} + + +#ifdef CYASSL_ALT_NAMES + +/* Set Alt Names from der cert, return 0 on success */ +static int SetAltNamesFromCert(Cert* cert, const byte* der, int derSz) +{ + DecodedCert decoded; + int ret; + + if (derSz < 0) + return derSz; + + InitDecodedCert(&decoded, (byte*)der, derSz, 0); + ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) { + FreeDecodedCert(&decoded); + return ret; + } + + if (decoded.extensions) { + byte b; + int length; + word32 maxExtensionsIdx; + + decoded.srcIdx = decoded.extensionsIdx; + b = decoded.source[decoded.srcIdx++]; + if (b != ASN_EXTENSIONS) { + FreeDecodedCert(&decoded); + return ASN_PARSE_E; + } + + if (GetLength(decoded.source, &decoded.srcIdx, &length, + decoded.maxIdx) < 0) { + FreeDecodedCert(&decoded); + return ASN_PARSE_E; + } + + if (GetSequence(decoded.source, &decoded.srcIdx, &length, + decoded.maxIdx) < 0) { + FreeDecodedCert(&decoded); + return ASN_PARSE_E; + } + + maxExtensionsIdx = decoded.srcIdx + length; + + while (decoded.srcIdx < maxExtensionsIdx) { + word32 oid; + word32 startIdx = decoded.srcIdx; + word32 tmpIdx; + + if (GetSequence(decoded.source, &decoded.srcIdx, &length, + decoded.maxIdx) < 0) { + FreeDecodedCert(&decoded); + return ASN_PARSE_E; + } + + tmpIdx = decoded.srcIdx; + decoded.srcIdx = startIdx; + + if (GetAlgoId(decoded.source, &decoded.srcIdx, &oid, + decoded.maxIdx) < 0) { + FreeDecodedCert(&decoded); + return ASN_PARSE_E; + } + + if (oid == ALT_NAMES_OID) { + cert->altNamesSz = length + (tmpIdx - startIdx); + + if (cert->altNamesSz < (int)sizeof(cert->altNames)) + XMEMCPY(cert->altNames, &decoded.source[startIdx], + cert->altNamesSz); + else { + cert->altNamesSz = 0; + CYASSL_MSG("AltNames extensions too big"); + FreeDecodedCert(&decoded); + return ALT_NAME_E; + } + } + decoded.srcIdx = tmpIdx + length; + } + } + FreeDecodedCert(&decoded); + + return 0; +} + + +/* Set Dates from der cert, return 0 on success */ +static int SetDatesFromCert(Cert* cert, const byte* der, int derSz) +{ + DecodedCert decoded; + int ret; + + CYASSL_ENTER("SetDatesFromCert"); + if (derSz < 0) + return derSz; + + InitDecodedCert(&decoded, (byte*)der, derSz, 0); + ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) { + CYASSL_MSG("ParseCertRelative error"); + FreeDecodedCert(&decoded); + return ret; + } + + if (decoded.beforeDate == NULL || decoded.afterDate == NULL) { + CYASSL_MSG("Couldn't extract dates"); + FreeDecodedCert(&decoded); + return -1; + } + + if (decoded.beforeDateLen > MAX_DATE_SIZE || decoded.afterDateLen > + MAX_DATE_SIZE) { + CYASSL_MSG("Bad date size"); + FreeDecodedCert(&decoded); + return -1; + } + + XMEMCPY(cert->beforeDate, decoded.beforeDate, decoded.beforeDateLen); + XMEMCPY(cert->afterDate, decoded.afterDate, decoded.afterDateLen); + + cert->beforeDateSz = decoded.beforeDateLen; + cert->afterDateSz = decoded.afterDateLen; + + return 0; +} + + +#endif /* CYASSL_ALT_NAMES && !NO_RSA */ + + +/* Set cn name from der buffer, return 0 on success */ +static int SetNameFromCert(CertName* cn, const byte* der, int derSz) +{ + DecodedCert decoded; + int ret; + int sz; + + if (derSz < 0) + return derSz; + + InitDecodedCert(&decoded, (byte*)der, derSz, 0); + ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) + return ret; + + if (decoded.subjectCN) { + sz = (decoded.subjectCNLen < CTC_NAME_SIZE) ? decoded.subjectCNLen : + CTC_NAME_SIZE - 1; + strncpy(cn->commonName, decoded.subjectCN, CTC_NAME_SIZE); + cn->commonName[sz] = 0; + } + if (decoded.subjectC) { + sz = (decoded.subjectCLen < CTC_NAME_SIZE) ? decoded.subjectCLen : + CTC_NAME_SIZE - 1; + strncpy(cn->country, decoded.subjectC, CTC_NAME_SIZE); + cn->country[sz] = 0; + } + if (decoded.subjectST) { + sz = (decoded.subjectSTLen < CTC_NAME_SIZE) ? decoded.subjectSTLen : + CTC_NAME_SIZE - 1; + strncpy(cn->state, decoded.subjectST, CTC_NAME_SIZE); + cn->state[sz] = 0; + } + if (decoded.subjectL) { + sz = (decoded.subjectLLen < CTC_NAME_SIZE) ? decoded.subjectLLen : + CTC_NAME_SIZE - 1; + strncpy(cn->locality, decoded.subjectL, CTC_NAME_SIZE); + cn->locality[sz] = 0; + } + if (decoded.subjectO) { + sz = (decoded.subjectOLen < CTC_NAME_SIZE) ? decoded.subjectOLen : + CTC_NAME_SIZE - 1; + strncpy(cn->org, decoded.subjectO, CTC_NAME_SIZE); + cn->org[sz] = 0; + } + if (decoded.subjectOU) { + sz = (decoded.subjectOULen < CTC_NAME_SIZE) ? decoded.subjectOULen : + CTC_NAME_SIZE - 1; + strncpy(cn->unit, decoded.subjectOU, CTC_NAME_SIZE); + cn->unit[sz] = 0; + } + if (decoded.subjectSN) { + sz = (decoded.subjectSNLen < CTC_NAME_SIZE) ? decoded.subjectSNLen : + CTC_NAME_SIZE - 1; + strncpy(cn->sur, decoded.subjectSN, CTC_NAME_SIZE); + cn->sur[sz] = 0; + } + if (decoded.subjectEmail) { + sz = (decoded.subjectEmailLen < CTC_NAME_SIZE) ? + decoded.subjectEmailLen : CTC_NAME_SIZE - 1; + strncpy(cn->email, decoded.subjectEmail, CTC_NAME_SIZE); + cn->email[sz] = 0; + } + + FreeDecodedCert(&decoded); + + return 0; +} + + +#ifndef NO_FILESYSTEM + +/* forward from CyaSSL */ +int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz); + +/* Set cert issuer from issuerFile in PEM */ +int SetIssuer(Cert* cert, const char* issuerFile) +{ + int ret; + int derSz; + byte* der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); + + if (der == NULL) { + CYASSL_MSG("SetIssuer OOF Problem"); + return MEMORY_E; + } + derSz = CyaSSL_PemCertToDer(issuerFile, der, EIGHTK_BUF); + cert->selfSigned = 0; + ret = SetNameFromCert(&cert->issuer, der, derSz); + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + + return ret; +} + + +/* Set cert subject from subjectFile in PEM */ +int SetSubject(Cert* cert, const char* subjectFile) +{ + int ret; + int derSz; + byte* der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); + + if (der == NULL) { + CYASSL_MSG("SetSubject OOF Problem"); + return MEMORY_E; + } + derSz = CyaSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF); + ret = SetNameFromCert(&cert->subject, der, derSz); + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + + return ret; +} + + +#ifdef CYASSL_ALT_NAMES + +/* Set atl names from file in PEM */ +int SetAltNames(Cert* cert, const char* file) +{ + int ret; + int derSz; + byte* der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); + + if (der == NULL) { + CYASSL_MSG("SetAltNames OOF Problem"); + return MEMORY_E; + } + derSz = CyaSSL_PemCertToDer(file, der, EIGHTK_BUF); + ret = SetAltNamesFromCert(cert, der, derSz); + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + + return ret; +} + +#endif /* CYASSL_ALT_NAMES */ + +#endif /* NO_FILESYSTEM */ + +/* Set cert issuer from DER buffer */ +int SetIssuerBuffer(Cert* cert, const byte* der, int derSz) +{ + cert->selfSigned = 0; + return SetNameFromCert(&cert->issuer, der, derSz); +} + + +/* Set cert subject from DER buffer */ +int SetSubjectBuffer(Cert* cert, const byte* der, int derSz) +{ + return SetNameFromCert(&cert->subject, der, derSz); +} + + +#ifdef CYASSL_ALT_NAMES + +/* Set cert alt names from DER buffer */ +int SetAltNamesBuffer(Cert* cert, const byte* der, int derSz) +{ + return SetAltNamesFromCert(cert, der, derSz); +} + +/* Set cert dates from DER buffer */ +int SetDatesBuffer(Cert* cert, const byte* der, int derSz) +{ + return SetDatesFromCert(cert, der, derSz); +} + +#endif /* CYASSL_ALT_NAMES */ + +#endif /* CYASSL_CERT_GEN */ + + +#ifdef HAVE_ECC + +/* Der Encode r & s ints into out, outLen is (in/out) size */ +int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r, mp_int* s) +{ + word32 idx = 0; + word32 rSz; /* encoding size */ + word32 sSz; + word32 headerSz = 4; /* 2*ASN_TAG + 2*LEN(ENUM) */ + + /* If the leading bit on the INTEGER is a 1, add a leading zero */ + int rLeadingZero = mp_leading_bit(r); + int sLeadingZero = mp_leading_bit(s); + int rLen = mp_unsigned_bin_size(r); /* big int size */ + int sLen = mp_unsigned_bin_size(s); + int err; + + if (*outLen < (rLen + rLeadingZero + sLen + sLeadingZero + + headerSz + 2)) /* SEQ_TAG + LEN(ENUM) */ + return BAD_FUNC_ARG; + + idx = SetSequence(rLen+rLeadingZero+sLen+sLeadingZero+headerSz, out); + + /* store r */ + out[idx++] = ASN_INTEGER; + rSz = SetLength(rLen + rLeadingZero, &out[idx]); + idx += rSz; + if (rLeadingZero) + out[idx++] = 0; + err = mp_to_unsigned_bin(r, &out[idx]); + if (err != MP_OKAY) return err; + idx += rLen; + + /* store s */ + out[idx++] = ASN_INTEGER; + sSz = SetLength(sLen + sLeadingZero, &out[idx]); + idx += sSz; + if (sLeadingZero) + out[idx++] = 0; + err = mp_to_unsigned_bin(s, &out[idx]); + if (err != MP_OKAY) return err; + idx += sLen; + + *outLen = idx; + + return 0; +} + + +/* Der Decode ECC-DSA Signautre, r & s stored as big ints */ +int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s) +{ + word32 idx = 0; + int len = 0; + + if (GetSequence(sig, &idx, &len, sigLen) < 0) + return ASN_ECC_KEY_E; + + if ((word32)len > (sigLen - idx)) + return ASN_ECC_KEY_E; + + if (GetInt(r, sig, &idx, sigLen) < 0) + return ASN_ECC_KEY_E; + + if (GetInt(s, sig, &idx, sigLen) < 0) + return ASN_ECC_KEY_E; + + return 0; +} + + +int EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key, + word32 inSz) +{ + word32 oid = 0; + int version, length; + int privSz, pubSz; + byte b; + byte priv[ECC_MAXSIZE]; + byte pub[ECC_MAXSIZE * 2 + 1]; /* public key has two parts plus header */ + + if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) + return BAD_FUNC_ARG; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + b = input[*inOutIdx]; + *inOutIdx += 1; + + /* priv type */ + if (b != 4 && b != 6 && b != 7) + return ASN_PARSE_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + /* priv key */ + privSz = length; + XMEMCPY(priv, &input[*inOutIdx], privSz); + *inOutIdx += length; + + /* prefix 0, may have */ + b = input[*inOutIdx]; + if (b == ECC_PREFIX_0) { + *inOutIdx += 1; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + /* object id */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + while(length--) { + oid += input[*inOutIdx]; + *inOutIdx += 1; + } + if (CheckCurve(oid) < 0) + return ECC_CURVE_OID_E; + } + + /* prefix 1 */ + b = input[*inOutIdx]; + *inOutIdx += 1; + if (b != ECC_PREFIX_1) + return ASN_ECC_KEY_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + /* key header */ + b = input[*inOutIdx]; + *inOutIdx += 1; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + b = input[*inOutIdx]; + *inOutIdx += 1; + if (b != 0x00) + return ASN_EXPECT_0_E; + + pubSz = length - 1; /* null prefix */ + XMEMCPY(pub, &input[*inOutIdx], pubSz); + + *inOutIdx += length; + + return ecc_import_private_key(priv, privSz, pub, pubSz, key); +} + +#endif /* HAVE_ECC */ + + +#if defined(HAVE_OCSP) || defined(HAVE_CRL) + +/* Get raw Date only, no processing, 0 on success */ +static int GetBasicDate(const byte* source, word32* idx, byte* date, + byte* format, int maxIdx) +{ + int length; + + CYASSL_ENTER("GetBasicDate"); + + *format = source[*idx]; + *idx += 1; + if (*format != ASN_UTC_TIME && *format != ASN_GENERALIZED_TIME) + return ASN_TIME_E; + + if (GetLength(source, idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE) + return ASN_DATE_SZ_E; + + XMEMCPY(date, &source[*idx], length); + *idx += length; + + return 0; +} + +#endif + + +#ifdef HAVE_OCSP + +static int GetEnumerated(const byte* input, word32* inOutIdx, int *value) +{ + word32 idx = *inOutIdx; + word32 len; + + CYASSL_ENTER("GetEnumerated"); + + *value = 0; + + if (input[idx++] != ASN_ENUMERATED) + return ASN_PARSE_E; + + len = input[idx++]; + if (len > 4) + return ASN_PARSE_E; + + while (len--) { + *value = *value << 8 | input[idx++]; + } + + *inOutIdx = idx; + + return *value; +} + + +static int DecodeSingleResponse(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + word32 idx = *ioIndex, prevIndex, oid; + int length, wrapperSz; + CertStatus* cs = resp->status; + + CYASSL_ENTER("DecodeSingleResponse"); + + /* Outer wrapper of the SEQUENCE OF Single Responses. */ + if (GetSequence(source, &idx, &wrapperSz, size) < 0) + return ASN_PARSE_E; + + prevIndex = idx; + + /* When making a request, we only request one status on one certificate + * at a time. There should only be one SingleResponse */ + + /* Wrapper around the Single Response */ + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + /* Wrapper around the CertID */ + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + /* Skip the hash algorithm */ + if (GetAlgoId(source, &idx, &oid, size) < 0) + return ASN_PARSE_E; + /* Save reference to the hash of CN */ + if (source[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + resp->issuerHash = source + idx; + idx += length; + /* Save reference to the hash of the issuer public key */ + if (source[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + resp->issuerKeyHash = source + idx; + idx += length; + + /* Read the serial number, it is handled as a string, not as a + * proper number. Just XMEMCPY the data over, rather than load it + * as an mp_int. */ + if (source[idx++] != ASN_INTEGER) + return ASN_PARSE_E; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + if (length <= EXTERNAL_SERIAL_SIZE) + { + if (source[idx] == 0) + { + idx++; + length--; + } + XMEMCPY(cs->serial, source + idx, length); + cs->serialSz = length; + } + else + { + return ASN_GETINT_E; + } + idx += length; + + /* CertStatus */ + switch (source[idx++]) + { + case (ASN_CONTEXT_SPECIFIC | CERT_GOOD): + cs->status = CERT_GOOD; + idx++; + break; + case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_REVOKED): + cs->status = CERT_REVOKED; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + idx += length; + break; + case (ASN_CONTEXT_SPECIFIC | CERT_UNKNOWN): + cs->status = CERT_UNKNOWN; + idx++; + break; + default: + return ASN_PARSE_E; + } + + if (GetBasicDate(source, &idx, cs->thisDate, + &cs->thisDateFormat, size) < 0) + return ASN_PARSE_E; + if (!XVALIDATE_DATE(cs->thisDate, cs->thisDateFormat, BEFORE)) + return ASN_BEFORE_DATE_E; + + /* The following items are optional. Only check for them if there is more + * unprocessed data in the singleResponse wrapper. */ + + if (((int)(idx - prevIndex) < wrapperSz) && + (source[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))) + { + idx++; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + if (GetBasicDate(source, &idx, cs->nextDate, + &cs->nextDateFormat, size) < 0) + return ASN_PARSE_E; + } + if (((int)(idx - prevIndex) < wrapperSz) && + (source[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))) + { + idx++; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + idx += length; + } + + *ioIndex = idx; + + return 0; +} + +static int DecodeOcspRespExtensions(byte* source, + word32* ioIndex, OcspResponse* resp, word32 sz) +{ + word32 idx = *ioIndex; + int length; + int ext_bound; /* boundary index for the sequence of extensions */ + word32 oid; + + CYASSL_ENTER("DecodeOcspRespExtensions"); + + if (source[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) + return ASN_PARSE_E; + + if (GetLength(source, &idx, &length, sz) < 0) return ASN_PARSE_E; + + if (GetSequence(source, &idx, &length, sz) < 0) return ASN_PARSE_E; + + ext_bound = idx + length; + + while (idx < (word32)ext_bound) { + if (GetSequence(source, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + oid = 0; + if (GetObjectId(source, &idx, &oid, sz) < 0) { + CYASSL_MSG("\tfail: OBJECT ID"); + return ASN_PARSE_E; + } + + /* check for critical flag */ + if (source[idx] == ASN_BOOLEAN) { + CYASSL_MSG("\tfound optional critical flag, moving past"); + idx += (ASN_BOOL_SIZE + 1); + } + + /* process the extension based on the OID */ + if (source[idx++] != ASN_OCTET_STRING) { + CYASSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(source, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: extension data length"); + return ASN_PARSE_E; + } + + if (oid == OCSP_NONCE_OID) { + resp->nonce = source + idx; + resp->nonceSz = length; + } + + idx += length; + } + + *ioIndex = idx; + return 0; +} + + +static int DecodeResponseData(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + word32 idx = *ioIndex, prev_idx; + int length; + int version; + word32 responderId = 0; + + CYASSL_ENTER("DecodeResponseData"); + + resp->response = source + idx; + prev_idx = idx; + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + resp->responseSz = length + idx - prev_idx; + + /* Get version. It is an EXPLICIT[0] DEFAULT(0) value. If this + * item isn't an EXPLICIT[0], then set version to zero and move + * onto the next item. + */ + if (source[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) + { + idx += 2; /* Eat the value and length */ + if (GetMyVersion(source, &idx, &version) < 0) + return ASN_PARSE_E; + } else + version = 0; + + responderId = source[idx++]; + if ((responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) || + (responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2))) + { + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + idx += length; + } + else + return ASN_PARSE_E; + + /* save pointer to the producedAt time */ + if (GetBasicDate(source, &idx, resp->producedDate, + &resp->producedDateFormat, size) < 0) + return ASN_PARSE_E; + + if (DecodeSingleResponse(source, &idx, resp, size) < 0) + return ASN_PARSE_E; + + if (DecodeOcspRespExtensions(source, &idx, resp, size) < 0) + return ASN_PARSE_E; + + *ioIndex = idx; + return 0; +} + + +static int DecodeCerts(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + word32 idx = *ioIndex; + + CYASSL_ENTER("DecodeCerts"); + + if (source[idx++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) + { + int length; + + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + resp->cert = source + idx; + resp->certSz = length; + + idx += length; + } + *ioIndex = idx; + return 0; +} + +static int DecodeBasicOcspResponse(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + int length; + word32 idx = *ioIndex; + word32 end_index; + + CYASSL_ENTER("DecodeBasicOcspResponse"); + + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + if (idx + length > size) + return ASN_INPUT_E; + end_index = idx + length; + + if (DecodeResponseData(source, &idx, resp, size) < 0) + return ASN_PARSE_E; + + /* Get the signature algorithm */ + if (GetAlgoId(source, &idx, &resp->sigOID, size) < 0) + return ASN_PARSE_E; + + /* Obtain pointer to the start of the signature, and save the size */ + if (source[idx++] == ASN_BIT_STRING) + { + int sigLength = 0; + if (GetLength(source, &idx, &sigLength, size) < 0) + return ASN_PARSE_E; + resp->sigSz = sigLength; + resp->sig = source + idx; + idx += sigLength; + } + + /* + * Check the length of the BasicOcspResponse against the current index to + * see if there are certificates, they are optional. + */ + if (idx < end_index) + { + DecodedCert cert; + int ret; + + if (DecodeCerts(source, &idx, resp, size) < 0) + return ASN_PARSE_E; + + InitDecodedCert(&cert, resp->cert, resp->certSz, 0); + ret = ParseCertRelative(&cert, CA_TYPE, NO_VERIFY, 0); + if (ret < 0) + return ret; + + ret = ConfirmSignature(resp->response, resp->responseSz, + cert.publicKey, cert.pubKeySize, cert.keyOID, + resp->sig, resp->sigSz, resp->sigOID, NULL); + FreeDecodedCert(&cert); + + if (ret == 0) + { + CYASSL_MSG("\tOCSP Confirm signature failed"); + return ASN_OCSP_CONFIRM_E; + } + } + + *ioIndex = idx; + return 0; +} + + +void InitOcspResponse(OcspResponse* resp, CertStatus* status, + byte* source, word32 inSz) +{ + CYASSL_ENTER("InitOcspResponse"); + + resp->responseStatus = -1; + resp->response = NULL; + resp->responseSz = 0; + resp->producedDateFormat = 0; + resp->issuerHash = NULL; + resp->issuerKeyHash = NULL; + resp->sig = NULL; + resp->sigSz = 0; + resp->sigOID = 0; + resp->status = status; + resp->nonce = NULL; + resp->nonceSz = 0; + resp->source = source; + resp->maxIdx = inSz; +} + + +int OcspResponseDecode(OcspResponse* resp) +{ + int length = 0; + word32 idx = 0; + byte* source = resp->source; + word32 size = resp->maxIdx; + word32 oid; + + CYASSL_ENTER("OcspResponseDecode"); + + /* peel the outer SEQUENCE wrapper */ + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + /* First get the responseStatus, an ENUMERATED */ + if (GetEnumerated(source, &idx, &resp->responseStatus) < 0) + return ASN_PARSE_E; + + if (resp->responseStatus != OCSP_SUCCESSFUL) + return 0; + + /* Next is an EXPLICIT record called ResponseBytes, OPTIONAL */ + if (idx >= size) + return ASN_INPUT_E; + if (source[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) + return ASN_PARSE_E; + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + /* Get the responseBytes SEQUENCE */ + if (GetSequence(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + /* Check ObjectID for the resposeBytes */ + if (GetObjectId(source, &idx, &oid, size) < 0) + return ASN_PARSE_E; + if (oid != OCSP_BASIC_OID) + return ASN_PARSE_E; + if (source[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(source, &idx, &length, size) < 0) + return ASN_PARSE_E; + + if (DecodeBasicOcspResponse(source, &idx, resp, size) < 0) + return ASN_PARSE_E; + + return 0; +} + + +static word32 SetOcspReqExtensions(word32 extSz, byte* output, + const byte* nonce, word32 nonceSz) +{ + static const byte NonceObjId[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x02 }; + byte seqArray[5][MAX_SEQ_SZ]; + word32 seqSz[5], totalSz; + + CYASSL_ENTER("SetOcspReqExtensions"); + + if (nonce == NULL || nonceSz == 0) return 0; + + seqArray[0][0] = ASN_OCTET_STRING; + seqSz[0] = 1 + SetLength(nonceSz, &seqArray[0][1]); + + seqArray[1][0] = ASN_OBJECT_ID; + seqSz[1] = 1 + SetLength(sizeof(NonceObjId), &seqArray[1][1]); + + totalSz = seqSz[0] + seqSz[1] + nonceSz + (word32)sizeof(NonceObjId); + + seqSz[2] = SetSequence(totalSz, seqArray[2]); + totalSz += seqSz[2]; + + seqSz[3] = SetSequence(totalSz, seqArray[3]); + totalSz += seqSz[3]; + + seqArray[4][0] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2); + seqSz[4] = 1 + SetLength(totalSz, &seqArray[4][1]); + totalSz += seqSz[4]; + + if (totalSz < extSz) + { + totalSz = 0; + XMEMCPY(output + totalSz, seqArray[4], seqSz[4]); + totalSz += seqSz[4]; + XMEMCPY(output + totalSz, seqArray[3], seqSz[3]); + totalSz += seqSz[3]; + XMEMCPY(output + totalSz, seqArray[2], seqSz[2]); + totalSz += seqSz[2]; + XMEMCPY(output + totalSz, seqArray[1], seqSz[1]); + totalSz += seqSz[1]; + XMEMCPY(output + totalSz, NonceObjId, sizeof(NonceObjId)); + totalSz += (word32)sizeof(NonceObjId); + XMEMCPY(output + totalSz, seqArray[0], seqSz[0]); + totalSz += seqSz[0]; + XMEMCPY(output + totalSz, nonce, nonceSz); + totalSz += nonceSz; + } + + return totalSz; +} + + +int EncodeOcspRequest(OcspRequest* req) +{ + byte seqArray[5][MAX_SEQ_SZ]; + /* The ASN.1 of the OCSP Request is an onion of sequences */ + byte algoArray[MAX_ALGO_SZ]; + byte issuerArray[MAX_ENCODED_DIG_SZ]; + byte issuerKeyArray[MAX_ENCODED_DIG_SZ]; + byte snArray[MAX_SN_SZ]; + byte extArray[MAX_OCSP_EXT_SZ]; + byte* output = req->dest; + word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, extSz, totalSz; + int i; + + CYASSL_ENTER("EncodeOcspRequest"); + + algoSz = SetAlgoID(SHAh, algoArray, hashType, 0); + + req->issuerHash = req->cert->issuerHash; + issuerSz = SetDigest(req->cert->issuerHash, SHA_SIZE, issuerArray); + + req->issuerKeyHash = req->cert->issuerKeyHash; + issuerKeySz = SetDigest(req->cert->issuerKeyHash, SHA_SIZE, issuerKeyArray); + + req->serial = req->cert->serial; + req->serialSz = req->cert->serialSz; + snSz = SetSerialNumber(req->cert->serial, req->cert->serialSz, snArray); + + extSz = 0; + if (req->useNonce) { + RNG rng; + if (InitRng(&rng) != 0) { + CYASSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce."); + } else { + if (RNG_GenerateBlock(&rng, req->nonce, MAX_OCSP_NONCE_SZ) != 0) + CYASSL_MSG("\tCannot run RNG. Skipping the OSCP Nonce."); + else { + req->nonceSz = MAX_OCSP_NONCE_SZ; + extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray, + req->nonce, req->nonceSz); + } + } + } + + totalSz = algoSz + issuerSz + issuerKeySz + snSz; + + for (i = 4; i >= 0; i--) { + seqSz[i] = SetSequence(totalSz, seqArray[i]); + totalSz += seqSz[i]; + if (i == 2) totalSz += extSz; + } + totalSz = 0; + for (i = 0; i < 5; i++) { + XMEMCPY(output + totalSz, seqArray[i], seqSz[i]); + totalSz += seqSz[i]; + } + XMEMCPY(output + totalSz, algoArray, algoSz); + totalSz += algoSz; + XMEMCPY(output + totalSz, issuerArray, issuerSz); + totalSz += issuerSz; + XMEMCPY(output + totalSz, issuerKeyArray, issuerKeySz); + totalSz += issuerKeySz; + XMEMCPY(output + totalSz, snArray, snSz); + totalSz += snSz; + if (extSz != 0) { + XMEMCPY(output + totalSz, extArray, extSz); + totalSz += extSz; + } + + return totalSz; +} + + +void InitOcspRequest(OcspRequest* req, DecodedCert* cert, byte useNonce, + byte* dest, word32 destSz) +{ + CYASSL_ENTER("InitOcspRequest"); + + req->cert = cert; + req->useNonce = useNonce; + req->nonceSz = 0; + req->issuerHash = NULL; + req->issuerKeyHash = NULL; + req->serial = NULL; + req->dest = dest; + req->destSz = destSz; +} + + +int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp) +{ + int cmp; + + CYASSL_ENTER("CompareOcspReqResp"); + + if (req == NULL) + { + CYASSL_MSG("\tReq missing"); + return -1; + } + + if (resp == NULL) + { + CYASSL_MSG("\tResp missing"); + return 1; + } + + /* Nonces are not critical. The responder may not necessarily add + * the nonce to the response. */ + if (req->useNonce && resp->nonceSz != 0) { + cmp = req->nonceSz - resp->nonceSz; + if (cmp != 0) + { + CYASSL_MSG("\tnonceSz mismatch"); + return cmp; + } + + cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz); + if (cmp != 0) + { + CYASSL_MSG("\tnonce mismatch"); + return cmp; + } + } + + cmp = XMEMCMP(req->issuerHash, resp->issuerHash, SHA_DIGEST_SIZE); + if (cmp != 0) + { + CYASSL_MSG("\tissuerHash mismatch"); + return cmp; + } + + cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, SHA_DIGEST_SIZE); + if (cmp != 0) + { + CYASSL_MSG("\tissuerKeyHash mismatch"); + return cmp; + } + + cmp = req->serialSz - resp->status->serialSz; + if (cmp != 0) + { + CYASSL_MSG("\tserialSz mismatch"); + return cmp; + } + + cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz); + if (cmp != 0) + { + CYASSL_MSG("\tserial mismatch"); + return cmp; + } + + return 0; +} + +#endif + + +/* store SHA1 hash of NAME */ +CYASSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash, + int maxIdx) +{ + Sha sha; + int length; /* length of all distinguished names */ + int ret = 0; + word32 dummy; + + CYASSL_ENTER("GetNameHash"); + + if (source[*idx] == ASN_OBJECT_ID) { + CYASSL_MSG("Trying optional prefix..."); + + if (GetLength(source, idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + *idx += length; + CYASSL_MSG("Got optional prefix"); + } + + /* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be + * calculated over the entire DER encoding of the Name field, including + * the tag and length. */ + dummy = *idx; + if (GetSequence(source, idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, source + dummy, length + *idx - dummy); + ShaFinal(&sha, hash); + + *idx += length; + + return 0; +} + + +#ifdef HAVE_CRL + +/* initialize decoded CRL */ +void InitDecodedCRL(DecodedCRL* dcrl) +{ + CYASSL_MSG("InitDecodedCRL"); + + dcrl->certBegin = 0; + dcrl->sigIndex = 0; + dcrl->sigLength = 0; + dcrl->signatureOID = 0; + dcrl->certs = NULL; + dcrl->totalCerts = 0; +} + + +/* free decoded CRL resources */ +void FreeDecodedCRL(DecodedCRL* dcrl) +{ + RevokedCert* tmp = dcrl->certs; + + CYASSL_MSG("FreeDecodedCRL"); + + while(tmp) { + RevokedCert* next = tmp->next; + XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED); + tmp = next; + } +} + + +/* Get Revoked Cert list, 0 on success */ +static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, + int maxIdx) +{ + int len; + word32 end; + byte b; + RevokedCert* rc; + + CYASSL_ENTER("GetRevoked"); + + if (GetSequence(buff, idx, &len, maxIdx) < 0) + return ASN_PARSE_E; + + end = *idx + len; + + /* get serial number */ + b = buff[*idx]; + *idx += 1; + + if (b != ASN_INTEGER) { + CYASSL_MSG("Expecting Integer"); + return ASN_PARSE_E; + } + + if (GetLength(buff, idx, &len, maxIdx) < 0) + return ASN_PARSE_E; + + if (len > EXTERNAL_SERIAL_SIZE) { + CYASSL_MSG("Serial Size too big"); + return ASN_PARSE_E; + } + + rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), NULL, DYNAMIC_TYPE_CRL); + if (rc == NULL) { + CYASSL_MSG("Alloc Revoked Cert failed"); + return MEMORY_E; + } + + XMEMCPY(rc->serialNumber, &buff[*idx], len); + rc->serialSz = len; + + /* add to list */ + rc->next = dcrl->certs; + dcrl->certs = rc; + dcrl->totalCerts++; + + *idx += len; + + /* get date */ + b = buff[*idx]; + *idx += 1; + + if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) { + CYASSL_MSG("Expecting Date"); + return ASN_PARSE_E; + } + + if (GetLength(buff, idx, &len, maxIdx) < 0) + return ASN_PARSE_E; + + /* skip for now */ + *idx += len; + + if (*idx != end) /* skip extensions */ + *idx = end; + + return 0; +} + + +/* Get CRL Signature, 0 on success */ +static int GetCRL_Signature(const byte* source, word32* idx, DecodedCRL* dcrl, + int maxIdx) +{ + int length; + byte b; + + CYASSL_ENTER("GetCRL_Signature"); + + b = source[*idx]; + *idx += 1; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(source, idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + dcrl->sigLength = length; + + b = source[*idx]; + *idx += 1; + if (b != 0x00) + return ASN_EXPECT_0_E; + + dcrl->sigLength--; + dcrl->signature = (byte*)&source[*idx]; + + *idx += dcrl->sigLength; + + return 0; +} + + +/* prase crl buffer into decoded state, 0 on success */ +int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm) +{ + int version, len; + word32 oid, idx = 0; + Signer* ca = NULL; + + CYASSL_MSG("ParseCRL"); + + /* raw crl hash */ + /* hash here if needed for optimized comparisons + * Sha sha; + * InitSha(&sha); + * ShaUpdate(&sha, buff, sz); + * ShaFinal(&sha, dcrl->crlHash); */ + + if (GetSequence(buff, &idx, &len, sz) < 0) + return ASN_PARSE_E; + + dcrl->certBegin = idx; + + if (GetSequence(buff, &idx, &len, sz) < 0) + return ASN_PARSE_E; + dcrl->sigIndex = len + idx; + + /* may have version */ + if (buff[idx] == ASN_INTEGER) { + if (GetMyVersion(buff, &idx, &version) < 0) + return ASN_PARSE_E; + } + + if (GetAlgoId(buff, &idx, &oid, sz) < 0) + return ASN_PARSE_E; + + if (GetNameHash(buff, &idx, dcrl->issuerHash, sz) < 0) + return ASN_PARSE_E; + + if (GetBasicDate(buff, &idx, dcrl->lastDate, &dcrl->lastDateFormat, sz) < 0) + return ASN_PARSE_E; + + if (GetBasicDate(buff, &idx, dcrl->nextDate, &dcrl->nextDateFormat, sz) < 0) + return ASN_PARSE_E; + + if (!XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, AFTER)) { + CYASSL_MSG("CRL after date is no longer valid"); + return ASN_AFTER_DATE_E; + } + + if (idx != dcrl->sigIndex && buff[idx] != CRL_EXTENSIONS) { + if (GetSequence(buff, &idx, &len, sz) < 0) + return ASN_PARSE_E; + + len += idx; + + while (idx < (word32)len) { + if (GetRevoked(buff, &idx, dcrl, sz) < 0) + return ASN_PARSE_E; + } + } + + if (idx != dcrl->sigIndex) + idx = dcrl->sigIndex; /* skip extensions */ + + if (GetAlgoId(buff, &idx, &dcrl->signatureOID, sz) < 0) + return ASN_PARSE_E; + + if (GetCRL_Signature(buff, &idx, dcrl, sz) < 0) + return ASN_PARSE_E; + + /* openssl doesn't add skid by default for CRLs cause firefox chokes + we're not assuming it's available yet */ + #if !defined(NO_SKID) && defined(CRL_SKID_READY) + if (dcrl->extAuthKeyIdSet) + ca = GetCA(cm, dcrl->extAuthKeyId); + if (ca == NULL) + ca = GetCAByName(cm, dcrl->issuerHash); + #else /* NO_SKID */ + ca = GetCA(cm, dcrl->issuerHash); + #endif /* NO_SKID */ + CYASSL_MSG("About to verify CRL signature"); + + if (ca) { + CYASSL_MSG("Found CRL issuer CA"); + /* try to confirm/verify signature */ + #ifndef IGNORE_KEY_EXTENSIONS + if ((ca->keyUsage & KEYUSE_CRL_SIGN) == 0) { + CYASSL_MSG("CA cannot sign CRLs"); + return ASN_CRL_NO_SIGNER_E; + } + #endif /* IGNORE_KEY_EXTENSIONS */ + if (!ConfirmSignature(buff + dcrl->certBegin, + dcrl->sigIndex - dcrl->certBegin, + ca->publicKey, ca->pubKeySize, ca->keyOID, + dcrl->signature, dcrl->sigLength, dcrl->signatureOID, NULL)) { + CYASSL_MSG("CRL Confirm signature failed"); + return ASN_CRL_CONFIRM_E; + } + } + else { + CYASSL_MSG("Did NOT find CRL issuer CA"); + return ASN_CRL_NO_SIGNER_E; + } + + return 0; +} + +#endif /* HAVE_CRL */ +#endif + +#ifdef CYASSL_SEP + + + +#endif /* CYASSL_SEP */ + +
diff -r 64d4f7cb83d5 -r e505054279ed ctaocrypt/src/random.c --- a/ctaocrypt/src/random.c Wed Dec 03 05:24:18 2014 +0000 +++ b/ctaocrypt/src/random.c Wed Jan 14 22:07:14 2015 +0000 @@ -1,846 +1,853 @@ -/* random.c - * - * Copyright (C) 2006-2014 wolfSSL Inc. - * - * This file is part of CyaSSL. - * - * CyaSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * CyaSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <cyassl/ctaocrypt/settings.h> - -/* on HPUX 11 you may need to install /dev/random see - http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I - -*/ - -#include <cyassl/ctaocrypt/random.h> -#include <cyassl/ctaocrypt/error-crypt.h> - -#ifdef NO_RC4 - #include <cyassl/ctaocrypt/sha256.h> - - #ifdef NO_INLINE - #include <cyassl/ctaocrypt/misc.h> - #else - #define MISC_DUMM_FUNC misc_dummy_random - #include <ctaocrypt/src/misc.c> - #endif -#endif - -#if defined(USE_WINDOWS_API) - #ifndef _WIN32_WINNT - #define _WIN32_WINNT 0x0400 - #endif - #include <windows.h> - #include <wincrypt.h> -#else - #if !defined(NO_DEV_RANDOM) && !defined(CYASSL_MDK_ARM) \ - && !defined(CYASSL_IAR_ARM) - #include <fcntl.h> - #ifndef EBSNET - #include <unistd.h> - #endif - #else - /* include headers that may be needed to get good seed */ - #endif -#endif /* USE_WINDOWS_API */ - - -#ifdef NO_RC4 - -/* Start NIST DRBG code */ - -#define OUTPUT_BLOCK_LEN (256/8) -#define MAX_REQUEST_LEN (0x1000) -#define MAX_STRING_LEN (0x100000000) -#define RESEED_MAX (0x100000000000LL) -#define ENTROPY_SZ 256 - -#define DBRG_SUCCESS 0 -#define DBRG_ERROR 1 -#define DBRG_NEED_RESEED 2 - - -enum { - dbrgInitC = 0, - dbrgReseed = 1, - dbrgGenerateW = 2, - dbrgGenerateH = 3, - dbrgInitV -}; - - -static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type, byte* inA, word32 inASz, - byte* inB, word32 inBSz, byte* inC, word32 inCSz) -{ - byte ctr; - int i; - int len; - word32 bits = (outSz * 8); /* reverse byte order */ - - #ifdef LITTLE_ENDIAN_ORDER - bits = ByteReverseWord32(bits); - #endif - len = (outSz / SHA256_DIGEST_SIZE) - + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); - - for (i = 0, ctr = 1; i < len; i++, ctr++) - { - if (InitSha256(&rng->sha) != 0) - return DBRG_ERROR; - - if (Sha256Update(&rng->sha, &ctr, sizeof(ctr)) != 0) - return DBRG_ERROR; - - if (Sha256Update(&rng->sha, (byte*)&bits, sizeof(bits)) != 0) - return DBRG_ERROR; - - /* churning V is the only string that doesn't have - * the type added */ - if (type != dbrgInitV) - if (Sha256Update(&rng->sha, &type, sizeof(type)) != 0) - return DBRG_ERROR; - - if (Sha256Update(&rng->sha, inA, inASz) != 0) - return DBRG_ERROR; - - if (inB != NULL && inBSz > 0) - if (Sha256Update(&rng->sha, inB, inBSz) != 0) - return DBRG_ERROR; - - if (inC != NULL && inCSz > 0) - if (Sha256Update(&rng->sha, inC, inCSz) != 0) - return DBRG_ERROR; - - if (Sha256Final(&rng->sha, rng->digest) != 0) - return DBRG_ERROR; - - if (outSz > SHA256_DIGEST_SIZE) { - XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE); - outSz -= SHA256_DIGEST_SIZE; - out += SHA256_DIGEST_SIZE; - } - else { - XMEMCPY(out, rng->digest, outSz); - } - } - - return DBRG_SUCCESS; -} - - -static int Hash_DBRG_Reseed(RNG* rng, byte* entropy, word32 entropySz) -{ - int ret; - byte seed[DBRG_SEED_LEN]; - - ret = Hash_df(rng, seed, sizeof(seed), dbrgInitV, rng->V, sizeof(rng->V), - entropy, entropySz, NULL, 0); - if (ret != 0) - return ret; - - XMEMCPY(rng->V, seed, sizeof(rng->V)); - XMEMSET(seed, 0, sizeof(seed)); - - ret = Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, - sizeof(rng->V), NULL, 0, NULL, 0); - if (ret != 0) - return ret; - - rng->reseed_ctr = 1; - return 0; -} - -static INLINE void array_add_one(byte* data, word32 dataSz) -{ - int i; - - for (i = dataSz - 1; i >= 0; i--) - { - data[i]++; - if (data[i] != 0) break; - } -} - -static int Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V) -{ - byte data[DBRG_SEED_LEN]; - int i, ret; - int len = (outSz / SHA256_DIGEST_SIZE) - + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); - - XMEMCPY(data, V, sizeof(data)); - for (i = 0; i < len; i++) { - ret = InitSha256(&rng->sha); - if (ret != 0) - return ret; - - ret = Sha256Update(&rng->sha, data, sizeof(data)); - if (ret != 0) - return ret; - - ret = Sha256Final(&rng->sha, rng->digest); - if (ret != 0) - return ret; - - if (outSz > SHA256_DIGEST_SIZE) { - XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE); - outSz -= SHA256_DIGEST_SIZE; - out += SHA256_DIGEST_SIZE; - array_add_one(data, DBRG_SEED_LEN); - } - else { - XMEMCPY(out, rng->digest, outSz); - } - } - XMEMSET(data, 0, sizeof(data)); - - return 0; -} - - -static INLINE void array_add(byte* d, word32 dLen, byte* s, word32 sLen) -{ - word16 carry = 0; - - if (dLen > 0 && sLen > 0 && dLen >= sLen) { - int sIdx, dIdx; - - for (sIdx = sLen - 1, dIdx = dLen - 1; sIdx >= 0; dIdx--, sIdx--) - { - carry += d[dIdx] + s[sIdx]; - d[dIdx] = carry; - carry >>= 8; - } - if (dIdx > 0) - d[dIdx] += carry; - } -} - - -static int Hash_DBRG_Generate(RNG* rng, byte* out, word32 outSz) -{ - int ret; - - if (rng->reseed_ctr != RESEED_MAX) { - byte type = dbrgGenerateH; - - if (Hash_gen(rng, out, outSz, rng->V) != 0) - return DBRG_ERROR; - if (InitSha256(&rng->sha) != 0) - return DBRG_ERROR; - if (Sha256Update(&rng->sha, &type, sizeof(type)) != 0) - return DBRG_ERROR; - if (Sha256Update(&rng->sha, rng->V, sizeof(rng->V)) != 0) - return DBRG_ERROR; - if (Sha256Final(&rng->sha, rng->digest) != 0) - return DBRG_ERROR; - - array_add(rng->V, sizeof(rng->V), rng->digest, sizeof(rng->digest)); - array_add(rng->V, sizeof(rng->V), rng->C, sizeof(rng->C)); - array_add(rng->V, sizeof(rng->V), - (byte*)&rng->reseed_ctr, sizeof(rng->reseed_ctr)); - rng->reseed_ctr++; - ret = DBRG_SUCCESS; - } - else { - ret = DBRG_NEED_RESEED; - } - return ret; -} - - -static int Hash_DBRG_Instantiate(RNG* rng, byte* seed, word32 seedSz) -{ - int ret; - - XMEMSET(rng, 0, sizeof(*rng)); - ret = Hash_df(rng, rng->V, sizeof(rng->V), dbrgInitV, seed, seedSz, NULL, 0, - NULL, 0); - if (ret != 0) - return ret; - - ret = Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, - sizeof(rng->V), NULL, 0, NULL, 0); - if (ret != 0) - return ret; - - rng->reseed_ctr = 1; - - return 0; -} - - -static int Hash_DBRG_Uninstantiate(RNG* rng) -{ - int result = DBRG_ERROR; - - if (rng != NULL) { - XMEMSET(rng, 0, sizeof(*rng)); - result = DBRG_SUCCESS; - } - - return result; -} - -/* End NIST DRBG Code */ - - - -/* Get seed and key cipher */ -int InitRng(RNG* rng) -{ -#ifdef CYASSL_SMALL_STACK - byte* entropy; -#else - byte entropy[ENTROPY_SZ]; -#endif - int ret = DBRG_ERROR; - -#ifdef CYASSL_SMALL_STACK - entropy = (byte*)XMALLOC(ENTROPY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (entropy == NULL) - return MEMORY_E; -#endif - - if (GenerateSeed(&rng->seed, entropy, ENTROPY_SZ) == 0) - ret = Hash_DBRG_Instantiate(rng, entropy, ENTROPY_SZ); - - XMEMSET(entropy, 0, ENTROPY_SZ); - -#ifdef CYASSL_SMALL_STACK - XFREE(entropy, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - - -/* place a generated block in output */ -int RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) -{ - int ret; - - XMEMSET(output, 0, sz); - ret = Hash_DBRG_Generate(rng, output, sz); - - if (ret == DBRG_NEED_RESEED) { -#ifdef CYASSL_SMALL_STACK - byte* entropy; -#else - byte entropy[ENTROPY_SZ]; -#endif - -#ifdef CYASSL_SMALL_STACK - entropy = (byte*)XMALLOC(ENTROPY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (entropy == NULL) - return MEMORY_E; -#endif - - ret = GenerateSeed(&rng->seed, entropy, ENTROPY_SZ); - if (ret == 0) { - ret = Hash_DBRG_Reseed(rng, entropy, ENTROPY_SZ); - - if (ret == 0) - ret = Hash_DBRG_Generate(rng, output, sz); - } - else - ret = DBRG_ERROR; - - XMEMSET(entropy, 0, ENTROPY_SZ); - -#ifdef CYASSL_SMALL_STACK - XFREE(entropy, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - } - - return ret; -} - - -int RNG_GenerateByte(RNG* rng, byte* b) -{ - return RNG_GenerateBlock(rng, b, 1); -} - - -void FreeRng(RNG* rng) -{ - Hash_DBRG_Uninstantiate(rng); -} - -#else /* NO_RC4 */ - -/* Get seed and key cipher */ -int InitRng(RNG* rng) -{ - int ret; -#ifdef CYASSL_SMALL_STACK - byte* key; - byte* junk; -#else - byte key[32]; - byte junk[256]; -#endif - -#ifdef HAVE_CAVIUM - if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC) - return 0; -#endif - -#ifdef CYASSL_SMALL_STACK - key = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (key == NULL) - return MEMORY_E; - - junk = (byte*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (junk == NULL) { - XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - ret = GenerateSeed(&rng->seed, key, 32); - - if (ret == 0) { - Arc4SetKey(&rng->cipher, key, sizeof(key)); - - ret = RNG_GenerateBlock(rng, junk, 256); /*rid initial state*/ - } - -#ifdef CYASSL_SMALL_STACK - XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(junk, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -#ifdef HAVE_CAVIUM - static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz); -#endif - -/* place a generated block in output */ -int RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) -{ -#ifdef HAVE_CAVIUM - if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC) - return CaviumRNG_GenerateBlock(rng, output, sz); -#endif - XMEMSET(output, 0, sz); - Arc4Process(&rng->cipher, output, output, sz); - - return 0; -} - - -int RNG_GenerateByte(RNG* rng, byte* b) -{ - return RNG_GenerateBlock(rng, b, 1); -} - - -#ifdef HAVE_CAVIUM - -#include <cyassl/ctaocrypt/logging.h> -#include "cavium_common.h" - -/* Initiliaze RNG for use with Nitrox device */ -int InitRngCavium(RNG* rng, int devId) -{ - if (rng == NULL) - return -1; - - rng->devId = devId; - rng->magic = CYASSL_RNG_CAVIUM_MAGIC; - - return 0; -} - - -static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz) -{ - word offset = 0; - word32 requestId; - - while (sz > CYASSL_MAX_16BIT) { - word16 slen = (word16)CYASSL_MAX_16BIT; - if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId, - rng->devId) != 0) { - CYASSL_MSG("Cavium RNG failed"); - } - sz -= CYASSL_MAX_16BIT; - offset += CYASSL_MAX_16BIT; - } - if (sz) { - word16 slen = (word16)sz; - if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId, - rng->devId) != 0) { - CYASSL_MSG("Cavium RNG failed"); - } - } -} - -#endif /* HAVE_CAVIUM */ - -#endif /* NO_RC4 */ - - -#if defined(USE_WINDOWS_API) - - -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - return WINCRYPT_E; - - if (!CryptGenRandom(os->handle, sz, output)) - return CRYPTGEN_E; - - CryptReleaseContext(os->handle, 0); - - return 0; -} - - -#elif defined(HAVE_RTP_SYS) || defined(EBSNET) - -#include "rtprand.h" /* rtp_rand () */ -#include "rtptime.h" /* rtp_get_system_msec() */ - - -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - int i; - rtp_srand(rtp_get_system_msec()); - - for (i = 0; i < sz; i++ ) { - output[i] = rtp_rand() % 256; - if ( (i % 8) == 7) - rtp_srand(rtp_get_system_msec()); - } - - return 0; -} - - -#elif defined(MICRIUM) - -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) - NetSecure_InitSeed(output, sz); - #endif - return 0; -} - -#elif defined(MBED) - -/* write a real one !!!, just for testing board */ -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - int i; - for (i = 0; i < sz; i++ ) - output[i] = i; - - return 0; -} - -#elif defined(MICROCHIP_PIC32) - -#ifdef MICROCHIP_MPLAB_HARMONY - #define PIC32_SEED_COUNT _CP0_GET_COUNT -#else - #if !defined(CYASSL_MICROCHIP_PIC32MZ) - #include <peripheral/timer.h> - #endif - #define PIC32_SEED_COUNT ReadCoreTimer -#endif - #ifdef CYASSL_MIC32MZ_RNG - #include "xc.h" - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i ; - byte rnd[8] ; - word32 *rnd32 = (word32 *)rnd ; - word32 size = sz ; - byte* op = output ; - - /* This part has to be replaced with better random seed */ - RNGNUMGEN1 = ReadCoreTimer(); - RNGPOLY1 = ReadCoreTimer(); - RNGPOLY2 = ReadCoreTimer(); - RNGNUMGEN2 = ReadCoreTimer(); -#ifdef DEBUG_CYASSL - printf("GenerateSeed::Seed=%08x, %08x\n", RNGNUMGEN1, RNGNUMGEN2) ; -#endif - RNGCONbits.PLEN = 0x40; - RNGCONbits.PRNGEN = 1; - for(i=0; i<5; i++) { /* wait for RNGNUMGEN ready */ - volatile int x ; - x = RNGNUMGEN1 ; - x = RNGNUMGEN2 ; - } - do { - rnd32[0] = RNGNUMGEN1; - rnd32[1] = RNGNUMGEN2; - - for(i=0; i<8; i++, op++) { - *op = rnd[i] ; - size -- ; - if(size==0)break ; - } - } while(size) ; - return 0; - } - #else /* CYASSL_MIC32MZ_RNG */ - /* uses the core timer, in nanoseconds to seed srand */ - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - srand(PIC32_SEED_COUNT() * 25); - - for (i = 0; i < sz; i++ ) { - output[i] = rand() % 256; - if ( (i % 8) == 7) - srand(PIC32_SEED_COUNT() * 25); - } - return 0; - } - #endif /* CYASSL_MIC32MZ_RNG */ - -#elif defined(FREESCALE_MQX) - - #ifdef FREESCALE_K70_RNGA - /* - * Generates a RNG seed using the Random Number Generator Accelerator - * on the Kinetis K70. Documentation located in Chapter 37 of - * K70 Sub-Family Reference Manual (see Note 3 in the README for link). - */ - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - - /* turn on RNGA module */ - SIM_SCGC3 |= SIM_SCGC3_RNGA_MASK; - - /* set SLP bit to 0 - "RNGA is not in sleep mode" */ - RNG_CR &= ~RNG_CR_SLP_MASK; - - /* set HA bit to 1 - "security violations masked" */ - RNG_CR |= RNG_CR_HA_MASK; - - /* set GO bit to 1 - "output register loaded with data" */ - RNG_CR |= RNG_CR_GO_MASK; - - for (i = 0; i < sz; i++) { - - /* wait for RNG FIFO to be full */ - while((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0) {} - - /* get value */ - output[i] = RNG_OR; - } - - return 0; - } - - #elif defined(FREESCALE_K53_RNGB) - /* - * Generates a RNG seed using the Random Number Generator (RNGB) - * on the Kinetis K53. Documentation located in Chapter 33 of - * K53 Sub-Family Reference Manual (see note in the README for link). - */ - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - - /* turn on RNGB module */ - SIM_SCGC3 |= SIM_SCGC3_RNGB_MASK; - - /* reset RNGB */ - RNG_CMD |= RNG_CMD_SR_MASK; - - /* FIFO generate interrupt, return all zeros on underflow, - * set auto reseed */ - RNG_CR |= (RNG_CR_FUFMOD_MASK | RNG_CR_AR_MASK); - - /* gen seed, clear interrupts, clear errors */ - RNG_CMD |= (RNG_CMD_GS_MASK | RNG_CMD_CI_MASK | RNG_CMD_CE_MASK); - - /* wait for seeding to complete */ - while ((RNG_SR & RNG_SR_SDN_MASK) == 0) {} - - for (i = 0; i < sz; i++) { - - /* wait for a word to be available from FIFO */ - while((RNG_SR & RNG_SR_FIFO_LVL_MASK) == 0) {} - - /* get value */ - output[i] = RNG_OUT; - } - - return 0; - } - - #else - #warning "write a real random seed!!!!, just for testing now" - - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - for (i = 0; i < sz; i++ ) - output[i] = i; - - return 0; - } - #endif /* FREESCALE_K70_RNGA */ - -#elif defined(CYASSL_SAFERTOS) || defined(CYASSL_LEANPSK) \ - || defined(CYASSL_IAR_ARM) - -#warning "write a real random seed!!!!, just for testing now" - -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - word32 i; - for (i = 0; i < sz; i++ ) - output[i] = i; - - (void)os; - - return 0; -} - -#elif defined(STM32F2_RNG) - #undef RNG - #include "stm32f2xx_rng.h" - #include "stm32f2xx_rcc.h" - /* - * Generate a RNG seed using the hardware random number generator - * on the STM32F2. Documentation located in STM32F2xx Standard Peripheral - * Library document (See note in README). - */ - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - - /* enable RNG clock source */ - RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE); - - /* enable RNG peripheral */ - RNG_Cmd(ENABLE); - - for (i = 0; i < sz; i++) { - /* wait until RNG number is ready */ - while(RNG_GetFlagStatus(RNG_FLAG_DRDY)== RESET) { } - - /* get value */ - output[i] = RNG_GetRandomNumber(); - } - - return 0; - } -#elif defined(CYASSL_LPC43xx) || defined(CYASSL_STM32F2xx) - - #warning "write a real random seed!!!!, just for testing now" - - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - - for (i = 0; i < sz; i++ ) - output[i] = i; - - return 0; - } - -#elif defined(CUSTOM_RAND_GENERATE) - - /* Implement your own random generation function - * word32 rand_gen(void); - * #define CUSTOM_RAND_GENERATE rand_gen */ - - int GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - int i; - - for (i = 0; i < sz; i++ ) - output[i] = CUSTOM_RAND_GENERATE(); - - return 0; - } - -#elif defined(NO_DEV_RANDOM) - -#error "you need to write an os specific GenerateSeed() here" - -/* -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - return 0; -} -*/ - - -#else /* !USE_WINDOWS_API && !HAVE_RPT_SYS && !MICRIUM && !NO_DEV_RANDOM */ - - -/* may block */ -int GenerateSeed(OS_Seed* os, byte* output, word32 sz) -{ - int ret = 0; - - os->fd = open("/dev/urandom",O_RDONLY); - if (os->fd == -1) { - /* may still have /dev/random */ - os->fd = open("/dev/random",O_RDONLY); - if (os->fd == -1) - return OPEN_RAN_E; - } - - while (sz) { - int len = (int)read(os->fd, output, sz); - if (len == -1) { - ret = READ_RAN_E; - break; - } - - sz -= len; - output += len; - - if (sz) { -#ifdef BLOCKING - sleep(0); /* context switch */ -#else - ret = RAN_BLOCK_E; - break; -#endif - } - } - close(os->fd); - - return ret; -} - -#endif /* USE_WINDOWS_API */ - +/* random.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <cyassl/ctaocrypt/settings.h> + +/* on HPUX 11 you may need to install /dev/random see + http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I + +*/ + +#include <cyassl/ctaocrypt/random.h> +#include <cyassl/ctaocrypt/error-crypt.h> + +#ifdef NO_RC4 + #include <cyassl/ctaocrypt/sha256.h> + + #ifdef NO_INLINE + #include <cyassl/ctaocrypt/misc.h> + #else + #define MISC_DUMM_FUNC misc_dummy_random + #include <ctaocrypt/src/misc.c> + #endif +#endif + +#if defined(USE_WINDOWS_API) + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 + #endif + #include <windows.h> + #include <wincrypt.h> +#else + #if !defined(NO_DEV_RANDOM) && !defined(CYASSL_MDK_ARM) \ + && !defined(CYASSL_IAR_ARM) + #include <fcntl.h> + #ifndef EBSNET + #include <unistd.h> + #endif + #else + /* include headers that may be needed to get good seed */ + #endif +#endif /* USE_WINDOWS_API */ + + +#ifdef NO_RC4 + +/* Start NIST DRBG code */ + +#define OUTPUT_BLOCK_LEN (256/8) +#define MAX_REQUEST_LEN (0x1000) +#define MAX_STRING_LEN (0x100000000) +#define RESEED_MAX (0x100000000000LL) +#define ENTROPY_SZ 256 + +#define DBRG_SUCCESS 0 +#define DBRG_ERROR 1 +#define DBRG_NEED_RESEED 2 + + +enum { + dbrgInitC = 0, + dbrgReseed = 1, + dbrgGenerateW = 2, + dbrgGenerateH = 3, + dbrgInitV +}; + + +static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type, byte* inA, word32 inASz, + byte* inB, word32 inBSz, byte* inC, word32 inCSz) +{ + byte ctr; + int i; + int len; + word32 bits = (outSz * 8); /* reverse byte order */ + + #ifdef LITTLE_ENDIAN_ORDER + bits = ByteReverseWord32(bits); + #endif + len = (outSz / SHA256_DIGEST_SIZE) + + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); + + for (i = 0, ctr = 1; i < len; i++, ctr++) + { + if (InitSha256(&rng->sha) != 0) + return DBRG_ERROR; + + if (Sha256Update(&rng->sha, &ctr, sizeof(ctr)) != 0) + return DBRG_ERROR; + + if (Sha256Update(&rng->sha, (byte*)&bits, sizeof(bits)) != 0) + return DBRG_ERROR; + + /* churning V is the only string that doesn't have + * the type added */ + if (type != dbrgInitV) + if (Sha256Update(&rng->sha, &type, sizeof(type)) != 0) + return DBRG_ERROR; + + if (Sha256Update(&rng->sha, inA, inASz) != 0) + return DBRG_ERROR; + + if (inB != NULL && inBSz > 0) + if (Sha256Update(&rng->sha, inB, inBSz) != 0) + return DBRG_ERROR; + + if (inC != NULL && inCSz > 0) + if (Sha256Update(&rng->sha, inC, inCSz) != 0) + return DBRG_ERROR; + + if (Sha256Final(&rng->sha, rng->digest) != 0) + return DBRG_ERROR; + + if (outSz > SHA256_DIGEST_SIZE) { + XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE); + outSz -= SHA256_DIGEST_SIZE; + out += SHA256_DIGEST_SIZE; + } + else { + XMEMCPY(out, rng->digest, outSz); + } + } + + return DBRG_SUCCESS; +} + + +static int Hash_DBRG_Reseed(RNG* rng, byte* entropy, word32 entropySz) +{ + int ret; + byte seed[DBRG_SEED_LEN]; + + ret = Hash_df(rng, seed, sizeof(seed), dbrgInitV, rng->V, sizeof(rng->V), + entropy, entropySz, NULL, 0); + if (ret != 0) + return ret; + + XMEMCPY(rng->V, seed, sizeof(rng->V)); + XMEMSET(seed, 0, sizeof(seed)); + + ret = Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, + sizeof(rng->V), NULL, 0, NULL, 0); + if (ret != 0) + return ret; + + rng->reseed_ctr = 1; + return 0; +} + +static INLINE void array_add_one(byte* data, word32 dataSz) +{ + int i; + + for (i = dataSz - 1; i >= 0; i--) + { + data[i]++; + if (data[i] != 0) break; + } +} + +static int Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V) +{ + byte data[DBRG_SEED_LEN]; + int i, ret; + int len = (outSz / SHA256_DIGEST_SIZE) + + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); + + XMEMCPY(data, V, sizeof(data)); + for (i = 0; i < len; i++) { + ret = InitSha256(&rng->sha); + if (ret != 0) + return ret; + + ret = Sha256Update(&rng->sha, data, sizeof(data)); + if (ret != 0) + return ret; + + ret = Sha256Final(&rng->sha, rng->digest); + if (ret != 0) + return ret; + + if (outSz > SHA256_DIGEST_SIZE) { + XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE); + outSz -= SHA256_DIGEST_SIZE; + out += SHA256_DIGEST_SIZE; + array_add_one(data, DBRG_SEED_LEN); + } + else { + XMEMCPY(out, rng->digest, outSz); + } + } + XMEMSET(data, 0, sizeof(data)); + + return 0; +} + + +static INLINE void array_add(byte* d, word32 dLen, byte* s, word32 sLen) +{ + word16 carry = 0; + + if (dLen > 0 && sLen > 0 && dLen >= sLen) { + int sIdx, dIdx; + + for (sIdx = sLen - 1, dIdx = dLen - 1; sIdx >= 0; dIdx--, sIdx--) + { + carry += d[dIdx] + s[sIdx]; + d[dIdx] = carry; + carry >>= 8; + } + if (dIdx > 0) + d[dIdx] += carry; + } +} + + +static int Hash_DBRG_Generate(RNG* rng, byte* out, word32 outSz) +{ + int ret; + + if (rng->reseed_ctr != RESEED_MAX) { + byte type = dbrgGenerateH; + + if (Hash_gen(rng, out, outSz, rng->V) != 0) + return DBRG_ERROR; + if (InitSha256(&rng->sha) != 0) + return DBRG_ERROR; + if (Sha256Update(&rng->sha, &type, sizeof(type)) != 0) + return DBRG_ERROR; + if (Sha256Update(&rng->sha, rng->V, sizeof(rng->V)) != 0) + return DBRG_ERROR; + if (Sha256Final(&rng->sha, rng->digest) != 0) + return DBRG_ERROR; + + array_add(rng->V, sizeof(rng->V), rng->digest, sizeof(rng->digest)); + array_add(rng->V, sizeof(rng->V), rng->C, sizeof(rng->C)); + array_add(rng->V, sizeof(rng->V), + (byte*)&rng->reseed_ctr, sizeof(rng->reseed_ctr)); + rng->reseed_ctr++; + ret = DBRG_SUCCESS; + } + else { + ret = DBRG_NEED_RESEED; + } + return ret; +} + + +static int Hash_DBRG_Instantiate(RNG* rng, byte* seed, word32 seedSz) +{ + int ret; + + XMEMSET(rng, 0, sizeof(*rng)); + ret = Hash_df(rng, rng->V, sizeof(rng->V), dbrgInitV, seed, seedSz, NULL, 0, + NULL, 0); + if (ret != 0) + return ret; + + ret = Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, + sizeof(rng->V), NULL, 0, NULL, 0); + if (ret != 0) + return ret; + + rng->reseed_ctr = 1; + + return 0; +} + + +static int Hash_DBRG_Uninstantiate(RNG* rng) +{ + int result = DBRG_ERROR; + + if (rng != NULL) { + XMEMSET(rng, 0, sizeof(*rng)); + result = DBRG_SUCCESS; + } + + return result; +} + +/* End NIST DRBG Code */ + + + +/* Get seed and key cipher */ +int InitRng(RNG* rng) +{ +#ifdef CYASSL_SMALL_STACK + byte* entropy; +#else + byte entropy[ENTROPY_SZ]; +#endif + int ret = DBRG_ERROR; + +#ifdef CYASSL_SMALL_STACK + entropy = (byte*)XMALLOC(ENTROPY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (entropy == NULL) + return MEMORY_E; +#endif + + if (GenerateSeed(&rng->seed, entropy, ENTROPY_SZ) == 0) + ret = Hash_DBRG_Instantiate(rng, entropy, ENTROPY_SZ); + + XMEMSET(entropy, 0, ENTROPY_SZ); + +#ifdef CYASSL_SMALL_STACK + XFREE(entropy, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +/* place a generated block in output */ +int RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) +{ + int ret; + + XMEMSET(output, 0, sz); + ret = Hash_DBRG_Generate(rng, output, sz); + + if (ret == DBRG_NEED_RESEED) { +#ifdef CYASSL_SMALL_STACK + byte* entropy; +#else + byte entropy[ENTROPY_SZ]; +#endif + +#ifdef CYASSL_SMALL_STACK + entropy = (byte*)XMALLOC(ENTROPY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (entropy == NULL) + return MEMORY_E; +#endif + + ret = GenerateSeed(&rng->seed, entropy, ENTROPY_SZ); + if (ret == 0) { + ret = Hash_DBRG_Reseed(rng, entropy, ENTROPY_SZ); + + if (ret == 0) + ret = Hash_DBRG_Generate(rng, output, sz); + } + else + ret = DBRG_ERROR; + + XMEMSET(entropy, 0, ENTROPY_SZ); + +#ifdef CYASSL_SMALL_STACK + XFREE(entropy, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + } + + return ret; +} + + +int RNG_GenerateByte(RNG* rng, byte* b) +{ + return RNG_GenerateBlock(rng, b, 1); +} + + +void FreeRng(RNG* rng) +{ + Hash_DBRG_Uninstantiate(rng); +} + +#else /* NO_RC4 */ + +/* Get seed and key cipher */ +int InitRng(RNG* rng) +{ + int ret; +#ifdef CYASSL_SMALL_STACK + byte* key; + byte* junk; +#else + byte key[32]; + byte junk[256]; +#endif + +#ifdef HAVE_CAVIUM + if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC) + return 0; +#endif + +#ifdef CYASSL_SMALL_STACK + key = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (key == NULL) + return MEMORY_E; + + junk = (byte*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (junk == NULL) { + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + ret = GenerateSeed(&rng->seed, key, 32); + + if (ret == 0) { + Arc4SetKey(&rng->cipher, key, sizeof(key)); + + ret = RNG_GenerateBlock(rng, junk, 256); /*rid initial state*/ + } +#ifdef CYASSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(junk, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#ifdef HAVE_CAVIUM + static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz); +#endif + +/* place a generated block in output */ +int RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) +{ +#ifdef HAVE_CAVIUM + if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC) + return CaviumRNG_GenerateBlock(rng, output, sz); +#endif + XMEMSET(output, 0, sz); + Arc4Process(&rng->cipher, output, output, sz); + + return 0; +} + + +int RNG_GenerateByte(RNG* rng, byte* b) +{ + return RNG_GenerateBlock(rng, b, 1); +} + + +#ifdef HAVE_CAVIUM + +#include <cyassl/ctaocrypt/logging.h> +#include "cavium_common.h" + +/* Initiliaze RNG for use with Nitrox device */ +int InitRngCavium(RNG* rng, int devId) +{ + if (rng == NULL) + return -1; + + rng->devId = devId; + rng->magic = CYASSL_RNG_CAVIUM_MAGIC; + + return 0; +} + + +static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz) +{ + word offset = 0; + word32 requestId; + + while (sz > CYASSL_MAX_16BIT) { + word16 slen = (word16)CYASSL_MAX_16BIT; + if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId, + rng->devId) != 0) { + CYASSL_MSG("Cavium RNG failed"); + } + sz -= CYASSL_MAX_16BIT; + offset += CYASSL_MAX_16BIT; + } + if (sz) { + word16 slen = (word16)sz; + if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId, + rng->devId) != 0) { + CYASSL_MSG("Cavium RNG failed"); + } + } +} + +#endif /* HAVE_CAVIUM */ + +#endif /* NO_RC4 */ + + +#if defined(USE_WINDOWS_API) + + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return WINCRYPT_E; + + if (!CryptGenRandom(os->handle, sz, output)) + return CRYPTGEN_E; + + CryptReleaseContext(os->handle, 0); + + return 0; +} + + +#elif defined(HAVE_RTP_SYS) || defined(EBSNET) + +#include "rtprand.h" /* rtp_rand () */ +#include "rtptime.h" /* rtp_get_system_msec() */ + + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + int i; + rtp_srand(rtp_get_system_msec()); + + for (i = 0; i < sz; i++ ) { + output[i] = rtp_rand() % 256; + if ( (i % 8) == 7) + rtp_srand(rtp_get_system_msec()); + } + + return 0; +} + + +#elif defined(MICRIUM) + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + NetSecure_InitSeed(output, sz); + #endif + return 0; +} + +#elif defined(MBED) + +/* write a real one !!!, just for testing board */ +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + int i; + for (i = 0; i < sz; i++ ) + output[i] = i; + + return 0; +} + +#elif defined(MICROCHIP_PIC32) + +#ifdef MICROCHIP_MPLAB_HARMONY + #define PIC32_SEED_COUNT _CP0_GET_COUNT +#else + #if !defined(CYASSL_MICROCHIP_PIC32MZ) + #include <peripheral/timer.h> + #endif + #define PIC32_SEED_COUNT ReadCoreTimer +#endif + #ifdef CYASSL_MIC32MZ_RNG + #include "xc.h" + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i ; + byte rnd[8] ; + word32 *rnd32 = (word32 *)rnd ; + word32 size = sz ; + byte* op = output ; + + /* This part has to be replaced with better random seed */ + RNGNUMGEN1 = ReadCoreTimer(); + RNGPOLY1 = ReadCoreTimer(); + RNGPOLY2 = ReadCoreTimer(); + RNGNUMGEN2 = ReadCoreTimer(); +#ifdef DEBUG_CYASSL + printf("GenerateSeed::Seed=%08x, %08x\n", RNGNUMGEN1, RNGNUMGEN2) ; +#endif + RNGCONbits.PLEN = 0x40; + RNGCONbits.PRNGEN = 1; + for(i=0; i<5; i++) { /* wait for RNGNUMGEN ready */ + volatile int x ; + x = RNGNUMGEN1 ; + x = RNGNUMGEN2 ; + } + do { + rnd32[0] = RNGNUMGEN1; + rnd32[1] = RNGNUMGEN2; + + for(i=0; i<8; i++, op++) { + *op = rnd[i] ; + size -- ; + if(size==0)break ; + } + } while(size) ; + return 0; + } + #else /* CYASSL_MIC32MZ_RNG */ + /* uses the core timer, in nanoseconds to seed srand */ + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + srand(PIC32_SEED_COUNT() * 25); + + for (i = 0; i < sz; i++ ) { + output[i] = rand() % 256; + if ( (i % 8) == 7) + srand(PIC32_SEED_COUNT() * 25); + } + return 0; + } + #endif /* CYASSL_MIC32MZ_RNG */ + +#elif defined(FREESCALE_MQX) + + #ifdef FREESCALE_K70_RNGA + /* + * Generates a RNG seed using the Random Number Generator Accelerator + * on the Kinetis K70. Documentation located in Chapter 37 of + * K70 Sub-Family Reference Manual (see Note 3 in the README for link). + */ + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + + /* turn on RNGA module */ + SIM_SCGC3 |= SIM_SCGC3_RNGA_MASK; + + /* set SLP bit to 0 - "RNGA is not in sleep mode" */ + RNG_CR &= ~RNG_CR_SLP_MASK; + + /* set HA bit to 1 - "security violations masked" */ + RNG_CR |= RNG_CR_HA_MASK; + + /* set GO bit to 1 - "output register loaded with data" */ + RNG_CR |= RNG_CR_GO_MASK; + + for (i = 0; i < sz; i++) { + + /* wait for RNG FIFO to be full */ + while((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0) {} + + /* get value */ + output[i] = RNG_OR; + } + + return 0; + } + + #elif defined(FREESCALE_K53_RNGB) + /* + * Generates a RNG seed using the Random Number Generator (RNGB) + * on the Kinetis K53. Documentation located in Chapter 33 of + * K53 Sub-Family Reference Manual (see note in the README for link). + */ + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + + /* turn on RNGB module */ + SIM_SCGC3 |= SIM_SCGC3_RNGB_MASK; + + /* reset RNGB */ + RNG_CMD |= RNG_CMD_SR_MASK; + + /* FIFO generate interrupt, return all zeros on underflow, + * set auto reseed */ + RNG_CR |= (RNG_CR_FUFMOD_MASK | RNG_CR_AR_MASK); + + /* gen seed, clear interrupts, clear errors */ + RNG_CMD |= (RNG_CMD_GS_MASK | RNG_CMD_CI_MASK | RNG_CMD_CE_MASK); + + /* wait for seeding to complete */ + while ((RNG_SR & RNG_SR_SDN_MASK) == 0) {} + + for (i = 0; i < sz; i++) { + + /* wait for a word to be available from FIFO */ + while((RNG_SR & RNG_SR_FIFO_LVL_MASK) == 0) {} + + /* get value */ + output[i] = RNG_OUT; + } + + return 0; + } + + #else + #warning "write a real random seed!!!!, just for testing now" + + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + for (i = 0; i < sz; i++ ) + output[i] = i; + + return 0; + } + #endif /* FREESCALE_K70_RNGA */ + +#elif defined(CYASSL_SAFERTOS) || defined(CYASSL_LEANPSK) \ + || defined(CYASSL_IAR_ARM) + +#warning "write a real random seed!!!!, just for testing now" + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + word32 i; + for (i = 0; i < sz; i++ ) + output[i] = i; + + (void)os; + + return 0; +} + +#elif defined(STM32F2_RNG) + #undef RNG + #include "stm32f2xx_rng.h" + #include "stm32f2xx_rcc.h" + /* + * Generate a RNG seed using the hardware random number generator + * on the STM32F2. Documentation located in STM32F2xx Standard Peripheral + * Library document (See note in README). + */ + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + + /* enable RNG clock source */ + RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE); + + /* enable RNG peripheral */ + RNG_Cmd(ENABLE); + + for (i = 0; i < sz; i++) { + /* wait until RNG number is ready */ + while(RNG_GetFlagStatus(RNG_FLAG_DRDY)== RESET) { } + + /* get value */ + output[i] = RNG_GetRandomNumber(); + } + + return 0; + } +#elif defined(CYASSL_LPC43xx) || defined(CYASSL_STM32F2xx) + + #warning "write a real random seed!!!!, just for testing now" + + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + + for (i = 0; i < sz; i++ ) + output[i] = i; + + return 0; + } + +#elif defined(CUSTOM_RAND_GENERATE) + + /* Implement your own random generation function + * word32 rand_gen(void); + * #define CUSTOM_RAND_GENERATE rand_gen */ + + int GenerateSeed(OS_Seed* os, byte* output, word32 sz) + { + int i; + + for (i = 0; i < sz; i++ ) + output[i] = CUSTOM_RAND_GENERATE(); + + return 0; + } + +#elif defined(NO_DEV_RANDOM) + +//#error "you need to write an os specific GenerateSeed() here" + +#warning "PRNG is not well-implemented" +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + srand(time()); + int i; + + for (i = 0; i < sz; i++ ) { + output[i] = rand() % 256; + if ( (i % 8) == 7) + rand(time()); + } + return 0; +} + + +#else /* !USE_WINDOWS_API && !HAVE_RPT_SYS && !MICRIUM && !NO_DEV_RANDOM */ + + +/* may block */ +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + int ret = 0; + + os->fd = open("/dev/urandom",O_RDONLY); + if (os->fd == -1) { + /* may still have /dev/random */ + os->fd = open("/dev/random",O_RDONLY); + if (os->fd == -1) + return OPEN_RAN_E; + } + + while (sz) { + int len = (int)read(os->fd, output, sz); + if (len == -1) { + ret = READ_RAN_E; + break; + } + + sz -= len; + output += len; + + if (sz) { +#ifdef BLOCKING + sleep(0); /* context switch */ +#else + ret = RAN_BLOCK_E; + break; +#endif + } + } + close(os->fd); + + return ret; +} + +#endif /* USE_WINDOWS_API */ + +
diff -r 64d4f7cb83d5 -r e505054279ed cyassl/ctaocrypt/settings.h --- a/cyassl/ctaocrypt/settings.h Wed Dec 03 05:24:18 2014 +0000 +++ b/cyassl/ctaocrypt/settings.h Wed Jan 14 22:07:14 2015 +0000 @@ -137,21 +137,28 @@ #endif #endif -#ifdef MBED - //#define SINGLE_THREADED +#ifdef MBED + //Required + #define USER_TIME //Platform specific time() functions #define CYASSL_USER_IO - #define NO_FILESYSTEM - //#define NO_CERTS - //#define USE_CERT_BUFFERS_1024 - #define NO_WRITEV - #define NO_DEV_RANDOM - #define NO_SHA512 + #define NO_WRITEV //Some sort of semantic debugging or something + + //Mbed-Platform-Specific + //#define CYASSL_CMSIS_RTOS //RTOS + #define NO_DEV_RANDOM //A random seed generator that should be implemented for full security + #define SINGLE_THREADED //Single thread + #define NO_FILESYSTEM //Filesystem + + //Optional + #define NO_CERT + #define USE_CERT_BUFFERS_1024 + #define NO_CYASSL_SERVER + #define NO_SHA512 //Type of cipher #define NO_DH - #define NO_DSA - #define NO_HC128 - #define HAVE_ECC + #define NO_DSA //Type of encryption format + #define NO_HC128 //Type of cipher/encryption suite + #define HAVE_ECC //Elliptic Cipher Cryptic #define NO_SESSION_CACHE - #define CYASSL_CMSIS_RTOS #define IGNORE_KEY_EXTENSIONS #define DEBUG_CYASSL #endif
diff -r 64d4f7cb83d5 -r e505054279ed src/internal.c --- a/src/internal.c Wed Dec 03 05:24:18 2014 +0000 +++ b/src/internal.c Wed Jan 14 22:07:14 2015 +0000 @@ -1,11301 +1,11301 @@ -/* internal.c - * - * Copyright (C) 2006-2014 wolfSSL Inc. - * - * This file is part of CyaSSL. - * - * CyaSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * CyaSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <cyassl/ctaocrypt/settings.h> - -#include <cyassl/internal.h> -#include <cyassl/error-ssl.h> -#include <cyassl/ctaocrypt/asn.h> - -#ifdef HAVE_LIBZ - #include "zlib.h" -#endif - -#ifdef HAVE_NTRU - #include "crypto_ntru.h" -#endif - -#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) - #ifdef FREESCALE_MQX - #include <fio.h> - #else - #include <stdio.h> - #endif -#endif - -#ifdef __sun - #include <sys/filio.h> -#endif - -#ifndef TRUE - #define TRUE 1 -#endif -#ifndef FALSE - #define FALSE 0 -#endif - - -#if defined(OPENSSL_EXTRA) && defined(NO_DH) - #error OPENSSL_EXTRA needs DH, please remove NO_DH -#endif - -#if defined(CYASSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS) - #error \ -CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS -#endif - - -#ifndef NO_CYASSL_CLIENT - static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*, - word32); - static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); - static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*, - word32); - #ifndef NO_CERTS - static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*, - word32); - #endif -#endif - - -#ifndef NO_CYASSL_SERVER - static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32); - static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32*, word32); - #if !defined(NO_RSA) || defined(HAVE_ECC) - static int DoCertificateVerify(CYASSL* ssl, byte*, word32*, word32); - #endif -#endif - - -#ifdef CYASSL_DTLS - static INLINE int DtlsCheckWindow(DtlsState* state); - static INLINE int DtlsUpdateWindow(DtlsState* state); -#endif - - -typedef enum { - doProcessInit = 0, -#ifndef NO_CYASSL_SERVER - runProcessOldClientHello, -#endif - getRecordLayerHeader, - getData, - runProcessingOneMessage -} processReply; - -#ifndef NO_OLD_TLS -static int SSL_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz, - int content, int verify); - -#endif - -#ifndef NO_CERTS -static int BuildCertHashes(CYASSL* ssl, Hashes* hashes); -#endif - -static void PickHashSigAlgo(CYASSL* ssl, - const byte* hashSigAlgo, word32 hashSigAlgoSz); - -#ifndef min - - static INLINE word32 min(word32 a, word32 b) - { - return a > b ? b : a; - } - -#endif /* min */ - - -int IsTLS(const CYASSL* ssl) -{ - if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR) - return 1; - - return 0; -} - - -int IsAtLeastTLSv1_2(const CYASSL* ssl) -{ - if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR) - return 1; - if (ssl->version.major == DTLS_MAJOR && ssl->version.minor <= DTLSv1_2_MINOR) - return 1; - - return 0; -} - - -#ifdef HAVE_NTRU - -static byte GetEntropy(ENTROPY_CMD cmd, byte* out) -{ - /* TODO: add locking? */ - static RNG rng; - - if (cmd == INIT) - return (InitRng(&rng) == 0) ? 1 : 0; - - if (out == NULL) - return 0; - - if (cmd == GET_BYTE_OF_ENTROPY) - return (RNG_GenerateBlock(&rng, out, 1) == 0) ? 1 : 0; - - if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) { - *out = 1; - return 1; - } - - return 0; -} - -#endif /* HAVE_NTRU */ - -/* used by ssl.c too */ -void c32to24(word32 in, word24 out) -{ - out[0] = (in >> 16) & 0xff; - out[1] = (in >> 8) & 0xff; - out[2] = in & 0xff; -} - - -#ifdef CYASSL_DTLS - -static INLINE void c32to48(word32 in, byte out[6]) -{ - out[0] = 0; - out[1] = 0; - out[2] = (in >> 24) & 0xff; - out[3] = (in >> 16) & 0xff; - out[4] = (in >> 8) & 0xff; - out[5] = in & 0xff; -} - -#endif /* CYASSL_DTLS */ - - -/* convert 16 bit integer to opaque */ -static INLINE void c16toa(word16 u16, byte* c) -{ - c[0] = (u16 >> 8) & 0xff; - c[1] = u16 & 0xff; -} - - -/* convert 32 bit integer to opaque */ -static INLINE void c32toa(word32 u32, byte* c) -{ - c[0] = (u32 >> 24) & 0xff; - c[1] = (u32 >> 16) & 0xff; - c[2] = (u32 >> 8) & 0xff; - c[3] = u32 & 0xff; -} - - -/* convert a 24 bit integer into a 32 bit one */ -static INLINE void c24to32(const word24 u24, word32* u32) -{ - *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; -} - - -/* convert opaque to 16 bit integer */ -static INLINE void ato16(const byte* c, word16* u16) -{ - *u16 = (word16) ((c[0] << 8) | (c[1])); -} - - -#ifdef CYASSL_DTLS - -/* convert opaque to 32 bit integer */ -static INLINE void ato32(const byte* c, word32* u32) -{ - *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; -} - -#endif /* CYASSL_DTLS */ - - -#ifdef HAVE_LIBZ - - /* alloc user allocs to work with zlib */ - static void* myAlloc(void* opaque, unsigned int item, unsigned int size) - { - (void)opaque; - return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ); - } - - - static void myFree(void* opaque, void* memory) - { - (void)opaque; - XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ); - } - - - /* init zlib comp/decomp streams, 0 on success */ - static int InitStreams(CYASSL* ssl) - { - ssl->c_stream.zalloc = (alloc_func)myAlloc; - ssl->c_stream.zfree = (free_func)myFree; - ssl->c_stream.opaque = (voidpf)ssl->heap; - - if (deflateInit(&ssl->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) - return ZLIB_INIT_ERROR; - - ssl->didStreamInit = 1; - - ssl->d_stream.zalloc = (alloc_func)myAlloc; - ssl->d_stream.zfree = (free_func)myFree; - ssl->d_stream.opaque = (voidpf)ssl->heap; - - if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR; - - return 0; - } - - - static void FreeStreams(CYASSL* ssl) - { - if (ssl->didStreamInit) { - deflateEnd(&ssl->c_stream); - inflateEnd(&ssl->d_stream); - } - } - - - /* compress in to out, return out size or error */ - static int myCompress(CYASSL* ssl, byte* in, int inSz, byte* out, int outSz) - { - int err; - int currTotal = (int)ssl->c_stream.total_out; - - ssl->c_stream.next_in = in; - ssl->c_stream.avail_in = inSz; - ssl->c_stream.next_out = out; - ssl->c_stream.avail_out = outSz; - - err = deflate(&ssl->c_stream, Z_SYNC_FLUSH); - if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR; - - return (int)ssl->c_stream.total_out - currTotal; - } - - - /* decompress in to out, returnn out size or error */ - static int myDeCompress(CYASSL* ssl, byte* in,int inSz, byte* out,int outSz) - { - int err; - int currTotal = (int)ssl->d_stream.total_out; - - ssl->d_stream.next_in = in; - ssl->d_stream.avail_in = inSz; - ssl->d_stream.next_out = out; - ssl->d_stream.avail_out = outSz; - - err = inflate(&ssl->d_stream, Z_SYNC_FLUSH); - if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR; - - return (int)ssl->d_stream.total_out - currTotal; - } - -#endif /* HAVE_LIBZ */ - - -void InitSSL_Method(CYASSL_METHOD* method, ProtocolVersion pv) -{ - method->version = pv; - method->side = CYASSL_CLIENT_END; - method->downgrade = 0; -} - - -/* Initialze SSL context, return 0 on success */ -int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method) -{ - ctx->method = method; - ctx->refCount = 1; /* so either CTX_free or SSL_free can release */ -#ifndef NO_CERTS - ctx->certificate.buffer = 0; - ctx->certChain.buffer = 0; - ctx->privateKey.buffer = 0; - ctx->serverDH_P.buffer = 0; - ctx->serverDH_G.buffer = 0; -#endif - ctx->haveDH = 0; - ctx->haveNTRU = 0; /* start off */ - ctx->haveECDSAsig = 0; /* start off */ - ctx->haveStaticECC = 0; /* start off */ - ctx->heap = ctx; /* defaults to self */ -#ifndef NO_PSK - ctx->havePSK = 0; - ctx->server_hint[0] = 0; - ctx->client_psk_cb = 0; - ctx->server_psk_cb = 0; -#endif /* NO_PSK */ -#ifdef HAVE_ECC - ctx->eccTempKeySz = ECDHE_SIZE; -#endif - -#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) - ctx->passwd_cb = 0; - ctx->userdata = 0; -#endif /* OPENSSL_EXTRA */ - - ctx->timeout = DEFAULT_TIMEOUT; - -#ifndef CYASSL_USER_IO - ctx->CBIORecv = EmbedReceive; - ctx->CBIOSend = EmbedSend; - #ifdef CYASSL_DTLS - if (method->version.major == DTLS_MAJOR) { - ctx->CBIORecv = EmbedReceiveFrom; - ctx->CBIOSend = EmbedSendTo; - ctx->CBIOCookie = EmbedGenerateCookie; - } - #endif -#else - /* user will set */ - ctx->CBIORecv = NULL; - ctx->CBIOSend = NULL; - #ifdef CYASSL_DTLS - ctx->CBIOCookie = NULL; - #endif -#endif /* CYASSL_USER_IO */ -#ifdef HAVE_NETX - ctx->CBIORecv = NetX_Receive; - ctx->CBIOSend = NetX_Send; -#endif - ctx->partialWrite = 0; - ctx->verifyCallback = 0; - -#ifndef NO_CERTS - ctx->cm = CyaSSL_CertManagerNew(); -#endif -#ifdef HAVE_NTRU - if (method->side == CYASSL_CLIENT_END) - ctx->haveNTRU = 1; /* always on cliet side */ - /* server can turn on by loading key */ -#endif -#ifdef HAVE_ECC - if (method->side == CYASSL_CLIENT_END) { - ctx->haveECDSAsig = 1; /* always on cliet side */ - ctx->haveStaticECC = 1; /* server can turn on by loading key */ - } -#endif - ctx->suites.setSuites = 0; /* user hasn't set yet */ - /* remove DH later if server didn't set, add psk later */ - InitSuites(&ctx->suites, method->version, TRUE, FALSE, TRUE, ctx->haveNTRU, - ctx->haveECDSAsig, ctx->haveStaticECC, method->side); - ctx->verifyPeer = 0; - ctx->verifyNone = 0; - ctx->failNoCert = 0; - ctx->sessionCacheOff = 0; /* initially on */ - ctx->sessionCacheFlushOff = 0; /* initially on */ - ctx->sendVerify = 0; - ctx->quietShutdown = 0; - ctx->groupMessages = 0; -#ifdef HAVE_CAVIUM - ctx->devId = NO_CAVIUM_DEVICE; -#endif -#ifdef HAVE_TLS_EXTENSIONS - ctx->extensions = NULL; -#endif -#ifdef ATOMIC_USER - ctx->MacEncryptCb = NULL; - ctx->DecryptVerifyCb = NULL; -#endif -#ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ctx->EccSignCb = NULL; - ctx->EccVerifyCb = NULL; - #endif /* HAVE_ECC */ - #ifndef NO_RSA - ctx->RsaSignCb = NULL; - ctx->RsaVerifyCb = NULL; - ctx->RsaEncCb = NULL; - ctx->RsaDecCb = NULL; - #endif /* NO_RSA */ -#endif /* HAVE_PK_CALLBACKS */ - - if (InitMutex(&ctx->countMutex) < 0) { - CYASSL_MSG("Mutex error on CTX init"); - return BAD_MUTEX_E; - } -#ifndef NO_CERTS - if (ctx->cm == NULL) { - CYASSL_MSG("Bad Cert Manager New"); - return BAD_CERT_MANAGER_ERROR; - } -#endif - return 0; -} - - -/* In case contexts are held in array and don't want to free actual ctx */ -void SSL_CtxResourceFree(CYASSL_CTX* ctx) -{ - XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); - -#ifndef NO_CERTS - XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH); - XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH); - XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY); - XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT); - XFREE(ctx->certChain.buffer, ctx->heap, DYNAMIC_TYPE_CERT); - CyaSSL_CertManagerFree(ctx->cm); -#endif -#ifdef HAVE_TLS_EXTENSIONS - TLSX_FreeAll(ctx->extensions); -#endif -} - - -void FreeSSL_Ctx(CYASSL_CTX* ctx) -{ - int doFree = 0; - - if (LockMutex(&ctx->countMutex) != 0) { - CYASSL_MSG("Couldn't lock count mutex"); - return; - } - ctx->refCount--; - if (ctx->refCount == 0) - doFree = 1; - UnLockMutex(&ctx->countMutex); - - if (doFree) { - CYASSL_MSG("CTX ref count down to 0, doing full free"); - SSL_CtxResourceFree(ctx); - FreeMutex(&ctx->countMutex); - XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX); - } - else { - (void)ctx; - CYASSL_MSG("CTX ref count not 0 yet, no free"); - } -} - - -/* Set cipher pointers to null */ -void InitCiphers(CYASSL* ssl) -{ -#ifdef BUILD_ARC4 - ssl->encrypt.arc4 = NULL; - ssl->decrypt.arc4 = NULL; -#endif -#ifdef BUILD_DES3 - ssl->encrypt.des3 = NULL; - ssl->decrypt.des3 = NULL; -#endif -#ifdef BUILD_AES - ssl->encrypt.aes = NULL; - ssl->decrypt.aes = NULL; -#endif -#ifdef HAVE_CAMELLIA - ssl->encrypt.cam = NULL; - ssl->decrypt.cam = NULL; -#endif -#ifdef HAVE_HC128 - ssl->encrypt.hc128 = NULL; - ssl->decrypt.hc128 = NULL; -#endif -#ifdef BUILD_RABBIT - ssl->encrypt.rabbit = NULL; - ssl->decrypt.rabbit = NULL; -#endif - ssl->encrypt.setup = 0; - ssl->decrypt.setup = 0; -} - - -/* Free ciphers */ -void FreeCiphers(CYASSL* ssl) -{ - (void)ssl; -#ifdef BUILD_ARC4 - #ifdef HAVE_CAVIUM - if (ssl->devId != NO_CAVIUM_DEVICE) { - Arc4FreeCavium(ssl->encrypt.arc4); - Arc4FreeCavium(ssl->decrypt.arc4); - } - #endif - XFREE(ssl->encrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->decrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); -#endif -#ifdef BUILD_DES3 - #ifdef HAVE_CAVIUM - if (ssl->devId != NO_CAVIUM_DEVICE) { - Des3_FreeCavium(ssl->encrypt.des3); - Des3_FreeCavium(ssl->decrypt.des3); - } - #endif - XFREE(ssl->encrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->decrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); -#endif -#ifdef BUILD_AES - #ifdef HAVE_CAVIUM - if (ssl->devId != NO_CAVIUM_DEVICE) { - AesFreeCavium(ssl->encrypt.aes); - AesFreeCavium(ssl->decrypt.aes); - } - #endif - XFREE(ssl->encrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->decrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); -#endif -#ifdef HAVE_CAMELLIA - XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); -#endif -#ifdef HAVE_HC128 - XFREE(ssl->encrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->decrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER); -#endif -#ifdef BUILD_RABBIT - XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); -#endif -} - - -void InitCipherSpecs(CipherSpecs* cs) -{ - cs->bulk_cipher_algorithm = INVALID_BYTE; - cs->cipher_type = INVALID_BYTE; - cs->mac_algorithm = INVALID_BYTE; - cs->kea = INVALID_BYTE; - cs->sig_algo = INVALID_BYTE; - - cs->hash_size = 0; - cs->static_ecdh = 0; - cs->key_size = 0; - cs->iv_size = 0; - cs->block_size = 0; -} - - -void InitSuites(Suites* suites, ProtocolVersion pv, byte haveRSA, byte havePSK, - byte haveDH, byte haveNTRU, byte haveECDSAsig, - byte haveStaticECC, int side) -{ - word16 idx = 0; - int tls = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR; - int tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR; - int haveRSAsig = 1; - - (void)tls; /* shut up compiler */ - (void)tls1_2; - (void)haveDH; - (void)havePSK; - (void)haveNTRU; - (void)haveStaticECC; - - if (suites == NULL) { - CYASSL_MSG("InitSuites pointer error"); - return; - } - - if (suites->setSuites) - return; /* trust user settings, don't override */ - - if (side == CYASSL_SERVER_END && haveStaticECC) { - haveRSA = 0; /* can't do RSA with ECDSA key */ - (void)haveRSA; /* some builds won't read */ - } - - if (side == CYASSL_SERVER_END && haveECDSAsig) { - haveRSAsig = 0; /* can't have RSA sig if signed by ECDSA */ - (void)haveRSAsig; /* non ecc builds won't read */ - } - -#ifdef CYASSL_DTLS - if (pv.major == DTLS_MAJOR) { - tls = 1; - tls1_2 = pv.minor <= DTLSv1_2_MINOR; - } -#endif - -#ifdef HAVE_RENEGOTIATION_INDICATION - if (side == CYASSL_CLIENT_END) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - if (tls1_2 && haveRSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - if (tls1_2 && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - if (tls1_2 && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - if (tls1_2 && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - if (tls1_2 && haveRSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - if (tls1_2 && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - if (tls1_2 && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - if (tls1_2 && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - if (tls1_2 && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - if (tls && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - if (tls1_2 && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - if (tls && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - if (tls1_2 && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - if (tls && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - if (tls1_2 && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - if (tls && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - if (tls && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA - if (tls && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - if (tls && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - if (tls && haveECDSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - if (tls1_2 && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - if (tls && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - if (tls1_2 && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - if (tls && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA - if (tls && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA - if (tls && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - if (tls && haveRSAsig && haveStaticECC) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - if (tls1_2 && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 - if (tls1_2 && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; - } -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 - if (tls1_2 && haveECDSAsig) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_RSA_WITH_AES_128_CCM_8; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_RSA_WITH_AES_256_CCM_8; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - if (tls1_2 && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - if (tls1_2 && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - if (tls1_2 && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA - if (tls && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA - if (tls && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 - if (tls1_2 && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA256; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA - if (tls && havePSK) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 - if (tls && havePSK) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA - if (tls && havePSK) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 - if (tls && havePSK) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM_8; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 - if (tls && havePSK) { - suites->suites[idx++] = ECC_BYTE; - suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM_8; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 - if (tls && havePSK) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA256; - } -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA - if (tls && havePSK) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA; - } -#endif - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA - if (haveRSA ) { - suites->suites[idx++] = 0; - suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 - if (haveRSA ) { - suites->suites[idx++] = 0; - suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5; - } -#endif - -#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA - if (haveRSA ) { - suites->suites[idx++] = 0; - suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_HC_128_B2B256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_B2B256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_B2B256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - if (tls && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_DHE_WITH_RSA_CAMELLIA_256_CBC_SHA - if (tls && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - if (tls && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - if (tls && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256; - } -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - if (tls && haveDH && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256; - } -#endif - - suites->suiteSz = idx; - - { - idx = 0; - - if (haveECDSAsig) { - #ifdef CYASSL_SHA384 - suites->hashSigAlgo[idx++] = sha384_mac; - suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - #ifndef NO_SHA256 - suites->hashSigAlgo[idx++] = sha256_mac; - suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - #ifndef NO_SHA - suites->hashSigAlgo[idx++] = sha_mac; - suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - } - - if (haveRSAsig) { - #ifdef CYASSL_SHA384 - suites->hashSigAlgo[idx++] = sha384_mac; - suites->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - #ifndef NO_SHA256 - suites->hashSigAlgo[idx++] = sha256_mac; - suites->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - #ifndef NO_SHA - suites->hashSigAlgo[idx++] = sha_mac; - suites->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - } - - suites->hashSigAlgoSz = idx; - } -} - - -#ifndef NO_CERTS - - -void InitX509Name(CYASSL_X509_NAME* name, int dynamicFlag) -{ - (void)dynamicFlag; - - if (name != NULL) { - name->name = name->staticName; - name->dynamicName = 0; -#ifdef OPENSSL_EXTRA - XMEMSET(&name->fullName, 0, sizeof(DecodedName)); -#endif /* OPENSSL_EXTRA */ - } -} - - -void FreeX509Name(CYASSL_X509_NAME* name) -{ - if (name != NULL) { - if (name->dynamicName) - XFREE(name->name, NULL, DYNAMIC_TYPE_SUBJECT_CN); -#ifdef OPENSSL_EXTRA - if (name->fullName.fullName != NULL) - XFREE(name->fullName.fullName, NULL, DYNAMIC_TYPE_X509); -#endif /* OPENSSL_EXTRA */ - } -} - - -/* Initialize CyaSSL X509 type */ -void InitX509(CYASSL_X509* x509, int dynamicFlag) -{ - InitX509Name(&x509->issuer, 0); - InitX509Name(&x509->subject, 0); - x509->version = 0; - x509->pubKey.buffer = NULL; - x509->sig.buffer = NULL; - x509->derCert.buffer = NULL; - x509->altNames = NULL; - x509->altNamesNext = NULL; - x509->dynamicMemory = (byte)dynamicFlag; - x509->isCa = 0; -#ifdef HAVE_ECC - x509->pkCurveOID = 0; -#endif /* HAVE_ECC */ -#ifdef OPENSSL_EXTRA - x509->pathLength = 0; - x509->basicConstSet = 0; - x509->basicConstCrit = 0; - x509->basicConstPlSet = 0; - x509->subjAltNameSet = 0; - x509->subjAltNameCrit = 0; - x509->authKeyIdSet = 0; - x509->authKeyIdCrit = 0; - x509->authKeyId = NULL; - x509->authKeyIdSz = 0; - x509->subjKeyIdSet = 0; - x509->subjKeyIdCrit = 0; - x509->subjKeyId = NULL; - x509->subjKeyIdSz = 0; - x509->keyUsageSet = 0; - x509->keyUsageCrit = 0; - x509->keyUsage = 0; - #ifdef CYASSL_SEP - x509->certPolicySet = 0; - x509->certPolicyCrit = 0; - #endif /* CYASSL_SEP */ -#endif /* OPENSSL_EXTRA */ -} - - -/* Free CyaSSL X509 type */ -void FreeX509(CYASSL_X509* x509) -{ - if (x509 == NULL) - return; - - FreeX509Name(&x509->issuer); - FreeX509Name(&x509->subject); - if (x509->pubKey.buffer) - XFREE(x509->pubKey.buffer, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_SUBJECT_CN); - XFREE(x509->sig.buffer, NULL, DYNAMIC_TYPE_SIGNATURE); - #ifdef OPENSSL_EXTRA - XFREE(x509->authKeyId, NULL, 0); - XFREE(x509->subjKeyId, NULL, 0); - #endif /* OPENSSL_EXTRA */ - if (x509->altNames) - FreeAltNames(x509->altNames, NULL); - if (x509->dynamicMemory) - XFREE(x509, NULL, DYNAMIC_TYPE_X509); -} - -#endif /* NO_CERTS */ - - -/* init everything to 0, NULL, default values before calling anything that may - fail so that desctructor has a "good" state to cleanup */ -int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) -{ - int ret; - byte haveRSA = 0; - byte havePSK = 0; - - ssl->ctx = ctx; /* only for passing to calls, options could change */ - ssl->version = ctx->method->version; - ssl->suites = NULL; - -#ifdef HAVE_LIBZ - ssl->didStreamInit = 0; -#endif -#ifndef NO_RSA - haveRSA = 1; -#endif - -#ifndef NO_CERTS - ssl->buffers.certificate.buffer = 0; - ssl->buffers.key.buffer = 0; - ssl->buffers.certChain.buffer = 0; -#endif - ssl->buffers.inputBuffer.length = 0; - ssl->buffers.inputBuffer.idx = 0; - ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; - ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; - ssl->buffers.inputBuffer.dynamicFlag = 0; - ssl->buffers.inputBuffer.offset = 0; - ssl->buffers.outputBuffer.length = 0; - ssl->buffers.outputBuffer.idx = 0; - ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; - ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; - ssl->buffers.outputBuffer.dynamicFlag = 0; - ssl->buffers.outputBuffer.offset = 0; - ssl->buffers.domainName.buffer = 0; -#ifndef NO_CERTS - ssl->buffers.serverDH_P.buffer = 0; - ssl->buffers.serverDH_G.buffer = 0; - ssl->buffers.serverDH_Pub.buffer = 0; - ssl->buffers.serverDH_Priv.buffer = 0; -#endif - ssl->buffers.clearOutputBuffer.buffer = 0; - ssl->buffers.clearOutputBuffer.length = 0; - ssl->buffers.prevSent = 0; - ssl->buffers.plainSz = 0; -#ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ssl->buffers.peerEccDsaKey.buffer = 0; - ssl->buffers.peerEccDsaKey.length = 0; - #endif /* HAVE_ECC */ - #ifndef NO_RSA - ssl->buffers.peerRsaKey.buffer = 0; - ssl->buffers.peerRsaKey.length = 0; - #endif /* NO_RSA */ -#endif /* HAVE_PK_CALLBACKS */ - -#ifdef KEEP_PEER_CERT - InitX509(&ssl->peerCert, 0); -#endif - -#ifdef HAVE_ECC - ssl->eccTempKeySz = ctx->eccTempKeySz; - ssl->pkCurveOID = ctx->pkCurveOID; - ssl->peerEccKeyPresent = 0; - ssl->peerEccDsaKeyPresent = 0; - ssl->eccDsaKeyPresent = 0; - ssl->eccTempKeyPresent = 0; - ssl->peerEccKey = NULL; - ssl->peerEccDsaKey = NULL; - ssl->eccDsaKey = NULL; - ssl->eccTempKey = NULL; -#endif - - ssl->timeout = ctx->timeout; - ssl->rfd = -1; /* set to invalid descriptor */ - ssl->wfd = -1; - ssl->rflags = 0; /* no user flags yet */ - ssl->wflags = 0; /* no user flags yet */ - ssl->biord = 0; - ssl->biowr = 0; - - ssl->IOCB_ReadCtx = &ssl->rfd; /* prevent invalid pointer access if not */ - ssl->IOCB_WriteCtx = &ssl->wfd; /* correctly set */ -#ifdef HAVE_NETX - ssl->nxCtx.nxSocket = NULL; - ssl->nxCtx.nxPacket = NULL; - ssl->nxCtx.nxOffset = 0; - ssl->nxCtx.nxWait = 0; - ssl->IOCB_ReadCtx = &ssl->nxCtx; /* default NetX IO ctx, same for read */ - ssl->IOCB_WriteCtx = &ssl->nxCtx; /* and write */ -#endif -#ifdef CYASSL_DTLS - ssl->IOCB_CookieCtx = NULL; /* we don't use for default cb */ - ssl->dtls_expected_rx = MAX_MTU; - ssl->keys.dtls_state.window = 0; - ssl->keys.dtls_state.nextEpoch = 0; - ssl->keys.dtls_state.nextSeq = 0; -#endif - -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - InitMd5(&ssl->hashMd5); -#endif -#ifndef NO_SHA - ret = InitSha(&ssl->hashSha); - if (ret != 0) { - return ret; - } -#endif -#endif -#ifndef NO_SHA256 - ret = InitSha256(&ssl->hashSha256); - if (ret != 0) { - return ret; - } -#endif -#ifdef CYASSL_SHA384 - ret = InitSha384(&ssl->hashSha384); - if (ret != 0) { - return ret; - } -#endif -#ifndef NO_RSA - ssl->peerRsaKey = NULL; - ssl->peerRsaKeyPresent = 0; -#endif - ssl->verifyCallback = ctx->verifyCallback; - ssl->verifyCbCtx = NULL; - ssl->options.side = ctx->method->side; - ssl->options.downgrade = ctx->method->downgrade; - ssl->error = 0; - ssl->options.connReset = 0; - ssl->options.isClosed = 0; - ssl->options.closeNotify = 0; - ssl->options.sentNotify = 0; - ssl->options.usingCompression = 0; - if (ssl->options.side == CYASSL_SERVER_END) - ssl->options.haveDH = ctx->haveDH; - else - ssl->options.haveDH = 0; - ssl->options.haveNTRU = ctx->haveNTRU; - ssl->options.haveECDSAsig = ctx->haveECDSAsig; - ssl->options.haveStaticECC = ctx->haveStaticECC; - ssl->options.havePeerCert = 0; - ssl->options.havePeerVerify = 0; - ssl->options.usingPSK_cipher = 0; - ssl->options.sendAlertState = 0; -#ifndef NO_PSK - havePSK = ctx->havePSK; - ssl->options.havePSK = ctx->havePSK; - ssl->options.client_psk_cb = ctx->client_psk_cb; - ssl->options.server_psk_cb = ctx->server_psk_cb; -#endif /* NO_PSK */ - - ssl->options.serverState = NULL_STATE; - ssl->options.clientState = NULL_STATE; - ssl->options.connectState = CONNECT_BEGIN; - ssl->options.acceptState = ACCEPT_BEGIN; - ssl->options.handShakeState = NULL_STATE; - ssl->options.processReply = doProcessInit; - -#ifdef CYASSL_DTLS - ssl->keys.dtls_sequence_number = 0; - ssl->keys.dtls_state.curSeq = 0; - ssl->keys.dtls_state.nextSeq = 0; - ssl->keys.dtls_handshake_number = 0; - ssl->keys.dtls_expected_peer_handshake_number = 0; - ssl->keys.dtls_epoch = 0; - ssl->keys.dtls_state.curEpoch = 0; - ssl->keys.dtls_state.nextEpoch = 0; - ssl->dtls_timeout_init = DTLS_TIMEOUT_INIT; - ssl->dtls_timeout_max = DTLS_TIMEOUT_MAX; - ssl->dtls_timeout = ssl->dtls_timeout_init; - ssl->dtls_pool = NULL; - ssl->dtls_msg_list = NULL; -#endif - ssl->keys.encryptSz = 0; - ssl->keys.padSz = 0; - ssl->keys.encryptionOn = 0; /* initially off */ - ssl->keys.decryptedCur = 0; /* initially off */ - ssl->options.sessionCacheOff = ctx->sessionCacheOff; - ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff; - - ssl->options.verifyPeer = ctx->verifyPeer; - ssl->options.verifyNone = ctx->verifyNone; - ssl->options.failNoCert = ctx->failNoCert; - ssl->options.sendVerify = ctx->sendVerify; - - ssl->options.resuming = 0; - ssl->options.haveSessionId = 0; - #ifndef NO_OLD_TLS - ssl->hmac = SSL_hmac; /* default to SSLv3 */ - #else - ssl->hmac = TLS_hmac; - #endif - ssl->heap = ctx->heap; /* defaults to self */ - ssl->options.tls = 0; - ssl->options.tls1_1 = 0; - ssl->options.dtls = ssl->version.major == DTLS_MAJOR; - ssl->options.partialWrite = ctx->partialWrite; - ssl->options.quietShutdown = ctx->quietShutdown; - ssl->options.certOnly = 0; - ssl->options.groupMessages = ctx->groupMessages; - ssl->options.usingNonblock = 0; - ssl->options.saveArrays = 0; - -#ifndef NO_CERTS - /* ctx still owns certificate, certChain, key, dh, and cm */ - ssl->buffers.certificate = ctx->certificate; - ssl->buffers.certChain = ctx->certChain; - ssl->buffers.key = ctx->privateKey; - if (ssl->options.side == CYASSL_SERVER_END) { - ssl->buffers.serverDH_P = ctx->serverDH_P; - ssl->buffers.serverDH_G = ctx->serverDH_G; - } -#endif - ssl->buffers.weOwnCert = 0; - ssl->buffers.weOwnKey = 0; - ssl->buffers.weOwnDH = 0; - -#ifdef CYASSL_DTLS - ssl->buffers.dtlsCtx.fd = -1; - ssl->buffers.dtlsCtx.peer.sa = NULL; - ssl->buffers.dtlsCtx.peer.sz = 0; -#endif - -#ifdef KEEP_PEER_CERT - ssl->peerCert.issuer.sz = 0; - ssl->peerCert.subject.sz = 0; -#endif - -#ifdef SESSION_CERTS - ssl->session.chain.count = 0; -#endif - -#ifndef NO_CLIENT_CACHE - ssl->session.idLen = 0; -#endif - - ssl->cipher.ssl = ssl; - -#ifdef FORTRESS - ssl->ex_data[0] = 0; - ssl->ex_data[1] = 0; - ssl->ex_data[2] = 0; -#endif - -#ifdef CYASSL_CALLBACKS - ssl->hsInfoOn = 0; - ssl->toInfoOn = 0; -#endif - -#ifdef HAVE_CAVIUM - ssl->devId = ctx->devId; -#endif - -#ifdef HAVE_TLS_EXTENSIONS - ssl->extensions = NULL; -#ifdef HAVE_MAX_FRAGMENT - ssl->max_fragment = MAX_RECORD_SIZE; -#endif -#ifdef HAVE_TRUNCATED_HMAC - ssl->truncated_hmac = 0; -#endif -#endif - - ssl->rng = NULL; - ssl->arrays = NULL; - - /* default alert state (none) */ - ssl->alert_history.last_rx.code = -1; - ssl->alert_history.last_rx.level = -1; - ssl->alert_history.last_tx.code = -1; - ssl->alert_history.last_tx.level = -1; - - InitCiphers(ssl); - InitCipherSpecs(&ssl->specs); -#ifdef ATOMIC_USER - ssl->MacEncryptCtx = NULL; - ssl->DecryptVerifyCtx = NULL; -#endif -#ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ssl->EccSignCtx = NULL; - ssl->EccVerifyCtx = NULL; - #endif /* HAVE_ECC */ - #ifndef NO_RSA - ssl->RsaSignCtx = NULL; - ssl->RsaVerifyCtx = NULL; - ssl->RsaEncCtx = NULL; - ssl->RsaDecCtx = NULL; - #endif /* NO_RSA */ -#endif /* HAVE_PK_CALLBACKS */ - - /* all done with init, now can return errors, call other stuff */ - - /* increment CTX reference count */ - if (LockMutex(&ctx->countMutex) != 0) { - CYASSL_MSG("Couldn't lock CTX count mutex"); - return BAD_MUTEX_E; - } - ctx->refCount++; - UnLockMutex(&ctx->countMutex); - - /* arrays */ - ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap, - DYNAMIC_TYPE_ARRAYS); - if (ssl->arrays == NULL) { - CYASSL_MSG("Arrays Memory error"); - return MEMORY_E; - } - XMEMSET(ssl->arrays, 0, sizeof(Arrays)); - -#ifndef NO_PSK - ssl->arrays->client_identity[0] = 0; - if (ctx->server_hint[0]) { /* set in CTX */ - XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint, MAX_PSK_ID_LEN); - ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0'; - } - else - ssl->arrays->server_hint[0] = 0; -#endif /* NO_PSK */ - -#ifdef CYASSL_DTLS - ssl->arrays->cookieSz = 0; -#endif - - /* RNG */ - ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG); - if (ssl->rng == NULL) { - CYASSL_MSG("RNG Memory error"); - return MEMORY_E; - } - - if ( (ret = InitRng(ssl->rng)) != 0) { - CYASSL_MSG("RNG Init error"); - return ret; - } - - /* suites */ - ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, - DYNAMIC_TYPE_SUITES); - if (ssl->suites == NULL) { - CYASSL_MSG("Suites Memory error"); - return MEMORY_E; - } - *ssl->suites = ctx->suites; - - /* peer key */ -#ifndef NO_RSA - ssl->peerRsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey), ssl->heap, - DYNAMIC_TYPE_RSA); - if (ssl->peerRsaKey == NULL) { - CYASSL_MSG("PeerRsaKey Memory error"); - return MEMORY_E; - } - ret = InitRsaKey(ssl->peerRsaKey, ctx->heap); - if (ret != 0) return ret; -#endif -#ifndef NO_CERTS - /* make sure server has cert and key unless using PSK */ - if (ssl->options.side == CYASSL_SERVER_END && !havePSK) - if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) { - CYASSL_MSG("Server missing certificate and/or private key"); - return NO_PRIVATE_KEY; - } -#endif -#ifdef HAVE_ECC - ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccKey == NULL) { - CYASSL_MSG("PeerEccKey Memory error"); - return MEMORY_E; - } - ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccDsaKey == NULL) { - CYASSL_MSG("PeerEccDsaKey Memory error"); - return MEMORY_E; - } - ssl->eccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->eccDsaKey == NULL) { - CYASSL_MSG("EccDsaKey Memory error"); - return MEMORY_E; - } - ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->eccTempKey == NULL) { - CYASSL_MSG("EccTempKey Memory error"); - return MEMORY_E; - } - ecc_init(ssl->peerEccKey); - ecc_init(ssl->peerEccDsaKey); - ecc_init(ssl->eccDsaKey); - ecc_init(ssl->eccTempKey); -#endif - - /* make sure server has DH parms, and add PSK if there, add NTRU too */ - if (ssl->options.side == CYASSL_SERVER_END) - InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, - ssl->options.haveDH, ssl->options.haveNTRU, - ssl->options.haveECDSAsig, ssl->options.haveStaticECC, - ssl->options.side); - else - InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, TRUE, - ssl->options.haveNTRU, ssl->options.haveECDSAsig, - ssl->options.haveStaticECC, ssl->options.side); - - return 0; -} - - -/* free use of temporary arrays */ -void FreeArrays(CYASSL* ssl, int keep) -{ - if (ssl->arrays && keep) { - /* keeps session id for user retrieval */ - XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN); - } - XFREE(ssl->arrays, ssl->heap, DYNAMIC_TYPE_ARRAYS); - ssl->arrays = NULL; -} - - -/* In case holding SSL object in array and don't want to free actual ssl */ -void SSL_ResourceFree(CYASSL* ssl) -{ - FreeCiphers(ssl); - FreeArrays(ssl, 0); - XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); - XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); - XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); - -#ifndef NO_CERTS - XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH); - XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH); - /* parameters (p,g) may be owned by ctx */ - if (ssl->buffers.weOwnDH || ssl->options.side == CYASSL_CLIENT_END) { - XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH); - XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH); - } - - /* CYASSL_CTX always owns certChain */ - if (ssl->buffers.weOwnCert) - XFREE(ssl->buffers.certificate.buffer, ssl->heap, DYNAMIC_TYPE_CERT); - if (ssl->buffers.weOwnKey) - XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY); -#endif -#ifndef NO_RSA - if (ssl->peerRsaKey) { - FreeRsaKey(ssl->peerRsaKey); - XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA); - } -#endif - if (ssl->buffers.inputBuffer.dynamicFlag) - ShrinkInputBuffer(ssl, FORCED_FREE); - if (ssl->buffers.outputBuffer.dynamicFlag) - ShrinkOutputBuffer(ssl); -#ifdef CYASSL_DTLS - if (ssl->dtls_pool != NULL) { - DtlsPoolReset(ssl); - XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE); - } - if (ssl->dtls_msg_list != NULL) { - DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap); - ssl->dtls_msg_list = NULL; - } - XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); - ssl->buffers.dtlsCtx.peer.sa = NULL; -#endif -#if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS) - FreeX509(&ssl->peerCert); -#endif -#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) - CyaSSL_BIO_free(ssl->biord); - if (ssl->biord != ssl->biowr) /* in case same as write */ - CyaSSL_BIO_free(ssl->biowr); -#endif -#ifdef HAVE_LIBZ - FreeStreams(ssl); -#endif -#ifdef HAVE_ECC - if (ssl->peerEccKey) { - if (ssl->peerEccKeyPresent) - ecc_free(ssl->peerEccKey); - XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC); - } - if (ssl->peerEccDsaKey) { - if (ssl->peerEccDsaKeyPresent) - ecc_free(ssl->peerEccDsaKey); - XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); - } - if (ssl->eccTempKey) { - if (ssl->eccTempKeyPresent) - ecc_free(ssl->eccTempKey); - XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC); - } - if (ssl->eccDsaKey) { - if (ssl->eccDsaKeyPresent) - ecc_free(ssl->eccDsaKey); - XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); - } -#endif -#ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); - #endif /* HAVE_ECC */ - #ifndef NO_RSA - XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA); - #endif /* NO_RSA */ -#endif /* HAVE_PK_CALLBACKS */ -#ifdef HAVE_TLS_EXTENSIONS - TLSX_FreeAll(ssl->extensions); -#endif -#ifdef HAVE_NETX - if (ssl->nxCtx.nxPacket) - nx_packet_release(ssl->nxCtx.nxPacket); -#endif -} - - -/* Free any handshake resources no longer needed */ -void FreeHandshakeResources(CYASSL* ssl) -{ - /* input buffer */ - if (ssl->buffers.inputBuffer.dynamicFlag) - ShrinkInputBuffer(ssl, NO_FORCED_FREE); - - /* suites */ - XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); - ssl->suites = NULL; - - /* RNG */ - if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) { - XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); - ssl->rng = NULL; - } - -#ifdef CYASSL_DTLS - /* DTLS_POOL */ - if (ssl->options.dtls && ssl->dtls_pool != NULL) { - DtlsPoolReset(ssl); - XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - ssl->dtls_pool = NULL; - } -#endif - - /* arrays */ - if (ssl->options.saveArrays) - FreeArrays(ssl, 1); - -#ifndef NO_RSA - /* peerRsaKey */ - if (ssl->peerRsaKey) { - FreeRsaKey(ssl->peerRsaKey); - XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA); - ssl->peerRsaKey = NULL; - } -#endif - -#ifdef HAVE_ECC - if (ssl->peerEccKey) - { - if (ssl->peerEccKeyPresent) { - ecc_free(ssl->peerEccKey); - ssl->peerEccKeyPresent = 0; - } - XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC); - ssl->peerEccKey = NULL; - } - if (ssl->peerEccDsaKey) - { - if (ssl->peerEccDsaKeyPresent) { - ecc_free(ssl->peerEccDsaKey); - ssl->peerEccDsaKeyPresent = 0; - } - XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); - ssl->peerEccDsaKey = NULL; - } - if (ssl->eccTempKey) - { - if (ssl->eccTempKeyPresent) { - ecc_free(ssl->eccTempKey); - ssl->eccTempKeyPresent = 0; - } - XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC); - ssl->eccTempKey = NULL; - } - if (ssl->eccDsaKey) - { - if (ssl->eccDsaKeyPresent) { - ecc_free(ssl->eccDsaKey); - ssl->eccDsaKeyPresent = 0; - } - XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); - ssl->eccDsaKey = NULL; - } -#endif -#ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); - ssl->buffers.peerEccDsaKey.buffer = NULL; - #endif /* HAVE_ECC */ - #ifndef NO_RSA - XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA); - ssl->buffers.peerRsaKey.buffer = NULL; - #endif /* NO_RSA */ -#endif /* HAVE_PK_CALLBACKS */ -} - - -void FreeSSL(CYASSL* ssl) -{ - FreeSSL_Ctx(ssl->ctx); /* will decrement and free underyling CTX if 0 */ - SSL_ResourceFree(ssl); - XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL); -} - - -#ifdef CYASSL_DTLS - -int DtlsPoolInit(CYASSL* ssl) -{ - if (ssl->dtls_pool == NULL) { - DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool), - ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - if (pool == NULL) { - CYASSL_MSG("DTLS Buffer Pool Memory error"); - return MEMORY_E; - } - else { - int i; - - for (i = 0; i < DTLS_POOL_SZ; i++) { - pool->buf[i].length = 0; - pool->buf[i].buffer = NULL; - } - pool->used = 0; - ssl->dtls_pool = pool; - } - } - return 0; -} - - -int DtlsPoolSave(CYASSL* ssl, const byte *src, int sz) -{ - DtlsPool *pool = ssl->dtls_pool; - if (pool != NULL && pool->used < DTLS_POOL_SZ) { - buffer *pBuf = &pool->buf[pool->used]; - pBuf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); - if (pBuf->buffer == NULL) { - CYASSL_MSG("DTLS Buffer Memory error"); - return MEMORY_ERROR; - } - XMEMCPY(pBuf->buffer, src, sz); - pBuf->length = (word32)sz; - pool->used++; - } - return 0; -} - - -void DtlsPoolReset(CYASSL* ssl) -{ - DtlsPool *pool = ssl->dtls_pool; - if (pool != NULL) { - buffer *pBuf; - int i, used; - - used = pool->used; - for (i = 0, pBuf = &pool->buf[0]; i < used; i++, pBuf++) { - XFREE(pBuf->buffer, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); - pBuf->buffer = NULL; - pBuf->length = 0; - } - pool->used = 0; - } - ssl->dtls_timeout = ssl->dtls_timeout_init; -} - - -int DtlsPoolTimeout(CYASSL* ssl) -{ - int result = -1; - if (ssl->dtls_timeout < ssl->dtls_timeout_max) { - ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; - result = 0; - } - return result; -} - - -int DtlsPoolSend(CYASSL* ssl) -{ - int ret; - DtlsPool *pool = ssl->dtls_pool; - - if (pool != NULL && pool->used > 0) { - int i; - for (i = 0; i < pool->used; i++) { - int sendResult; - buffer* buf = &pool->buf[i]; - - DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer; - - word16 message_epoch; - ato16(dtls->epoch, &message_epoch); - if (message_epoch == ssl->keys.dtls_epoch) { - /* Increment record sequence number on retransmitted handshake - * messages */ - c32to48(ssl->keys.dtls_sequence_number, dtls->sequence_number); - ssl->keys.dtls_sequence_number++; - } - else { - /* The Finished message is sent with the next epoch, keep its - * sequence number */ - } - - if ((ret = CheckAvailableSize(ssl, buf->length)) != 0) - return ret; - - XMEMCPY(ssl->buffers.outputBuffer.buffer, buf->buffer, buf->length); - ssl->buffers.outputBuffer.idx = 0; - ssl->buffers.outputBuffer.length = buf->length; - - sendResult = SendBuffered(ssl); - if (sendResult < 0) { - return sendResult; - } - } - } - return 0; -} - - -/* functions for managing DTLS datagram reordering */ - -/* Need to allocate space for the handshake message header. The hashing - * routines assume the message pointer is still within the buffer that - * has the headers, and will include those headers in the hash. The store - * routines need to take that into account as well. New will allocate - * extra space for the headers. */ -DtlsMsg* DtlsMsgNew(word32 sz, void* heap) -{ - DtlsMsg* msg = NULL; - - msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); - - if (msg != NULL) { - msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ, - heap, DYNAMIC_TYPE_NONE); - if (msg->buf != NULL) { - msg->next = NULL; - msg->seq = 0; - msg->sz = sz; - msg->fragSz = 0; - msg->msg = msg->buf + DTLS_HANDSHAKE_HEADER_SZ; - } - else { - XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); - msg = NULL; - } - } - - return msg; -} - -void DtlsMsgDelete(DtlsMsg* item, void* heap) -{ - (void)heap; - - if (item != NULL) { - if (item->buf != NULL) - XFREE(item->buf, heap, DYNAMIC_TYPE_NONE); - XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG); - } -} - - -void DtlsMsgListDelete(DtlsMsg* head, void* heap) -{ - DtlsMsg* next; - while (head) { - next = head->next; - DtlsMsgDelete(head, heap); - head = next; - } -} - - -void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type, - word32 fragOffset, word32 fragSz) -{ - if (msg != NULL && data != NULL && msg->fragSz <= msg->sz) { - msg->seq = seq; - msg->type = type; - msg->fragSz += fragSz; - /* If fragOffset is zero, this is either a full message that is out - * of order, or the first fragment of a fragmented message. Copy the - * handshake message header as well as the message data. */ - if (fragOffset == 0) - XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ, - fragSz + DTLS_HANDSHAKE_HEADER_SZ); - else { - /* If fragOffet is non-zero, this is an additional fragment that - * needs to be copied to its location in the message buffer. Also - * copy the total size of the message over the fragment size. The - * hash routines look at a defragmented message if it had actually - * come across as a single handshake message. */ - XMEMCPY(msg->msg + fragOffset, data, fragSz); - c32to24(msg->sz, msg->msg - DTLS_HANDSHAKE_FRAG_SZ); - } - } -} - - -DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq) -{ - while (head != NULL && head->seq != seq) { - head = head->next; - } - return head; -} - - -DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, - word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap) -{ - - /* See if seq exists in the list. If it isn't in the list, make - * a new item of size dataSz, copy fragSz bytes from data to msg->msg - * starting at offset fragOffset, and add fragSz to msg->fragSz. If - * the seq is in the list and it isn't full, copy fragSz bytes from - * data to msg->msg starting at offset fragOffset, and add fragSz to - * msg->fragSz. The new item should be inserted into the list in its - * proper position. - * - * 1. Find seq in list, or where seq should go in list. If seq not in - * list, create new item and insert into list. Either case, keep - * pointer to item. - * 2. If msg->fragSz + fragSz < sz, copy data to msg->msg at offset - * fragOffset. Add fragSz to msg->fragSz. - */ - - if (head != NULL) { - DtlsMsg* cur = DtlsMsgFind(head, seq); - if (cur == NULL) { - cur = DtlsMsgNew(dataSz, heap); - if (cur != NULL) { - DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz); - head = DtlsMsgInsert(head, cur); - } - } - else { - DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz); - } - } - else { - head = DtlsMsgNew(dataSz, heap); - DtlsMsgSet(head, seq, data, type, fragOffset, fragSz); - } - - return head; -} - - -/* DtlsMsgInsert() is an in-order insert. */ -DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item) -{ - if (head == NULL || item->seq < head->seq) { - item->next = head; - head = item; - } - else if (head->next == NULL) { - head->next = item; - } - else { - DtlsMsg* cur = head->next; - DtlsMsg* prev = head; - while (cur) { - if (item->seq < cur->seq) { - item->next = cur; - prev->next = item; - break; - } - prev = cur; - cur = cur->next; - } - if (cur == NULL) { - prev->next = item; - } - } - - return head; -} - -#endif /* CYASSL_DTLS */ - -#ifndef NO_OLD_TLS - -ProtocolVersion MakeSSLv3(void) -{ - ProtocolVersion pv; - pv.major = SSLv3_MAJOR; - pv.minor = SSLv3_MINOR; - - return pv; -} - -#endif /* NO_OLD_TLS */ - - -#ifdef CYASSL_DTLS - -ProtocolVersion MakeDTLSv1(void) -{ - ProtocolVersion pv; - pv.major = DTLS_MAJOR; - pv.minor = DTLS_MINOR; - - return pv; -} - -ProtocolVersion MakeDTLSv1_2(void) -{ - ProtocolVersion pv; - pv.major = DTLS_MAJOR; - pv.minor = DTLSv1_2_MINOR; - - return pv; -} - -#endif /* CYASSL_DTLS */ - - - - -#ifdef USE_WINDOWS_API - - word32 LowResTimer(void) - { - static int init = 0; - static LARGE_INTEGER freq; - LARGE_INTEGER count; - - if (!init) { - QueryPerformanceFrequency(&freq); - init = 1; - } - - QueryPerformanceCounter(&count); - - return (word32)(count.QuadPart / freq.QuadPart); - } - -#elif defined(HAVE_RTP_SYS) - - #include "rtptime.h" - - word32 LowResTimer(void) - { - return (word32)rtp_get_system_sec(); - } - - -#elif defined(MICRIUM) - - word32 LowResTimer(void) - { - NET_SECURE_OS_TICK clk; - - #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) - clk = NetSecure_OS_TimeGet(); - #endif - return (word32)clk; - } - - -#elif defined(MICROCHIP_TCPIP_V5) - - word32 LowResTimer(void) - { - return (word32) TickGet(); - } - - -#elif defined(MICROCHIP_TCPIP) - - #if defined(MICROCHIP_MPLAB_HARMONY) - - #include <system/tmr/sys_tmr.h> - - word32 LowResTimer(void) - { - return (word32) SYS_TMR_TickCountGet(); - } - - #else - - word32 LowResTimer(void) - { - return (word32) SYS_TICK_Get(); - } - - #endif - -#elif defined(FREESCALE_MQX) - - word32 LowResTimer(void) - { - TIME_STRUCT mqxTime; - - _time_get_elapsed(&mqxTime); - - return (word32) mqxTime.SECONDS; - } - - -#elif defined(USER_TICKS) -#if 0 - word32 LowResTimer(void) - { - /* - write your own clock tick function if don't want time(0) - needs second accuracy but doesn't have to correlated to EPOCH - */ - } -#endif -#else /* !USE_WINDOWS_API && !HAVE_RTP_SYS && !MICRIUM && !USER_TICKS */ - - #include <time.h> - - word32 LowResTimer(void) - { - return (word32)time(0); - } - - -#endif /* USE_WINDOWS_API */ - - -/* add output to md5 and sha handshake hashes, exclude record header */ -static int HashOutput(CYASSL* ssl, const byte* output, int sz, int ivSz) -{ - const byte* adj = output + RECORD_HEADER_SZ + ivSz; - sz -= RECORD_HEADER_SZ; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - adj += DTLS_RECORD_EXTRA; - sz -= DTLS_RECORD_EXTRA; - } -#endif -#ifndef NO_OLD_TLS -#ifndef NO_SHA - ShaUpdate(&ssl->hashSha, adj, sz); -#endif -#ifndef NO_MD5 - Md5Update(&ssl->hashMd5, adj, sz); -#endif -#endif - - if (IsAtLeastTLSv1_2(ssl)) { - int ret; - -#ifndef NO_SHA256 - ret = Sha256Update(&ssl->hashSha256, adj, sz); - if (ret != 0) - return ret; -#endif -#ifdef CYASSL_SHA384 - ret = Sha384Update(&ssl->hashSha384, adj, sz); - if (ret != 0) - return ret; -#endif - } - - return 0; -} - - -/* add input to md5 and sha handshake hashes, include handshake header */ -static int HashInput(CYASSL* ssl, const byte* input, int sz) -{ - const byte* adj = input - HANDSHAKE_HEADER_SZ; - sz += HANDSHAKE_HEADER_SZ; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - adj -= DTLS_HANDSHAKE_EXTRA; - sz += DTLS_HANDSHAKE_EXTRA; - } -#endif - -#ifndef NO_OLD_TLS -#ifndef NO_SHA - ShaUpdate(&ssl->hashSha, adj, sz); -#endif -#ifndef NO_MD5 - Md5Update(&ssl->hashMd5, adj, sz); -#endif -#endif - - if (IsAtLeastTLSv1_2(ssl)) { - int ret; - -#ifndef NO_SHA256 - ret = Sha256Update(&ssl->hashSha256, adj, sz); - if (ret != 0) - return ret; -#endif -#ifdef CYASSL_SHA384 - ret = Sha384Update(&ssl->hashSha384, adj, sz); - if (ret != 0) - return ret; -#endif - } - - return 0; -} - - -/* add record layer header for message */ -static void AddRecordHeader(byte* output, word32 length, byte type, CYASSL* ssl) -{ - RecordLayerHeader* rl; - - /* record layer header */ - rl = (RecordLayerHeader*)output; - rl->type = type; - rl->pvMajor = ssl->version.major; /* type and version same in each */ - rl->pvMinor = ssl->version.minor; - - if (!ssl->options.dtls) - c16toa((word16)length, rl->length); - else { -#ifdef CYASSL_DTLS - DtlsRecordLayerHeader* dtls; - - /* dtls record layer header extensions */ - dtls = (DtlsRecordLayerHeader*)output; - c16toa(ssl->keys.dtls_epoch, dtls->epoch); - c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number); - c16toa((word16)length, dtls->length); -#endif - } -} - - -/* add handshake header for message */ -static void AddHandShakeHeader(byte* output, word32 length, byte type, - CYASSL* ssl) -{ - HandShakeHeader* hs; - (void)ssl; - - /* handshake header */ - hs = (HandShakeHeader*)output; - hs->type = type; - c32to24(length, hs->length); /* type and length same for each */ -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - DtlsHandShakeHeader* dtls; - - /* dtls handshake header extensions */ - dtls = (DtlsHandShakeHeader*)output; - c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq); - c32to24(0, dtls->fragment_offset); - c32to24(length, dtls->fragment_length); - } -#endif -} - - -/* add both headers for handshake message */ -static void AddHeaders(byte* output, word32 length, byte type, CYASSL* ssl) -{ - if (!ssl->options.dtls) { - AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl); - AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl); - } -#ifdef CYASSL_DTLS - else { - AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl); - AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl); - } -#endif -} - - -/* return bytes received, -1 on error */ -static int Receive(CYASSL* ssl, byte* buf, word32 sz) -{ - int recvd; - - if (ssl->ctx->CBIORecv == NULL) { - CYASSL_MSG("Your IO Recv callback is null, please set"); - return -1; - } - -retry: - recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx); - if (recvd < 0) - switch (recvd) { - case CYASSL_CBIO_ERR_GENERAL: /* general/unknown error */ - return -1; - - case CYASSL_CBIO_ERR_WANT_READ: /* want read, would block */ - return WANT_READ; - - case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ - #ifdef USE_WINDOWS_API - if (ssl->options.dtls) { - goto retry; - } - #endif - ssl->options.connReset = 1; - return -1; - - case CYASSL_CBIO_ERR_ISR: /* interrupt */ - /* see if we got our timeout */ - #ifdef CYASSL_CALLBACKS - if (ssl->toInfoOn) { - struct itimerval timeout; - getitimer(ITIMER_REAL, &timeout); - if (timeout.it_value.tv_sec == 0 && - timeout.it_value.tv_usec == 0) { - XSTRNCPY(ssl->timeoutInfo.timeoutName, - "recv() timeout", MAX_TIMEOUT_NAME_SZ); - CYASSL_MSG("Got our timeout"); - return WANT_READ; - } - } - #endif - goto retry; - - case CYASSL_CBIO_ERR_CONN_CLOSE: /* peer closed connection */ - ssl->options.isClosed = 1; - return -1; - - case CYASSL_CBIO_ERR_TIMEOUT: -#ifdef CYASSL_DTLS - if (DtlsPoolTimeout(ssl) == 0 && DtlsPoolSend(ssl) == 0) - goto retry; - else -#endif - return -1; - - default: - return recvd; - } - - return recvd; -} - - -/* Switch dynamic output buffer back to static, buffer is assumed clear */ -void ShrinkOutputBuffer(CYASSL* ssl) -{ - CYASSL_MSG("Shrinking output buffer\n"); - XFREE(ssl->buffers.outputBuffer.buffer - ssl->buffers.outputBuffer.offset, - ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); - ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; - ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; - ssl->buffers.outputBuffer.dynamicFlag = 0; - ssl->buffers.outputBuffer.offset = 0; -} - - -/* Switch dynamic input buffer back to static, keep any remaining input */ -/* forced free means cleaning up */ -void ShrinkInputBuffer(CYASSL* ssl, int forcedFree) -{ - int usedLength = ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx; - if (!forcedFree && usedLength > STATIC_BUFFER_LEN) - return; - - CYASSL_MSG("Shrinking input buffer\n"); - - if (!forcedFree && usedLength) - XMEMCPY(ssl->buffers.inputBuffer.staticBuffer, - ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, - usedLength); - - XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, - ssl->heap, DYNAMIC_TYPE_IN_BUFFER); - ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; - ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; - ssl->buffers.inputBuffer.dynamicFlag = 0; - ssl->buffers.inputBuffer.offset = 0; - ssl->buffers.inputBuffer.idx = 0; - ssl->buffers.inputBuffer.length = usedLength; -} - - -int SendBuffered(CYASSL* ssl) -{ - if (ssl->ctx->CBIOSend == NULL) { - CYASSL_MSG("Your IO Send callback is null, please set"); - return SOCKET_ERROR_E; - } - - while (ssl->buffers.outputBuffer.length > 0) { - int sent = ssl->ctx->CBIOSend(ssl, - (char*)ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.idx, - (int)ssl->buffers.outputBuffer.length, - ssl->IOCB_WriteCtx); - if (sent < 0) { - switch (sent) { - - case CYASSL_CBIO_ERR_WANT_WRITE: /* would block */ - return WANT_WRITE; - - case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ - ssl->options.connReset = 1; - break; - - case CYASSL_CBIO_ERR_ISR: /* interrupt */ - /* see if we got our timeout */ - #ifdef CYASSL_CALLBACKS - if (ssl->toInfoOn) { - struct itimerval timeout; - getitimer(ITIMER_REAL, &timeout); - if (timeout.it_value.tv_sec == 0 && - timeout.it_value.tv_usec == 0) { - XSTRNCPY(ssl->timeoutInfo.timeoutName, - "send() timeout", MAX_TIMEOUT_NAME_SZ); - CYASSL_MSG("Got our timeout"); - return WANT_WRITE; - } - } - #endif - continue; - - case CYASSL_CBIO_ERR_CONN_CLOSE: /* epipe / conn closed */ - ssl->options.connReset = 1; /* treat same as reset */ - break; - - default: - return SOCKET_ERROR_E; - } - - return SOCKET_ERROR_E; - } - - ssl->buffers.outputBuffer.idx += sent; - ssl->buffers.outputBuffer.length -= sent; - } - - ssl->buffers.outputBuffer.idx = 0; - - if (ssl->buffers.outputBuffer.dynamicFlag) - ShrinkOutputBuffer(ssl); - - return 0; -} - - -/* Grow the output buffer */ -static INLINE int GrowOutputBuffer(CYASSL* ssl, int size) -{ - byte* tmp; - byte hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ : - RECORD_HEADER_SZ; - byte align = CYASSL_GENERAL_ALIGNMENT; - /* the encrypted data will be offset from the front of the buffer by - the header, if the user wants encrypted alignment they need - to define their alignment requirement */ - - if (align) { - while (align < hdrSz) - align *= 2; - } - - tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length + align, - ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); - CYASSL_MSG("growing output buffer\n"); - - if (!tmp) return MEMORY_E; - if (align) - tmp += align - hdrSz; - - if (ssl->buffers.outputBuffer.length) - XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer, - ssl->buffers.outputBuffer.length); - - if (ssl->buffers.outputBuffer.dynamicFlag) - XFREE(ssl->buffers.outputBuffer.buffer - - ssl->buffers.outputBuffer.offset, ssl->heap, - DYNAMIC_TYPE_OUT_BUFFER); - ssl->buffers.outputBuffer.dynamicFlag = 1; - if (align) - ssl->buffers.outputBuffer.offset = align - hdrSz; - else - ssl->buffers.outputBuffer.offset = 0; - ssl->buffers.outputBuffer.buffer = tmp; - ssl->buffers.outputBuffer.bufferSize = size + - ssl->buffers.outputBuffer.length; - return 0; -} - - -/* Grow the input buffer, should only be to read cert or big app data */ -int GrowInputBuffer(CYASSL* ssl, int size, int usedLength) -{ - byte* tmp; - byte hdrSz = DTLS_RECORD_HEADER_SZ; - byte align = ssl->options.dtls ? CYASSL_GENERAL_ALIGNMENT : 0; - /* the encrypted data will be offset from the front of the buffer by - the dtls record header, if the user wants encrypted alignment they need - to define their alignment requirement. in tls we read record header - to get size of record and put actual data back at front, so don't need */ - - if (align) { - while (align < hdrSz) - align *= 2; - } - tmp = (byte*) XMALLOC(size + usedLength + align, ssl->heap, - DYNAMIC_TYPE_IN_BUFFER); - CYASSL_MSG("growing input buffer\n"); - - if (!tmp) return MEMORY_E; - if (align) - tmp += align - hdrSz; - - if (usedLength) - XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, usedLength); - - if (ssl->buffers.inputBuffer.dynamicFlag) - XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, - ssl->heap,DYNAMIC_TYPE_IN_BUFFER); - - ssl->buffers.inputBuffer.dynamicFlag = 1; - if (align) - ssl->buffers.inputBuffer.offset = align - hdrSz; - else - ssl->buffers.inputBuffer.offset = 0; - ssl->buffers.inputBuffer.buffer = tmp; - ssl->buffers.inputBuffer.bufferSize = size + usedLength; - ssl->buffers.inputBuffer.idx = 0; - ssl->buffers.inputBuffer.length = usedLength; - - return 0; -} - - -/* check available size into output buffer, make room if needed */ -int CheckAvailableSize(CYASSL *ssl, int size) -{ - if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length - < (word32)size) { - if (GrowOutputBuffer(ssl, size) < 0) - return MEMORY_E; - } - - return 0; -} - - -/* do all verify and sanity checks on record header */ -static int GetRecordHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, - RecordLayerHeader* rh, word16 *size) -{ - if (!ssl->options.dtls) { - XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ); - *inOutIdx += RECORD_HEADER_SZ; - ato16(rh->length, size); - } - else { -#ifdef CYASSL_DTLS - /* type and version in same sport */ - XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ); - *inOutIdx += ENUM_LEN + VERSION_SZ; - ato16(input + *inOutIdx, &ssl->keys.dtls_state.curEpoch); - *inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */ - ato32(input + *inOutIdx, &ssl->keys.dtls_state.curSeq); - *inOutIdx += 4; /* advance past rest of seq */ - ato16(input + *inOutIdx, size); - *inOutIdx += LENGTH_SZ; -#endif - } - - /* catch version mismatch */ - if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){ - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.acceptState == ACCEPT_BEGIN) - CYASSL_MSG("Client attempting to connect with different version"); - else if (ssl->options.side == CYASSL_CLIENT_END && - ssl->options.downgrade && - ssl->options.connectState < FIRST_REPLY_DONE) - CYASSL_MSG("Server attempting to accept with different version"); - else { - CYASSL_MSG("SSL version error"); - return VERSION_ERROR; /* only use requested version */ - } - } - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if (DtlsCheckWindow(&ssl->keys.dtls_state) != 1) - return SEQUENCE_ERROR; - } -#endif - - /* record layer length check */ -#ifdef HAVE_MAX_FRAGMENT - if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) - return LENGTH_ERROR; -#else - if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) - return LENGTH_ERROR; -#endif - - /* verify record type here as well */ - switch (rh->type) { - case handshake: - case change_cipher_spec: - case application_data: - case alert: - break; - case no_type: - default: - CYASSL_MSG("Unknown Record Type"); - return UNKNOWN_RECORD_TYPE; - } - - /* haven't decrypted this record yet */ - ssl->keys.decryptedCur = 0; - - return 0; -} - - -static int GetHandShakeHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, - byte *type, word32 *size) -{ - const byte *ptr = input + *inOutIdx; - (void)ssl; - *inOutIdx += HANDSHAKE_HEADER_SZ; - - *type = ptr[0]; - c24to32(&ptr[1], size); - - return 0; -} - - -#ifdef CYASSL_DTLS -static int GetDtlsHandShakeHeader(CYASSL* ssl, const byte* input, - word32* inOutIdx, byte *type, word32 *size, - word32 *fragOffset, word32 *fragSz) -{ - word32 idx = *inOutIdx; - - *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; - - *type = input[idx++]; - c24to32(input + idx, size); - idx += BYTE3_LEN; - - ato16(input + idx, &ssl->keys.dtls_peer_handshake_number); - idx += DTLS_HANDSHAKE_SEQ_SZ; - - c24to32(input + idx, fragOffset); - idx += DTLS_HANDSHAKE_FRAG_SZ; - c24to32(input + idx, fragSz); - - return 0; -} -#endif - - -#ifndef NO_OLD_TLS -/* fill with MD5 pad size since biggest required */ -static const byte PAD1[PAD_MD5] = - { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 - }; -static const byte PAD2[PAD_MD5] = - { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c - }; - -/* calculate MD5 hash for finished */ -static void BuildMD5(CYASSL* ssl, Hashes* hashes, const byte* sender) -{ - byte md5_result[MD5_DIGEST_SIZE]; - - /* make md5 inner */ - Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER); - Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); - Md5Update(&ssl->hashMd5, PAD1, PAD_MD5); - Md5Final(&ssl->hashMd5, md5_result); - - /* make md5 outer */ - Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); - Md5Update(&ssl->hashMd5, PAD2, PAD_MD5); - Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE); - - Md5Final(&ssl->hashMd5, hashes->md5); -} - - -/* calculate SHA hash for finished */ -static void BuildSHA(CYASSL* ssl, Hashes* hashes, const byte* sender) -{ - byte sha_result[SHA_DIGEST_SIZE]; - - /* make sha inner */ - ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER); - ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); - ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA); - ShaFinal(&ssl->hashSha, sha_result); - - /* make sha outer */ - ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); - ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA); - ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE); - - ShaFinal(&ssl->hashSha, hashes->sha); -} -#endif - - -static int BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) -{ - /* store current states, building requires get_digest which resets state */ -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - Md5 md5 = ssl->hashMd5; -#endif -#ifndef NO_SHA - Sha sha = ssl->hashSha; -#endif -#endif -#ifndef NO_SHA256 - Sha256 sha256 = ssl->hashSha256; -#endif -#ifdef CYASSL_SHA384 - Sha384 sha384 = ssl->hashSha384; -#endif - - int ret = 0; - -#ifndef NO_TLS - if (ssl->options.tls) { - ret = BuildTlsFinished(ssl, hashes, sender); - } -#endif -#ifndef NO_OLD_TLS - if (!ssl->options.tls) { - BuildMD5(ssl, hashes, sender); - BuildSHA(ssl, hashes, sender); - } -#endif - - /* restore */ -#ifndef NO_OLD_TLS - #ifndef NO_MD5 - ssl->hashMd5 = md5; - #endif - #ifndef NO_SHA - ssl->hashSha = sha; - #endif -#endif - if (IsAtLeastTLSv1_2(ssl)) { - #ifndef NO_SHA256 - ssl->hashSha256 = sha256; - #endif - #ifdef CYASSL_SHA384 - ssl->hashSha384 = sha384; - #endif - } - - return ret; -} - - -#ifndef NO_CERTS - - -/* Match names with wildcards, each wildcard can represent a single name - component or fragment but not mulitple names, i.e., - *.z.com matches y.z.com but not x.y.z.com - - return 1 on success */ -static int MatchDomainName(const char* pattern, int len, const char* str) -{ - char p, s; - - if (pattern == NULL || str == NULL || len <= 0) - return 0; - - while (len > 0) { - - p = (char)XTOLOWER(*pattern++); - if (p == 0) - break; - - if (p == '*') { - while (--len > 0 && (p = (char)XTOLOWER(*pattern++)) == '*') - ; - - if (len == 0) - p = '\0'; - - while ( (s = (char)XTOLOWER(*str)) != '\0') { - if (s == p) - break; - if (s == '.') - return 0; - str++; - } - } - else { - if (p != (char)XTOLOWER(*str)) - return 0; - } - - if (*str != '\0') - str++; - - if (len > 0) - len--; - } - - return *str == '\0'; -} - - -/* try to find an altName match to domain, return 1 on success */ -static int CheckAltNames(DecodedCert* dCert, char* domain) -{ - int match = 0; - DNS_entry* altName = NULL; - - CYASSL_MSG("Checking AltNames"); - - if (dCert) - altName = dCert->altNames; - - while (altName) { - CYASSL_MSG(" individual AltName check"); - - if (MatchDomainName(altName->name,(int)XSTRLEN(altName->name), domain)){ - match = 1; - break; - } - - altName = altName->next; - } - - return match; -} - - -#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) - -/* Copy parts X509 needs from Decoded cert, 0 on success */ -int CopyDecodedToX509(CYASSL_X509* x509, DecodedCert* dCert) -{ - int ret = 0; - - if (x509 == NULL || dCert == NULL) - return BAD_FUNC_ARG; - - x509->version = dCert->version + 1; - - XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX); - x509->issuer.name[ASN_NAME_MAX - 1] = '\0'; - x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1; -#ifdef OPENSSL_EXTRA - if (dCert->issuerName.fullName != NULL) { - XMEMCPY(&x509->issuer.fullName, - &dCert->issuerName, sizeof(DecodedName)); - x509->issuer.fullName.fullName = (char*)XMALLOC( - dCert->issuerName.fullNameLen, NULL, DYNAMIC_TYPE_X509); - if (x509->issuer.fullName.fullName != NULL) - XMEMCPY(x509->issuer.fullName.fullName, - dCert->issuerName.fullName, dCert->issuerName.fullNameLen); - } -#endif /* OPENSSL_EXTRA */ - - XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX); - x509->subject.name[ASN_NAME_MAX - 1] = '\0'; - x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1; -#ifdef OPENSSL_EXTRA - if (dCert->subjectName.fullName != NULL) { - XMEMCPY(&x509->subject.fullName, - &dCert->subjectName, sizeof(DecodedName)); - x509->subject.fullName.fullName = (char*)XMALLOC( - dCert->subjectName.fullNameLen, NULL, DYNAMIC_TYPE_X509); - if (x509->subject.fullName.fullName != NULL) - XMEMCPY(x509->subject.fullName.fullName, - dCert->subjectName.fullName, dCert->subjectName.fullNameLen); - } -#endif /* OPENSSL_EXTRA */ - - XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE); - x509->serialSz = dCert->serialSz; - if (dCert->subjectCNLen < ASN_NAME_MAX) { - XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen); - x509->subjectCN[dCert->subjectCNLen] = '\0'; - } - else - x509->subjectCN[0] = '\0'; - -#ifdef CYASSL_SEP - { - int minSz = min(dCert->deviceTypeSz, EXTERNAL_SERIAL_SIZE); - if (minSz > 0) { - x509->deviceTypeSz = minSz; - XMEMCPY(x509->deviceType, dCert->deviceType, minSz); - } - else - x509->deviceTypeSz = 0; - minSz = min(dCert->hwTypeSz, EXTERNAL_SERIAL_SIZE); - if (minSz != 0) { - x509->hwTypeSz = minSz; - XMEMCPY(x509->hwType, dCert->hwType, minSz); - } - else - x509->hwTypeSz = 0; - minSz = min(dCert->hwSerialNumSz, EXTERNAL_SERIAL_SIZE); - if (minSz != 0) { - x509->hwSerialNumSz = minSz; - XMEMCPY(x509->hwSerialNum, dCert->hwSerialNum, minSz); - } - else - x509->hwSerialNumSz = 0; - } -#endif /* CYASSL_SEP */ - { - int minSz = min(dCert->beforeDateLen, MAX_DATE_SZ); - if (minSz != 0) { - x509->notBeforeSz = minSz; - XMEMCPY(x509->notBefore, dCert->beforeDate, minSz); - } - else - x509->notBeforeSz = 0; - minSz = min(dCert->afterDateLen, MAX_DATE_SZ); - if (minSz != 0) { - x509->notAfterSz = minSz; - XMEMCPY(x509->notAfter, dCert->afterDate, minSz); - } - else - x509->notAfterSz = 0; - } - - if (dCert->publicKey != NULL && dCert->pubKeySize != 0) { - x509->pubKey.buffer = (byte*)XMALLOC( - dCert->pubKeySize, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - if (x509->pubKey.buffer != NULL) { - x509->pubKeyOID = dCert->keyOID; - x509->pubKey.length = dCert->pubKeySize; - XMEMCPY(x509->pubKey.buffer, dCert->publicKey, dCert->pubKeySize); - } - else - ret = MEMORY_E; - } - - if (dCert->signature != NULL && dCert->sigLength != 0) { - x509->sig.buffer = (byte*)XMALLOC( - dCert->sigLength, NULL, DYNAMIC_TYPE_SIGNATURE); - if (x509->sig.buffer == NULL) { - ret = MEMORY_E; - } - else { - XMEMCPY(x509->sig.buffer, dCert->signature, dCert->sigLength); - x509->sig.length = dCert->sigLength; - x509->sigOID = dCert->signatureOID; - } - } - - /* store cert for potential retrieval */ - x509->derCert.buffer = (byte*)XMALLOC(dCert->maxIdx, NULL, - DYNAMIC_TYPE_CERT); - if (x509->derCert.buffer == NULL) { - ret = MEMORY_E; - } - else { - XMEMCPY(x509->derCert.buffer, dCert->source, dCert->maxIdx); - x509->derCert.length = dCert->maxIdx; - } - - x509->altNames = dCert->altNames; - dCert->altNames = NULL; /* takes ownership */ - x509->altNamesNext = x509->altNames; /* index hint */ - - x509->isCa = dCert->isCA; -#ifdef OPENSSL_EXTRA - x509->pathLength = dCert->pathLength; - x509->keyUsage = dCert->extKeyUsage; - - x509->basicConstSet = dCert->extBasicConstSet; - x509->basicConstCrit = dCert->extBasicConstCrit; - x509->basicConstPlSet = dCert->extBasicConstPlSet; - x509->subjAltNameSet = dCert->extSubjAltNameSet; - x509->subjAltNameCrit = dCert->extSubjAltNameCrit; - x509->authKeyIdSet = dCert->extAuthKeyIdSet; - x509->authKeyIdCrit = dCert->extAuthKeyIdCrit; - if (dCert->extAuthKeyIdSrc != NULL && dCert->extAuthKeyIdSz != 0) { - x509->authKeyId = (byte*)XMALLOC(dCert->extAuthKeyIdSz, NULL, 0); - if (x509->authKeyId != NULL) { - XMEMCPY(x509->authKeyId, - dCert->extAuthKeyIdSrc, dCert->extAuthKeyIdSz); - x509->authKeyIdSz = dCert->extAuthKeyIdSz; - } - else - ret = MEMORY_E; - } - x509->subjKeyIdSet = dCert->extSubjKeyIdSet; - x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit; - if (dCert->extSubjKeyIdSrc != NULL && dCert->extSubjKeyIdSz != 0) { - x509->subjKeyId = (byte*)XMALLOC(dCert->extSubjKeyIdSz, NULL, 0); - if (x509->subjKeyId != NULL) { - XMEMCPY(x509->subjKeyId, - dCert->extSubjKeyIdSrc, dCert->extSubjKeyIdSz); - x509->subjKeyIdSz = dCert->extSubjKeyIdSz; - } - else - ret = MEMORY_E; - } - x509->keyUsageSet = dCert->extKeyUsageSet; - x509->keyUsageCrit = dCert->extKeyUsageCrit; - #ifdef CYASSL_SEP - x509->certPolicySet = dCert->extCertPolicySet; - x509->certPolicyCrit = dCert->extCertPolicyCrit; - #endif /* CYASSL_SEP */ -#endif /* OPENSSL_EXTRA */ -#ifdef HAVE_ECC - x509->pkCurveOID = dCert->pkCurveOID; -#endif /* HAVE_ECC */ - - return ret; -} - -#endif /* KEEP_PEER_CERT || SESSION_CERTS */ - - -static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 size) -{ - word32 listSz, begin = *inOutIdx; - int ret = 0; - int anyError = 0; - int totalCerts = 0; /* number of certs in certs buffer */ - int count; - char domain[ASN_NAME_MAX]; - buffer certs[MAX_CHAIN_DEPTH]; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo); - #endif - - if ((*inOutIdx - begin) + OPAQUE24_LEN > size) - return BUFFER_ERROR; - - c24to32(input + *inOutIdx, &listSz); - *inOutIdx += OPAQUE24_LEN; - -#ifdef HAVE_MAX_FRAGMENT - if (listSz > ssl->max_fragment) - return BUFFER_E; -#else - if (listSz > MAX_RECORD_SIZE) - return BUFFER_E; -#endif - - if ((*inOutIdx - begin) + listSz != size) - return BUFFER_ERROR; - - CYASSL_MSG("Loading peer's cert chain"); - /* first put cert chain into buffer so can verify top down - we're sent bottom up */ - while (listSz) { - word32 certSz; - - if (totalCerts >= MAX_CHAIN_DEPTH) - return MAX_CHAIN_ERROR; - - if ((*inOutIdx - begin) + OPAQUE24_LEN > size) - return BUFFER_ERROR; - - c24to32(input + *inOutIdx, &certSz); - *inOutIdx += OPAQUE24_LEN; - - if ((*inOutIdx - begin) + certSz > size) - return BUFFER_ERROR; - - certs[totalCerts].length = certSz; - certs[totalCerts].buffer = input + *inOutIdx; - -#ifdef SESSION_CERTS - if (ssl->session.chain.count < MAX_CHAIN_DEPTH && - certSz < MAX_X509_SIZE) { - ssl->session.chain.certs[ssl->session.chain.count].length = certSz; - XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer, - input + *inOutIdx, certSz); - ssl->session.chain.count++; - } else { - CYASSL_MSG("Couldn't store chain cert for session"); - } -#endif - - *inOutIdx += certSz; - listSz -= certSz + CERT_HEADER_SZ; - - totalCerts++; - CYASSL_MSG(" Put another cert into chain"); - } - - count = totalCerts; - - /* verify up to peer's first */ - while (count > 1) { - buffer myCert = certs[count - 1]; - DecodedCert dCert; - byte* subjectHash; - - InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); - ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, - ssl->ctx->cm); - #ifndef NO_SKID - subjectHash = dCert.extSubjKeyId; - #else - subjectHash = dCert.subjectHash; - #endif - - if (ret == 0 && dCert.isCA == 0) { - CYASSL_MSG("Chain cert is not a CA, not adding as one"); - } - else if (ret == 0 && ssl->options.verifyNone) { - CYASSL_MSG("Chain cert not verified by option, not adding as CA"); - } - else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) { - buffer add; - add.length = myCert.length; - add.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, - DYNAMIC_TYPE_CA); - CYASSL_MSG("Adding CA from chain"); - - if (add.buffer == NULL) - return MEMORY_E; - XMEMCPY(add.buffer, myCert.buffer, myCert.length); - - ret = AddCA(ssl->ctx->cm, add, CYASSL_CHAIN_CA, - ssl->ctx->verifyPeer); - if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ - } - else if (ret != 0) { - CYASSL_MSG("Failed to verify CA from chain"); - } - else { - CYASSL_MSG("Verified CA from chain and already had it"); - } - -#ifdef HAVE_CRL - if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) { - CYASSL_MSG("Doing Non Leaf CRL check"); - ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); - - if (ret != 0) { - CYASSL_MSG("\tCRL check not ok"); - } - } -#endif /* HAVE_CRL */ - - if (ret != 0 && anyError == 0) - anyError = ret; /* save error from last time */ - - FreeDecodedCert(&dCert); - count--; - } - - /* peer's, may not have one if blank client cert sent by TLSv1.2 */ - if (count) { - buffer myCert = certs[0]; - DecodedCert dCert; - int fatal = 0; - - CYASSL_MSG("Verifying Peer's cert"); - - InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); - ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, - ssl->ctx->cm); - if (ret == 0) { - CYASSL_MSG("Verified Peer's cert"); - fatal = 0; - } - else if (ret == ASN_PARSE_E) { - CYASSL_MSG("Got Peer cert ASN PARSE ERROR, fatal"); - fatal = 1; - } - else { - CYASSL_MSG("Failed to verify Peer's cert"); - if (ssl->verifyCallback) { - CYASSL_MSG("\tCallback override available, will continue"); - fatal = 0; - } - else { - CYASSL_MSG("\tNo callback override available, fatal"); - fatal = 1; - } - } - -#ifdef HAVE_OCSP - if (fatal == 0 && ssl->ctx->cm->ocspEnabled) { - ret = CheckCertOCSP(ssl->ctx->cm->ocsp, &dCert); - if (ret != 0) { - CYASSL_MSG("\tOCSP Lookup not ok"); - fatal = 0; - } - } -#endif - -#ifdef HAVE_CRL - if (fatal == 0 && ssl->ctx->cm->crlEnabled) { - int doCrlLookup = 1; - - #ifdef HAVE_OCSP - if (ssl->ctx->cm->ocspEnabled) { - doCrlLookup = (ret == OCSP_CERT_UNKNOWN); - } - #endif /* HAVE_OCSP */ - - if (doCrlLookup) { - CYASSL_MSG("Doing Leaf CRL check"); - ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); - - if (ret != 0) { - CYASSL_MSG("\tCRL check not ok"); - fatal = 0; - } - } - } - -#endif /* HAVE_CRL */ - -#ifdef KEEP_PEER_CERT - { - /* set X509 format for peer cert even if fatal */ - int copyRet = CopyDecodedToX509(&ssl->peerCert, &dCert); - if (copyRet == MEMORY_E) - fatal = 1; - } -#endif - -#ifndef IGNORE_KEY_EXTENSIONS - if (dCert.extKeyUsageSet) { - if ((ssl->specs.kea == rsa_kea) && - (dCert.extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) { - ret = KEYUSE_ENCIPHER_E; - } - if ((ssl->specs.sig_algo == rsa_sa_algo || - ssl->specs.sig_algo == ecc_dsa_sa_algo) && - (dCert.extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { - CYASSL_MSG("KeyUse Digital Sig not set"); - ret = KEYUSE_SIGNATURE_E; - } - } - - if (dCert.extExtKeyUsageSet) { - if (ssl->options.side == CYASSL_CLIENT_END) { - if ((dCert.extExtKeyUsage & - (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { - CYASSL_MSG("ExtKeyUse Server Auth not set"); - ret = EXTKEYUSE_AUTH_E; - } - } - else { - if ((dCert.extExtKeyUsage & - (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { - CYASSL_MSG("ExtKeyUse Client Auth not set"); - ret = EXTKEYUSE_AUTH_E; - } - } - } -#endif /* IGNORE_KEY_EXTENSIONS */ - - if (fatal) { - FreeDecodedCert(&dCert); - ssl->error = ret; - return ret; - } - ssl->options.havePeerCert = 1; - - /* store for callback use */ - if (dCert.subjectCNLen < ASN_NAME_MAX) { - XMEMCPY(domain, dCert.subjectCN, dCert.subjectCNLen); - domain[dCert.subjectCNLen] = '\0'; - } - else - domain[0] = '\0'; - - if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) { - if (MatchDomainName(dCert.subjectCN, dCert.subjectCNLen, - (char*)ssl->buffers.domainName.buffer) == 0) { - CYASSL_MSG("DomainName match on common name failed"); - if (CheckAltNames(&dCert, - (char*)ssl->buffers.domainName.buffer) == 0 ) { - CYASSL_MSG("DomainName match on alt names failed too"); - ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */ - } - } - } - - /* decode peer key */ - switch (dCert.keyOID) { - #ifndef NO_RSA - case RSAk: - { - word32 idx = 0; - if (RsaPublicKeyDecode(dCert.publicKey, &idx, - ssl->peerRsaKey, dCert.pubKeySize) != 0) { - ret = PEER_KEY_ERROR; - } - else { - ssl->peerRsaKeyPresent = 1; - #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - ssl->buffers.peerRsaKey.buffer = - XMALLOC(dCert.pubKeySize, - ssl->heap, DYNAMIC_TYPE_RSA); - if (ssl->buffers.peerRsaKey.buffer == NULL) - ret = MEMORY_ERROR; - else { - XMEMCPY(ssl->buffers.peerRsaKey.buffer, - dCert.publicKey, dCert.pubKeySize); - ssl->buffers.peerRsaKey.length = - dCert.pubKeySize; - } - #endif /* NO_RSA */ - #endif /*HAVE_PK_CALLBACKS */ - } - } - break; - #endif /* NO_RSA */ - #ifdef HAVE_NTRU - case NTRUk: - { - if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) { - ret = PEER_KEY_ERROR; - } - else { - XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize); - ssl->peerNtruKeyLen = (word16)dCert.pubKeySize; - ssl->peerNtruKeyPresent = 1; - } - } - break; - #endif /* HAVE_NTRU */ - #ifdef HAVE_ECC - case ECDSAk: - { - if (ecc_import_x963(dCert.publicKey, dCert.pubKeySize, - ssl->peerEccDsaKey) != 0) { - ret = PEER_KEY_ERROR; - } - else { - ssl->peerEccDsaKeyPresent = 1; - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ssl->buffers.peerEccDsaKey.buffer = - XMALLOC(dCert.pubKeySize, - ssl->heap, DYNAMIC_TYPE_ECC); - if (ssl->buffers.peerEccDsaKey.buffer == NULL) - ret = MEMORY_ERROR; - else { - XMEMCPY(ssl->buffers.peerEccDsaKey.buffer, - dCert.publicKey, dCert.pubKeySize); - ssl->buffers.peerEccDsaKey.length = - dCert.pubKeySize; - } - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - } - } - break; - #endif /* HAVE_ECC */ - default: - break; - } - - FreeDecodedCert(&dCert); - } - - if (anyError != 0 && ret == 0) - ret = anyError; - - if (ret == 0 && ssl->options.side == CYASSL_CLIENT_END) - ssl->options.serverState = SERVER_CERT_COMPLETE; - - if (ret != 0) { - if (!ssl->options.verifyNone) { - int why = bad_certificate; - if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) - why = certificate_expired; - if (ssl->verifyCallback) { - int ok; - CYASSL_X509_STORE_CTX store; - - store.error = ret; - store.error_depth = totalCerts; - store.discardSessionCerts = 0; - store.domain = domain; - store.userCtx = ssl->verifyCbCtx; -#ifdef KEEP_PEER_CERT - store.current_cert = &ssl->peerCert; -#else - store.current_cert = NULL; -#endif -#ifdef FORTRESS - store.ex_data = ssl; -#endif - ok = ssl->verifyCallback(0, &store); - if (ok) { - CYASSL_MSG("Verify callback overriding error!"); - ret = 0; - } - #ifdef SESSION_CERTS - if (store.discardSessionCerts) { - CYASSL_MSG("Verify callback requested discard sess certs"); - ssl->session.chain.count = 0; - } - #endif - } - if (ret != 0) { - SendAlert(ssl, alert_fatal, why); /* try to send */ - ssl->options.isClosed = 1; - } - } - ssl->error = ret; - } -#ifdef CYASSL_ALWAYS_VERIFY_CB - else { - if (ssl->verifyCallback) { - int ok; - CYASSL_X509_STORE_CTX store; - - store.error = ret; - store.error_depth = totalCerts; - store.discardSessionCerts = 0; - store.domain = domain; - store.userCtx = ssl->verifyCbCtx; -#ifdef KEEP_PEER_CERT - store.current_cert = &ssl->peerCert; -#endif - store.ex_data = ssl; - - ok = ssl->verifyCallback(1, &store); - if (!ok) { - CYASSL_MSG("Verify callback overriding valid certificate!"); - ret = -1; - SendAlert(ssl, alert_fatal, bad_certificate); - ssl->options.isClosed = 1; - } - #ifdef SESSION_CERTS - if (store.discardSessionCerts) { - CYASSL_MSG("Verify callback requested discard sess certs"); - ssl->session.chain.count = 0; - } - #endif - } - } -#endif - - return ret; -} - -#endif /* !NO_CERTS */ - - -static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 size, word32 totalSz) -{ - int ret = 0; - - if (size) /* must be 0 */ - return BUFFER_ERROR; - - if (ssl->keys.encryptionOn) { - byte verify[MAX_DIGEST_SIZE]; - int padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - - ssl->specs.hash_size; - - ret = ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ, - HANDSHAKE_HEADER_SZ, handshake, 1); - if (ret != 0) - return ret; - - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) - padSz -= ssl->specs.block_size; - - /* access beyond input + size should be checked against totalSz */ - if ((word32) (*inOutIdx + ssl->specs.hash_size + padSz) > totalSz) - return INCOMPLETE_DATA; - - /* verify */ - if (XMEMCMP(input + *inOutIdx, verify, ssl->specs.hash_size) != 0) { - CYASSL_MSG(" hello_request verify mac error"); - return VERIFY_MAC_ERROR; - } - - *inOutIdx += ssl->specs.hash_size + padSz; - } - - if (ssl->options.side == CYASSL_SERVER_END) { - SendAlert(ssl, alert_fatal, unexpected_message); /* try */ - return FATAL_ERROR; - } - else - return SendAlert(ssl, alert_warning, no_renegotiation); -} - - -int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, word32 size, - word32 totalSz, int sniff) -{ - word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ); - - if (finishedSz != size) - return BUFFER_ERROR; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); - #endif - - if (sniff == NO_SNIFF) { - if (XMEMCMP(input + *inOutIdx, &ssl->verifyHashes, size) != 0) { - CYASSL_MSG("Verify finished error on hashes"); - return VERIFY_FINISHED_ERROR; - } - } - - /* increment beyond input + size should be checked against totalSz */ - if (*inOutIdx + size + ssl->keys.padSz > totalSz) - return INCOMPLETE_DATA; - - /* force input exhaustion at ProcessReply consuming padSz */ - *inOutIdx += size + ssl->keys.padSz; - - if (ssl->options.side == CYASSL_CLIENT_END) { - ssl->options.serverState = SERVER_FINISHED_COMPLETE; - if (!ssl->options.resuming) { - ssl->options.handShakeState = HANDSHAKE_DONE; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - /* Other side has received our Finished, go to next epoch */ - ssl->keys.dtls_epoch++; - ssl->keys.dtls_sequence_number = 1; - } -#endif - } - } - else { - ssl->options.clientState = CLIENT_FINISHED_COMPLETE; - if (ssl->options.resuming) { - ssl->options.handShakeState = HANDSHAKE_DONE; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - /* Other side has received our Finished, go to next epoch */ - ssl->keys.dtls_epoch++; - ssl->keys.dtls_sequence_number = 1; - } -#endif - } - } - - return 0; -} - - -static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, - byte type, word32 size, word32 totalSz) -{ - int ret = 0; - (void)totalSz; - - CYASSL_ENTER("DoHandShakeMsgType"); - - /* make sure can read the message */ - if (*inOutIdx + size > totalSz) - return INCOMPLETE_DATA; - - ret = HashInput(ssl, input + *inOutIdx, size); - if (ret != 0) - return ret; - -#ifdef CYASSL_CALLBACKS - /* add name later, add on record and handshake header part back on */ - if (ssl->toInfoOn) { - int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add, - size + add, ssl->heap); - AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); - } -#endif - - if (ssl->options.handShakeState == HANDSHAKE_DONE && type != hello_request){ - CYASSL_MSG("HandShake message after handshake complete"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls == 0 && - ssl->options.serverState == NULL_STATE && type != server_hello) { - CYASSL_MSG("First server message not server hello"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls && - type == server_hello_done && - ssl->options.serverState < SERVER_HELLO_COMPLETE) { - CYASSL_MSG("Server hello done received before server hello in DTLS"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.clientState == NULL_STATE && type != client_hello) { - CYASSL_MSG("First client message not client hello"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - - switch (type) { - - case hello_request: - CYASSL_MSG("processing hello request"); - ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz); - break; - -#ifndef NO_CYASSL_CLIENT - case hello_verify_request: - CYASSL_MSG("processing hello verify request"); - ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size); - break; - - case server_hello: - CYASSL_MSG("processing server hello"); - ret = DoServerHello(ssl, input, inOutIdx, size); - break; - -#ifndef NO_CERTS - case certificate_request: - CYASSL_MSG("processing certificate request"); - ret = DoCertificateRequest(ssl, input, inOutIdx, size); - break; -#endif - - case server_key_exchange: - CYASSL_MSG("processing server key exchange"); - ret = DoServerKeyExchange(ssl, input, inOutIdx, size); - break; -#endif - -#ifndef NO_CERTS - case certificate: - CYASSL_MSG("processing certificate"); - ret = DoCertificate(ssl, input, inOutIdx, size); - break; -#endif - - case server_hello_done: - CYASSL_MSG("processing server hello done"); - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerHelloDone", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("ServerHelloDone", &ssl->timeoutInfo); - #endif - ssl->options.serverState = SERVER_HELLODONE_COMPLETE; - break; - - case finished: - CYASSL_MSG("processing finished"); - ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); - break; - -#ifndef NO_CYASSL_SERVER - case client_hello: - CYASSL_MSG("processing client hello"); - ret = DoClientHello(ssl, input, inOutIdx, size); - break; - - case client_key_exchange: - CYASSL_MSG("processing client key exchange"); - ret = DoClientKeyExchange(ssl, input, inOutIdx, size); - break; - -#if !defined(NO_RSA) || defined(HAVE_ECC) - case certificate_verify: - CYASSL_MSG("processing certificate verify"); - ret = DoCertificateVerify(ssl, input, inOutIdx, size); - break; -#endif /* !NO_RSA || HAVE_ECC */ - -#endif /* !NO_CYASSL_SERVER */ - - default: - CYASSL_MSG("Unknown handshake message type"); - ret = UNKNOWN_HANDSHAKE_TYPE; - break; - } - - CYASSL_LEAVE("DoHandShakeMsgType()", ret); - return ret; -} - - -static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 totalSz) -{ - byte type; - word32 size; - int ret = 0; - - CYASSL_ENTER("DoHandShakeMsg()"); - - if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0) - return PARSE_ERROR; - - ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); - - CYASSL_LEAVE("DoHandShakeMsg()", ret); - return ret; -} - - -#ifdef CYASSL_DTLS - -static INLINE int DtlsCheckWindow(DtlsState* state) -{ - word32 cur; - word32 next; - DtlsSeq window; - - if (state->curEpoch == state->nextEpoch) { - next = state->nextSeq; - window = state->window; - } - else if (state->curEpoch < state->nextEpoch) { - next = state->prevSeq; - window = state->prevWindow; - } - else { - return 0; - } - - cur = state->curSeq; - - if ((next > DTLS_SEQ_BITS) && (cur < next - DTLS_SEQ_BITS)) { - return 0; - } - else if ((cur < next) && (window & (1 << (next - cur - 1)))) { - return 0; - } - - return 1; -} - - -static INLINE int DtlsUpdateWindow(DtlsState* state) -{ - word32 cur; - word32* next; - DtlsSeq* window; - - if (state->curEpoch == state->nextEpoch) { - next = &state->nextSeq; - window = &state->window; - } - else { - next = &state->prevSeq; - window = &state->prevWindow; - } - - cur = state->curSeq; - - if (cur < *next) { - *window |= (1 << (*next - cur - 1)); - } - else { - *window <<= (1 + cur - *next); - *window |= 1; - *next = cur + 1; - } - - return 1; -} - - -static int DtlsMsgDrain(CYASSL* ssl) -{ - DtlsMsg* item = ssl->dtls_msg_list; - int ret = 0; - - /* While there is an item in the store list, and it is the expected - * message, and it is complete, and there hasn't been an error in the - * last messge... */ - while (item != NULL && - ssl->keys.dtls_expected_peer_handshake_number == item->seq && - item->fragSz == item->sz && - ret == 0) { - word32 idx = 0; - ssl->keys.dtls_expected_peer_handshake_number++; - ret = DoHandShakeMsgType(ssl, item->msg, - &idx, item->type, item->sz, item->sz); - ssl->dtls_msg_list = item->next; - DtlsMsgDelete(item, ssl->heap); - item = ssl->dtls_msg_list; - } - - return ret; -} - - -static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 totalSz) -{ - byte type; - word32 size; - word32 fragOffset, fragSz; - int ret = 0; - - CYASSL_ENTER("DoDtlsHandShakeMsg()"); - if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, - &size, &fragOffset, &fragSz) != 0) - return PARSE_ERROR; - - if (*inOutIdx + fragSz > totalSz) - return INCOMPLETE_DATA; - - /* Check the handshake sequence number first. If out of order, - * add the current message to the list. If the message is in order, - * but it is a fragment, add the current message to the list, then - * check the head of the list to see if it is complete, if so, pop - * it out as the current message. If the message is complete and in - * order, process it. Check the head of the list to see if it is in - * order, if so, process it. (Repeat until list exhausted.) If the - * head is out of order, return for more processing. - */ - if (ssl->keys.dtls_peer_handshake_number > - ssl->keys.dtls_expected_peer_handshake_number) { - /* Current message is out of order. It will get stored in the list. - * Storing also takes care of defragmentation. */ - ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, - ssl->keys.dtls_peer_handshake_number, input + *inOutIdx, - size, type, fragOffset, fragSz, ssl->heap); - *inOutIdx += fragSz; - ret = 0; - } - else if (ssl->keys.dtls_peer_handshake_number < - ssl->keys.dtls_expected_peer_handshake_number) { - /* Already saw this message and processed it. It can be ignored. */ - *inOutIdx += fragSz; - ret = 0; - } - else if (fragSz < size) { - /* Since this branch is in order, but fragmented, dtls_msg_list will be - * pointing to the message with this fragment in it. Check it to see - * if it is completed. */ - ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, - ssl->keys.dtls_peer_handshake_number, input + *inOutIdx, - size, type, fragOffset, fragSz, ssl->heap); - *inOutIdx += fragSz; - ret = 0; - if (ssl->dtls_msg_list != NULL && - ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) - ret = DtlsMsgDrain(ssl); - } - else { - /* This branch is in order next, and a complete message. */ - ssl->keys.dtls_expected_peer_handshake_number++; - ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); - if (ret == 0 && ssl->dtls_msg_list != NULL) - ret = DtlsMsgDrain(ssl); - } - - CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret); - return ret; -} -#endif - - -static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) -{ - if (verify) - return ssl->keys.peer_sequence_number++; - else - return ssl->keys.sequence_number++; -} - - -#ifdef HAVE_AEAD -static INLINE void AeadIncrementExpIV(CYASSL* ssl) -{ - int i; - for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) { - if (++ssl->keys.aead_exp_IV[i]) return; - } -} -#endif - - -static INLINE int Encrypt(CYASSL* ssl, byte* out, const byte* input, word16 sz) -{ - (void)out; - (void)input; - (void)sz; - - if (ssl->encrypt.setup == 0) { - CYASSL_MSG("Encrypt ciphers not setup"); - return ENCRYPT_ERROR; - } - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_ARC4 - case cyassl_rc4: - Arc4Process(ssl->encrypt.arc4, out, input, sz); - break; - #endif - - #ifdef BUILD_DES3 - case cyassl_triple_des: - return Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz); - #endif - - #ifdef BUILD_AES - case cyassl_aes: - return AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); - #endif - - #ifdef BUILD_AESGCM - case cyassl_aes_gcm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - const byte* additionalSrc = input - 5; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 0), - additional + AEAD_SEQ_OFFSET); - - /* Store the type, version. Unfortunately, they are in - * the input buffer ahead of the plaintext. */ - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - additionalSrc -= DTLS_HANDSHAKE_EXTRA; - #endif - XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3); - - /* Store the length of the plain text minus the explicit - * IV length minus the authentication tag size. */ - c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - additional + AEAD_LEN_OFFSET); - XMEMCPY(nonce, - ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ); - XMEMCPY(nonce + AEAD_IMP_IV_SZ, - ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); - AesGcmEncrypt(ssl->encrypt.aes, - out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ, - sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - nonce, AEAD_NONCE_SZ, - out + sz - ssl->specs.aead_mac_size, - ssl->specs.aead_mac_size, additional, - AEAD_AUTH_DATA_SZ); - AeadIncrementExpIV(ssl); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - } - break; - #endif - - #ifdef HAVE_AESCCM - case cyassl_aes_ccm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - const byte* additionalSrc = input - 5; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 0), - additional + AEAD_SEQ_OFFSET); - - /* Store the type, version. Unfortunately, they are in - * the input buffer ahead of the plaintext. */ - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - c16toa(ssl->keys.dtls_epoch, additional); - additionalSrc -= DTLS_HANDSHAKE_EXTRA; - } - #endif - XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3); - - /* Store the length of the plain text minus the explicit - * IV length minus the authentication tag size. */ - c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - additional + AEAD_LEN_OFFSET); - XMEMCPY(nonce, - ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ); - XMEMCPY(nonce + AEAD_IMP_IV_SZ, - ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); - AesCcmEncrypt(ssl->encrypt.aes, - out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ, - sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - nonce, AEAD_NONCE_SZ, - out + sz - ssl->specs.aead_mac_size, - ssl->specs.aead_mac_size, - additional, AEAD_AUTH_DATA_SZ); - AeadIncrementExpIV(ssl); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - - break; - } - #endif - - #ifdef HAVE_CAMELLIA - case cyassl_camellia: - CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz); - break; - #endif - - #ifdef HAVE_HC128 - case cyassl_hc128: - return Hc128_Process(ssl->encrypt.hc128, out, input, sz); - #endif - - #ifdef BUILD_RABBIT - case cyassl_rabbit: - return RabbitProcess(ssl->encrypt.rabbit, out, input, sz); - #endif - - #ifdef HAVE_NULL_CIPHER - case cyassl_cipher_null: - if (input != out) { - XMEMMOVE(out, input, sz); - } - break; - #endif - - default: - CYASSL_MSG("CyaSSL Encrypt programming error"); - return ENCRYPT_ERROR; - } - - return 0; -} - - - -static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, - word16 sz) -{ - (void)plain; - (void)input; - (void)sz; - - if (ssl->decrypt.setup == 0) { - CYASSL_MSG("Decrypt ciphers not setup"); - return DECRYPT_ERROR; - } - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_ARC4 - case cyassl_rc4: - Arc4Process(ssl->decrypt.arc4, plain, input, sz); - break; - #endif - - #ifdef BUILD_DES3 - case cyassl_triple_des: - return Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz); - #endif - - #ifdef BUILD_AES - case cyassl_aes: - return AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); - #endif - - #ifdef BUILD_AESGCM - case cyassl_aes_gcm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); - - additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; - additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; - additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; - - c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - additional + AEAD_LEN_OFFSET); - XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ); - XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ); - if (AesGcmDecrypt(ssl->decrypt.aes, - plain + AEAD_EXP_IV_SZ, - input + AEAD_EXP_IV_SZ, - sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - nonce, AEAD_NONCE_SZ, - input + sz - ssl->specs.aead_mac_size, - ssl->specs.aead_mac_size, - additional, AEAD_AUTH_DATA_SZ) < 0) { - SendAlert(ssl, alert_fatal, bad_record_mac); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - return VERIFY_MAC_ERROR; - } - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - break; - } - #endif - - #ifdef HAVE_AESCCM - case cyassl_aes_ccm: - { - byte additional[AES_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - - XMEMSET(additional, 0, AES_BLOCK_SIZE); - - /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - c16toa(ssl->keys.dtls_state.curEpoch, additional); - #endif - - additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; - additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; - additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; - - c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - additional + AEAD_LEN_OFFSET); - XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ); - XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ); - if (AesCcmDecrypt(ssl->decrypt.aes, - plain + AEAD_EXP_IV_SZ, - input + AEAD_EXP_IV_SZ, - sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, - nonce, AEAD_NONCE_SZ, - input + sz - ssl->specs.aead_mac_size, - ssl->specs.aead_mac_size, - additional, AEAD_AUTH_DATA_SZ) < 0) { - SendAlert(ssl, alert_fatal, bad_record_mac); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - return VERIFY_MAC_ERROR; - } - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - break; - } - #endif - - #ifdef HAVE_CAMELLIA - case cyassl_camellia: - CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz); - break; - #endif - - #ifdef HAVE_HC128 - case cyassl_hc128: - return Hc128_Process(ssl->decrypt.hc128, plain, input, sz); - #endif - - #ifdef BUILD_RABBIT - case cyassl_rabbit: - return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); - #endif - - #ifdef HAVE_NULL_CIPHER - case cyassl_cipher_null: - if (input != plain) { - XMEMMOVE(plain, input, sz); - } - break; - #endif - - default: - CYASSL_MSG("CyaSSL Decrypt programming error"); - return DECRYPT_ERROR; - } - return 0; -} - - -/* check cipher text size for sanity */ -static int SanityCheckCipherText(CYASSL* ssl, word32 encryptSz) -{ -#ifdef HAVE_TRUNCATED_HMAC - word32 minLength = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ - : ssl->specs.hash_size; -#else - word32 minLength = ssl->specs.hash_size; /* covers stream */ -#endif - - if (ssl->specs.cipher_type == block) { - if (encryptSz % ssl->specs.block_size) { - CYASSL_MSG("Block ciphertext not block size"); - return SANITY_CIPHER_E; - } - - minLength++; /* pad byte */ - - if (ssl->specs.block_size > minLength) - minLength = ssl->specs.block_size; - - if (ssl->options.tls1_1) - minLength += ssl->specs.block_size; /* explicit IV */ - } - else if (ssl->specs.cipher_type == aead) { - minLength = ssl->specs.aead_mac_size + AEAD_EXP_IV_SZ; - /* explicit IV + authTag size */ - } - - if (encryptSz < minLength) { - CYASSL_MSG("Ciphertext not minimum size"); - return SANITY_CIPHER_E; - } - - return 0; -} - - -#ifndef NO_OLD_TLS - -static INLINE void Md5Rounds(int rounds, const byte* data, int sz) -{ - Md5 md5; - int i; - - InitMd5(&md5); - - for (i = 0; i < rounds; i++) - Md5Update(&md5, data, sz); -} - - - -/* do a dummy sha round */ -static INLINE void ShaRounds(int rounds, const byte* data, int sz) -{ - Sha sha; - int i; - - InitSha(&sha); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) - ShaUpdate(&sha, data, sz); -} -#endif - - -#ifndef NO_SHA256 - -static INLINE void Sha256Rounds(int rounds, const byte* data, int sz) -{ - Sha256 sha256; - int i; - - InitSha256(&sha256); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) { - Sha256Update(&sha256, data, sz); - /* no error check on purpose, dummy round */ - } - -} - -#endif - - -#ifdef CYASSL_SHA384 - -static INLINE void Sha384Rounds(int rounds, const byte* data, int sz) -{ - Sha384 sha384; - int i; - - InitSha384(&sha384); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) { - Sha384Update(&sha384, data, sz); - /* no error check on purpose, dummy round */ - } -} - -#endif - - -#ifdef CYASSL_SHA512 - -static INLINE void Sha512Rounds(int rounds, const byte* data, int sz) -{ - Sha512 sha512; - int i; - - InitSha512(&sha512); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) { - Sha512Update(&sha512, data, sz); - /* no error check on purpose, dummy round */ - } -} - -#endif - - -#ifdef CYASSL_RIPEMD - -static INLINE void RmdRounds(int rounds, const byte* data, int sz) -{ - RipeMd ripemd; - int i; - - InitRipeMd(&ripemd); - - for (i = 0; i < rounds; i++) - RipeMdUpdate(&ripemd, data, sz); -} - -#endif - - -/* Do dummy rounds */ -static INLINE void DoRounds(int type, int rounds, const byte* data, int sz) -{ - switch (type) { - - case no_mac : - break; - -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - case md5_mac : - Md5Rounds(rounds, data, sz); - break; -#endif - -#ifndef NO_SHA - case sha_mac : - ShaRounds(rounds, data, sz); - break; -#endif -#endif - -#ifndef NO_SHA256 - case sha256_mac : - Sha256Rounds(rounds, data, sz); - break; -#endif - -#ifdef CYASSL_SHA384 - case sha384_mac : - Sha384Rounds(rounds, data, sz); - break; -#endif - -#ifdef CYASSL_SHA512 - case sha512_mac : - Sha512Rounds(rounds, data, sz); - break; -#endif - -#ifdef CYASSL_RIPEMD - case rmd_mac : - RmdRounds(rounds, data, sz); - break; -#endif - - default: - CYASSL_MSG("Bad round type"); - break; - } -} - - -/* do number of compression rounds on dummy data */ -static INLINE void CompressRounds(CYASSL* ssl, int rounds, const byte* dummy) -{ - if (rounds) - DoRounds(ssl->specs.mac_algorithm, rounds, dummy, COMPRESS_LOWER); -} - - -/* check all length bytes for equality, return 0 on success */ -static int ConstantCompare(const byte* a, const byte* b, int length) -{ - int i; - int good = 0; - int bad = 0; - - for (i = 0; i < length; i++) { - if (a[i] == b[i]) - good++; - else - bad++; - } - - if (good == length) - return 0; - else - return 0 - bad; /* compare failed */ -} - - -/* check all length bytes for the pad value, return 0 on success */ -static int PadCheck(const byte* input, byte pad, int length) -{ - int i; - int good = 0; - int bad = 0; - - for (i = 0; i < length; i++) { - if (input[i] == pad) - good++; - else - bad++; - } - - if (good == length) - return 0; - else - return 0 - bad; /* pad check failed */ -} - - -/* get compression extra rounds */ -static INLINE int GetRounds(int pLen, int padLen, int t) -{ - int roundL1 = 1; /* round up flags */ - int roundL2 = 1; - - int L1 = COMPRESS_CONSTANT + pLen - t; - int L2 = COMPRESS_CONSTANT + pLen - padLen - 1 - t; - - L1 -= COMPRESS_UPPER; - L2 -= COMPRESS_UPPER; - - if ( (L1 % COMPRESS_LOWER) == 0) - roundL1 = 0; - if ( (L2 % COMPRESS_LOWER) == 0) - roundL2 = 0; - - L1 /= COMPRESS_LOWER; - L2 /= COMPRESS_LOWER; - - L1 += roundL1; - L2 += roundL2; - - return L1 - L2; -} - - -/* timing resistant pad/verify check, return 0 on success */ -static int TimingPadVerify(CYASSL* ssl, const byte* input, int padLen, int t, - int pLen, int content) -{ - byte verify[MAX_DIGEST_SIZE]; - byte dummy[MAX_PAD_SIZE]; - int ret = 0; - - XMEMSET(dummy, 1, sizeof(dummy)); - - if ( (t + padLen + 1) > pLen) { - CYASSL_MSG("Plain Len not long enough for pad/mac"); - PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE); - ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */ - ConstantCompare(verify, input + pLen - t, t); - - return VERIFY_MAC_ERROR; - } - - if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) { - CYASSL_MSG("PadCheck failed"); - PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); - ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */ - ConstantCompare(verify, input + pLen - t, t); - - return VERIFY_MAC_ERROR; - } - - PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); - ret = ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, content, 1); - - CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy); - - if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) { - CYASSL_MSG("Verify MAC compare failed"); - return VERIFY_MAC_ERROR; - } - - if (ret != 0) - return VERIFY_MAC_ERROR; - return 0; -} - - -int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) -{ - word32 msgSz = ssl->keys.encryptSz; - word32 idx = *inOutIdx; - int dataSz; - int ivExtra = 0; - byte* rawData = input + idx; /* keep current for hmac */ -#ifdef HAVE_LIBZ - byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; -#endif - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - CYASSL_MSG("Received App data before handshake complete"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - if (ssl->specs.cipher_type == block) { - if (ssl->options.tls1_1) - ivExtra = ssl->specs.block_size; - } - else if (ssl->specs.cipher_type == aead) { - ivExtra = AEAD_EXP_IV_SZ; - } - - dataSz = msgSz - ivExtra - ssl->keys.padSz; - if (dataSz < 0) { - CYASSL_MSG("App data buffer error, malicious input?"); - return BUFFER_ERROR; - } - - /* read data */ - if (dataSz) { - int rawSz = dataSz; /* keep raw size for idx adjustment */ - -#ifdef HAVE_LIBZ - if (ssl->options.usingCompression) { - dataSz = myDeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp)); - if (dataSz < 0) return dataSz; - } -#endif - idx += rawSz; - - ssl->buffers.clearOutputBuffer.buffer = rawData; - ssl->buffers.clearOutputBuffer.length = dataSz; - } - - idx += ssl->keys.padSz; - -#ifdef HAVE_LIBZ - /* decompress could be bigger, overwrite after verify */ - if (ssl->options.usingCompression) - XMEMMOVE(rawData, decomp, dataSz); -#endif - - *inOutIdx = idx; - return 0; -} - - -/* process alert, return level */ -static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type, - word32 totalSz) -{ - byte level; - byte code; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("Alert", &ssl->handShakeInfo); - if (ssl->toInfoOn) - /* add record header back on to info + 2 byte level, data */ - AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx - - RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap); - #endif - - /* make sure can read the message */ - if (*inOutIdx + ALERT_SIZE > totalSz) - return BUFFER_E; - - level = input[(*inOutIdx)++]; - code = input[(*inOutIdx)++]; - ssl->alert_history.last_rx.code = code; - ssl->alert_history.last_rx.level = level; - *type = code; - if (level == alert_fatal) { - ssl->options.isClosed = 1; /* Don't send close_notify */ - } - - CYASSL_MSG("Got alert"); - if (*type == close_notify) { - CYASSL_MSG(" close notify"); - ssl->options.closeNotify = 1; - } - CYASSL_ERROR(*type); - - if (ssl->keys.encryptionOn) { - if (*inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz; - } - - return level; -} - -static int GetInputData(CYASSL *ssl, word32 size) -{ - int in; - int inSz; - int maxLength; - int usedLength; - int dtlsExtra = 0; - - - /* check max input length */ - usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx; - maxLength = ssl->buffers.inputBuffer.bufferSize - usedLength; - inSz = (int)(size - usedLength); /* from last partial read */ - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if (size < ssl->dtls_expected_rx) - dtlsExtra = (int)(ssl->dtls_expected_rx - size); - inSz = ssl->dtls_expected_rx; - } -#endif - - if (inSz > maxLength) { - if (GrowInputBuffer(ssl, size + dtlsExtra, usedLength) < 0) - return MEMORY_E; - } - - if (inSz <= 0) - return BUFFER_ERROR; - - /* Put buffer data at start if not there */ - if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0) - XMEMMOVE(ssl->buffers.inputBuffer.buffer, - ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, - usedLength); - - /* remove processed data */ - ssl->buffers.inputBuffer.idx = 0; - ssl->buffers.inputBuffer.length = usedLength; - - /* read data from network */ - do { - in = Receive(ssl, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.length, - inSz); - if (in == -1) - return SOCKET_ERROR_E; - - if (in == WANT_READ) - return WANT_READ; - - if (in > inSz) - return RECV_OVERFLOW_E; - - ssl->buffers.inputBuffer.length += in; - inSz -= in; - - } while (ssl->buffers.inputBuffer.length < size); - - return 0; -} - - -static INLINE int VerifyMac(CYASSL* ssl, const byte* input, word32 msgSz, - int content, word32* padSz) -{ - int ivExtra = 0; - int ret; - word32 pad = 0; - word32 padByte = 0; -#ifdef HAVE_TRUNCATED_HMAC - word32 digestSz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ - : ssl->specs.hash_size; -#else - word32 digestSz = ssl->specs.hash_size; -#endif - byte verify[MAX_DIGEST_SIZE]; - - if (ssl->specs.cipher_type == block) { - if (ssl->options.tls1_1) - ivExtra = ssl->specs.block_size; - pad = *(input + msgSz - ivExtra - 1); - padByte = 1; - - if (ssl->options.tls) { - ret = TimingPadVerify(ssl, input, pad, digestSz, msgSz - ivExtra, - content); - if (ret != 0) - return ret; - } - else { /* sslv3, some implementations have bad padding, but don't - * allow bad read */ - int badPadLen = 0; - byte dummy[MAX_PAD_SIZE]; - - XMEMSET(dummy, 1, sizeof(dummy)); - - if (pad > (msgSz - digestSz - 1)) { - CYASSL_MSG("Plain Len not long enough for pad/mac"); - pad = 0; /* no bad read */ - badPadLen = 1; - } - PadCheck(dummy, (byte)pad, MAX_PAD_SIZE); /* timing only */ - ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, - content, 1); - if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1, - digestSz) != 0) - return VERIFY_MAC_ERROR; - if (ret != 0 || badPadLen) - return VERIFY_MAC_ERROR; - } - } - else if (ssl->specs.cipher_type == stream) { - ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1); - if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){ - return VERIFY_MAC_ERROR; - } - if (ret != 0) - return VERIFY_MAC_ERROR; - } - - if (ssl->specs.cipher_type == aead) { - *padSz = ssl->specs.aead_mac_size; - } - else { - *padSz = digestSz + pad + padByte; - } - - return 0; -} - - -/* process input requests, return 0 is done, 1 is call again to complete, and - negative number is error */ -int ProcessReply(CYASSL* ssl) -{ - int ret = 0, type, readSz; - int atomicUser = 0; - word32 startIdx = 0; -#ifndef NO_CYASSL_SERVER - byte b0, b1; -#endif -#ifdef CYASSL_DTLS - int used; -#endif - -#ifdef ATOMIC_USER - if (ssl->ctx->DecryptVerifyCb) - atomicUser = 1; -#endif - - if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE){ - CYASSL_MSG("ProcessReply retry in error state, not allowed"); - return ssl->error; - } - - for (;;) { - switch (ssl->options.processReply) { - - /* in the CYASSL_SERVER case, get the first byte for detecting - * old client hello */ - case doProcessInit: - - readSz = RECORD_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - readSz = DTLS_RECORD_HEADER_SZ; - #endif - - /* get header or return error */ - if (!ssl->options.dtls) { - if ((ret = GetInputData(ssl, readSz)) < 0) - return ret; - } else { - #ifdef CYASSL_DTLS - /* read ahead may already have header */ - used = ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx; - if (used < readSz) - if ((ret = GetInputData(ssl, readSz)) < 0) - return ret; - #endif - } - -#ifndef NO_CYASSL_SERVER - - /* see if sending SSLv2 client hello */ - if ( ssl->options.side == CYASSL_SERVER_END && - ssl->options.clientState == NULL_STATE && - ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx] - != handshake) { - ssl->options.processReply = runProcessOldClientHello; - - /* how many bytes need ProcessOldClientHello */ - b0 = - ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; - b1 = - ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; - ssl->curSize = (word16)(((b0 & 0x7f) << 8) | b1); - } - else { - ssl->options.processReply = getRecordLayerHeader; - continue; - } - - /* in the CYASSL_SERVER case, run the old client hello */ - case runProcessOldClientHello: - - /* get sz bytes or return error */ - if (!ssl->options.dtls) { - if ((ret = GetInputData(ssl, ssl->curSize)) < 0) - return ret; - } else { - #ifdef CYASSL_DTLS - /* read ahead may already have */ - used = ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx; - if (used < ssl->curSize) - if ((ret = GetInputData(ssl, ssl->curSize)) < 0) - return ret; - #endif /* CYASSL_DTLS */ - } - - ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx, - ssl->curSize); - if (ret < 0) - return ret; - - else if (ssl->buffers.inputBuffer.idx == - ssl->buffers.inputBuffer.length) { - ssl->options.processReply = doProcessInit; - return 0; - } - -#endif /* NO_CYASSL_SERVER */ - - /* get the record layer header */ - case getRecordLayerHeader: - - ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, - &ssl->curRL, &ssl->curSize); -#ifdef CYASSL_DTLS - if (ssl->options.dtls && ret == SEQUENCE_ERROR) { - ssl->options.processReply = doProcessInit; - ssl->buffers.inputBuffer.length = 0; - ssl->buffers.inputBuffer.idx = 0; - continue; - } -#endif - if (ret != 0) - return ret; - - ssl->options.processReply = getData; - - /* retrieve record layer data */ - case getData: - - /* get sz bytes or return error */ - if (!ssl->options.dtls) { - if ((ret = GetInputData(ssl, ssl->curSize)) < 0) - return ret; - } else { -#ifdef CYASSL_DTLS - /* read ahead may already have */ - used = ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx; - if (used < ssl->curSize) - if ((ret = GetInputData(ssl, ssl->curSize)) < 0) - return ret; -#endif - } - - ssl->options.processReply = runProcessingOneMessage; - startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */ - - /* the record layer is here */ - case runProcessingOneMessage: - - #ifdef CYASSL_DTLS - if (ssl->options.dtls && - ssl->keys.dtls_state.curEpoch < ssl->keys.dtls_state.nextEpoch) - ssl->keys.decryptedCur = 1; - #endif - - if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0) - { - ret = SanityCheckCipherText(ssl, ssl->curSize); - if (ret < 0) - return ret; - - if (atomicUser) { - #ifdef ATOMIC_USER - ret = ssl->ctx->DecryptVerifyCb(ssl, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->curSize, ssl->curRL.type, 1, - &ssl->keys.padSz, ssl->DecryptVerifyCtx); - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) - ssl->buffers.inputBuffer.idx += ssl->specs.block_size; - /* go past TLSv1.1 IV */ - if (ssl->specs.cipher_type == aead) - ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ; - #endif /* ATOMIC_USER */ - } - else { - ret = Decrypt(ssl, ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->curSize); - if (ret < 0) { - CYASSL_ERROR(ret); - return DECRYPT_ERROR; - } - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) - ssl->buffers.inputBuffer.idx += ssl->specs.block_size; - /* go past TLSv1.1 IV */ - if (ssl->specs.cipher_type == aead) - ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ; - - ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->curSize, ssl->curRL.type, - &ssl->keys.padSz); - } - if (ret < 0) { - CYASSL_ERROR(ret); - return DECRYPT_ERROR; - } - ssl->keys.encryptSz = ssl->curSize; - ssl->keys.decryptedCur = 1; - } - - if (ssl->options.dtls) { - #ifdef CYASSL_DTLS - DtlsUpdateWindow(&ssl->keys.dtls_state); - #endif /* CYASSL_DTLS */ - } - - CYASSL_MSG("received record layer msg"); - - switch (ssl->curRL.type) { - case handshake : - /* debugging in DoHandShakeMsg */ - if (!ssl->options.dtls) { - ret = DoHandShakeMsg(ssl, - ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.length); - } - else { -#ifdef CYASSL_DTLS - ret = DoDtlsHandShakeMsg(ssl, - ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.length); -#endif - } - if (ret != 0) - return ret; - break; - - case change_cipher_spec: - CYASSL_MSG("got CHANGE CIPHER SPEC"); - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ChangeCipher", &ssl->handShakeInfo); - /* add record header back on info */ - if (ssl->toInfoOn) { - AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ, - 1 + RECORD_HEADER_SZ, ssl->heap); - AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); - } - #endif - - if (ssl->curSize != 1) { - CYASSL_MSG("Malicious or corrupted ChangeCipher msg"); - return LENGTH_ERROR; - } - #ifndef NO_CERTS - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.verifyPeer && - ssl->options.havePeerCert) - if (!ssl->options.havePeerVerify) { - CYASSL_MSG("client didn't send cert verify"); - return NO_PEER_VERIFY; - } - #endif - - - ssl->buffers.inputBuffer.idx++; - ssl->keys.encryptionOn = 1; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - DtlsPoolReset(ssl); - ssl->keys.dtls_state.nextEpoch++; - ssl->keys.dtls_state.nextSeq = 0; - } - #endif - - #ifdef HAVE_LIBZ - if (ssl->options.usingCompression) - if ( (ret = InitStreams(ssl)) != 0) - return ret; - #endif - if (ssl->options.resuming && ssl->options.side == - CYASSL_CLIENT_END) - ret = BuildFinished(ssl, &ssl->verifyHashes, server); - else if (!ssl->options.resuming && ssl->options.side == - CYASSL_SERVER_END) - ret = BuildFinished(ssl, &ssl->verifyHashes, client); - if (ret != 0) - return ret; - break; - - case application_data: - CYASSL_MSG("got app DATA"); - if ((ret = DoApplicationData(ssl, - ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx)) - != 0) { - CYASSL_ERROR(ret); - return ret; - } - break; - - case alert: - CYASSL_MSG("got ALERT!"); - ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, &type, - ssl->buffers.inputBuffer.length); - if (ret == alert_fatal) - return FATAL_ERROR; - else if (ret < 0) - return ret; - - /* catch warnings that are handled as errors */ - if (type == close_notify) - return ssl->error = ZERO_RETURN; - - if (type == decrypt_error) - return FATAL_ERROR; - break; - - default: - CYASSL_ERROR(UNKNOWN_RECORD_TYPE); - return UNKNOWN_RECORD_TYPE; - } - - ssl->options.processReply = doProcessInit; - - /* input exhausted? */ - if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length) - return 0; - /* more messages per record */ - else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) { - CYASSL_MSG("More messages in record"); - #ifdef CYASSL_DTLS - /* read-ahead but dtls doesn't bundle messages per record */ - if (ssl->options.dtls) { - ssl->options.processReply = doProcessInit; - continue; - } - #endif - ssl->options.processReply = runProcessingOneMessage; - continue; - } - /* more records */ - else { - CYASSL_MSG("More records in input"); - ssl->options.processReply = doProcessInit; - continue; - } - - default: - CYASSL_MSG("Bad process input state, programming error"); - return INPUT_CASE_ERROR; - } - } -} - - -int SendChangeCipher(CYASSL* ssl) -{ - byte *output; - int sendSz = RECORD_HEADER_SZ + ENUM_LEN; - int idx = RECORD_HEADER_SZ; - int ret; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA; - idx += DTLS_RECORD_EXTRA; - } - #endif - - /* check for avalaible size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddRecordHeader(output, 1, change_cipher_spec, ssl); - - output[idx] = 1; /* turn it on */ - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz, - ssl->heap); - #endif - ssl->buffers.outputBuffer.length += sendSz; - - if (ssl->options.groupMessages) - return 0; - #ifdef CYASSL_DTLS - else if (ssl->options.dtls) { - /* If using DTLS, force the ChangeCipherSpec message to be in the - * same datagram as the finished message. */ - return 0; - } - #endif - else - return SendBuffered(ssl); -} - - -#ifndef NO_OLD_TLS -static int SSL_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz, - int content, int verify) -{ - byte result[MAX_DIGEST_SIZE]; - word32 digestSz = ssl->specs.hash_size; /* actual sizes */ - word32 padSz = ssl->specs.pad_size; - int ret = 0; - - Md5 md5; - Sha sha; - - /* data */ - byte seq[SEQ_SZ]; - byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */ - const byte* macSecret = CyaSSL_GetMacSecret(ssl, verify); - - XMEMSET(seq, 0, SEQ_SZ); - conLen[0] = (byte)content; - c16toa((word16)sz, &conLen[ENUM_LEN]); - c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]); - - if (ssl->specs.mac_algorithm == md5_mac) { - InitMd5(&md5); - /* inner */ - Md5Update(&md5, macSecret, digestSz); - Md5Update(&md5, PAD1, padSz); - Md5Update(&md5, seq, SEQ_SZ); - Md5Update(&md5, conLen, sizeof(conLen)); - /* in buffer */ - Md5Update(&md5, in, sz); - Md5Final(&md5, result); - /* outer */ - Md5Update(&md5, macSecret, digestSz); - Md5Update(&md5, PAD2, padSz); - Md5Update(&md5, result, digestSz); - Md5Final(&md5, digest); - } - else { - ret = InitSha(&sha); - if (ret != 0) - return ret; - /* inner */ - ShaUpdate(&sha, macSecret, digestSz); - ShaUpdate(&sha, PAD1, padSz); - ShaUpdate(&sha, seq, SEQ_SZ); - ShaUpdate(&sha, conLen, sizeof(conLen)); - /* in buffer */ - ShaUpdate(&sha, in, sz); - ShaFinal(&sha, result); - /* outer */ - ShaUpdate(&sha, macSecret, digestSz); - ShaUpdate(&sha, PAD2, padSz); - ShaUpdate(&sha, result, digestSz); - ShaFinal(&sha, digest); - } - return 0; -} - -#ifndef NO_CERTS -static void BuildMD5_CertVerify(CYASSL* ssl, byte* digest) -{ - byte md5_result[MD5_DIGEST_SIZE]; - - /* make md5 inner */ - Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); - Md5Update(&ssl->hashMd5, PAD1, PAD_MD5); - Md5Final(&ssl->hashMd5, md5_result); - - /* make md5 outer */ - Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); - Md5Update(&ssl->hashMd5, PAD2, PAD_MD5); - Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE); - - Md5Final(&ssl->hashMd5, digest); -} - - -static void BuildSHA_CertVerify(CYASSL* ssl, byte* digest) -{ - byte sha_result[SHA_DIGEST_SIZE]; - - /* make sha inner */ - ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); - ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA); - ShaFinal(&ssl->hashSha, sha_result); - - /* make sha outer */ - ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); - ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA); - ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE); - - ShaFinal(&ssl->hashSha, digest); -} -#endif /* NO_CERTS */ -#endif /* NO_OLD_TLS */ - - -#ifndef NO_CERTS - -static int BuildCertHashes(CYASSL* ssl, Hashes* hashes) -{ - /* store current states, building requires get_digest which resets state */ - #ifndef NO_OLD_TLS - Md5 md5 = ssl->hashMd5; - Sha sha = ssl->hashSha; - #endif - #ifndef NO_SHA256 - Sha256 sha256 = ssl->hashSha256; - #endif - #ifdef CYASSL_SHA384 - Sha384 sha384 = ssl->hashSha384; - #endif - - if (ssl->options.tls) { -#if ! defined( NO_OLD_TLS ) - Md5Final(&ssl->hashMd5, hashes->md5); - ShaFinal(&ssl->hashSha, hashes->sha); -#endif - if (IsAtLeastTLSv1_2(ssl)) { - int ret; - - #ifndef NO_SHA256 - ret = Sha256Final(&ssl->hashSha256, hashes->sha256); - if (ret != 0) - return ret; - #endif - #ifdef CYASSL_SHA384 - ret = Sha384Final(&ssl->hashSha384, hashes->sha384); - if (ret != 0) - return ret; - #endif - } - } -#if ! defined( NO_OLD_TLS ) - else { - BuildMD5_CertVerify(ssl, hashes->md5); - BuildSHA_CertVerify(ssl, hashes->sha); - } - - /* restore */ - ssl->hashMd5 = md5; - ssl->hashSha = sha; -#endif - if (IsAtLeastTLSv1_2(ssl)) { - #ifndef NO_SHA256 - ssl->hashSha256 = sha256; - #endif - #ifdef CYASSL_SHA384 - ssl->hashSha384 = sha384; - #endif - } - - return 0; -} - -#endif /* CYASSL_LEANPSK */ - -/* Build SSL Message, encrypted */ -static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz, - int type) -{ -#ifdef HAVE_TRUNCATED_HMAC - word32 digestSz = min(ssl->specs.hash_size, - ssl->truncated_hmac ? TRUNCATED_HMAC_SZ : ssl->specs.hash_size); -#else - word32 digestSz = ssl->specs.hash_size; -#endif - word32 sz = RECORD_HEADER_SZ + inSz + digestSz; - word32 pad = 0, i; - word32 idx = RECORD_HEADER_SZ; - word32 ivSz = 0; /* TLSv1.1 IV */ - word32 headerSz = RECORD_HEADER_SZ; - word16 size; - byte iv[AES_BLOCK_SIZE]; /* max size */ - int ret = 0; - int atomicUser = 0; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sz += DTLS_RECORD_EXTRA; - idx += DTLS_RECORD_EXTRA; - headerSz += DTLS_RECORD_EXTRA; - } -#endif - -#ifdef ATOMIC_USER - if (ssl->ctx->MacEncryptCb) - atomicUser = 1; -#endif - - if (ssl->specs.cipher_type == block) { - word32 blockSz = ssl->specs.block_size; - if (ssl->options.tls1_1) { - ivSz = blockSz; - sz += ivSz; - - ret = RNG_GenerateBlock(ssl->rng, iv, ivSz); - if (ret != 0) - return ret; - - } - sz += 1; /* pad byte */ - pad = (sz - headerSz) % blockSz; - pad = blockSz - pad; - sz += pad; - } - -#ifdef HAVE_AEAD - if (ssl->specs.cipher_type == aead) { - ivSz = AEAD_EXP_IV_SZ; - sz += (ivSz + ssl->specs.aead_mac_size - digestSz); - XMEMCPY(iv, ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); - } -#endif - size = (word16)(sz - headerSz); /* include mac and digest */ - AddRecordHeader(output, size, (byte)type, ssl); - - /* write to output */ - if (ivSz) { - XMEMCPY(output + idx, iv, min(ivSz, sizeof(iv))); - idx += ivSz; - } - XMEMCPY(output + idx, input, inSz); - idx += inSz; - - if (type == handshake) { - ret = HashOutput(ssl, output, headerSz + inSz, ivSz); - if (ret != 0) - return ret; - } - - if (ssl->specs.cipher_type == block) { - word32 tmpIdx = idx + digestSz; - - for (i = 0; i <= pad; i++) - output[tmpIdx++] = (byte)pad; /* pad byte gets pad value too */ - } - - if (atomicUser) { /* User Record Layer Callback handling */ -#ifdef ATOMIC_USER - if ( (ret = ssl->ctx->MacEncryptCb(ssl, output + idx, - output + headerSz + ivSz, inSz, type, 0, - output + headerSz, output + headerSz, size, - ssl->MacEncryptCtx)) != 0) - return ret; -#endif - } - else { - if (ssl->specs.cipher_type != aead) { -#ifdef HAVE_TRUNCATED_HMAC - if (ssl->truncated_hmac && ssl->specs.hash_size > digestSz) { - byte hmac[MAX_DIGEST_SIZE]; - - ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz, - type, 0); - XMEMCPY(output + idx, hmac, digestSz); - } else -#endif - ret = ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, - type, 0); - } - if (ret != 0) - return ret; - - if ( (ret = Encrypt(ssl, output + headerSz, output+headerSz,size)) != 0) - return ret; - } - - return sz; -} - - -int SendFinished(CYASSL* ssl) -{ - int sendSz, - finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : - FINISHED_SZ; - byte input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ]; /* max */ - byte *output; - Hashes* hashes; - int ret; - int headerSz = HANDSHAKE_HEADER_SZ; - - #ifdef CYASSL_DTLS - word32 sequence_number = ssl->keys.dtls_sequence_number; - word16 epoch = ssl->keys.dtls_epoch; - #endif - - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0) - return ret; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - /* Send Finished message with the next epoch, but don't commit that - * change until the other end confirms its reception. */ - headerSz += DTLS_HANDSHAKE_EXTRA; - ssl->keys.dtls_epoch++; - ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */ - } - #endif - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHandShakeHeader(input, finishedSz, finished, ssl); - - /* make finished hashes */ - hashes = (Hashes*)&input[headerSz]; - ret = BuildFinished(ssl, hashes, - ssl->options.side == CYASSL_CLIENT_END ? client : server); - if (ret != 0) return ret; - - sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake); - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - ssl->keys.dtls_epoch = epoch; - ssl->keys.dtls_sequence_number = sequence_number; - } - #endif - - if (sendSz < 0) - return BUILD_MSG_ERROR; - - if (!ssl->options.resuming) { -#ifndef NO_SESSION_CACHE - AddSession(ssl); /* just try */ -#endif - if (ssl->options.side == CYASSL_CLIENT_END) { - ret = BuildFinished(ssl, &ssl->verifyHashes, server); - if (ret != 0) return ret; - } - else { - ssl->options.handShakeState = HANDSHAKE_DONE; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - /* Other side will soon receive our Finished, go to next - * epoch. */ - ssl->keys.dtls_epoch++; - ssl->keys.dtls_sequence_number = 1; - } - #endif - } - } - else { - if (ssl->options.side == CYASSL_CLIENT_END) { - ssl->options.handShakeState = HANDSHAKE_DONE; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - /* Other side will soon receive our Finished, go to next - * epoch. */ - ssl->keys.dtls_epoch++; - ssl->keys.dtls_sequence_number = 1; - } - #endif - } - else { - ret = BuildFinished(ssl, &ssl->verifyHashes, client); - if (ret != 0) return ret; - } - } - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz, - ssl->heap); - #endif - - ssl->buffers.outputBuffer.length += sendSz; - - return SendBuffered(ssl); -} - -#ifndef NO_CERTS -int SendCertificate(CYASSL* ssl) -{ - int sendSz, length, ret = 0; - word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - word32 certSz, listSz; - byte* output = 0; - - if (ssl->options.usingPSK_cipher) return 0; /* not needed */ - - if (ssl->options.sendVerify == SEND_BLANK_CERT) { - certSz = 0; - length = CERT_HEADER_SZ; - listSz = 0; - } - else { - certSz = ssl->buffers.certificate.length; - /* list + cert size */ - length = certSz + 2 * CERT_HEADER_SZ; - listSz = certSz + CERT_HEADER_SZ; - - /* may need to send rest of chain, already has leading size(s) */ - if (ssl->buffers.certChain.buffer) { - length += ssl->buffers.certChain.length; - listSz += ssl->buffers.certChain.length; - } - } - sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, certificate, ssl); - - /* list total */ - c32to24(listSz, output + i); - i += CERT_HEADER_SZ; - - /* member */ - if (certSz) { - c32to24(certSz, output + i); - i += CERT_HEADER_SZ; - XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz); - i += certSz; - - /* send rest of chain? */ - if (ssl->buffers.certChain.buffer) { - XMEMCPY(output + i, ssl->buffers.certChain.buffer, - ssl->buffers.certChain.length); - /* if add more to output adjust i - i += ssl->buffers.certChain.length; */ - } - } - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, - ssl->heap); - #endif - - if (ssl->options.side == CYASSL_SERVER_END) - ssl->options.serverState = SERVER_CERT_COMPLETE; - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); -} - - -int SendCertificateRequest(CYASSL* ssl) -{ - byte *output; - int ret; - int sendSz; - word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - - int typeTotal = 1; /* only rsa for now */ - int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ - - if (IsAtLeastTLSv1_2(ssl)) - reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; - - if (ssl->options.usingPSK_cipher) return 0; /* not needed */ - - sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, reqSz, certificate_request, ssl); - - /* write to output */ - output[i++] = (byte)typeTotal; /* # of types */ - output[i++] = rsa_sign; - - /* supported hash/sig */ - if (IsAtLeastTLSv1_2(ssl)) { - c16toa(ssl->suites->hashSigAlgoSz, &output[i]); - i += LENGTH_SZ; - - XMEMCPY(&output[i], - ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz); - i += ssl->suites->hashSigAlgoSz; - } - - c16toa(0, &output[i]); /* auth's */ - /* if add more to output, adjust i - i += REQ_HEADER_SZ; */ - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("CertificateRequest", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output, - sendSz, ssl->heap); - #endif - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); -} -#endif /* !NO_CERTS */ - - -int SendData(CYASSL* ssl, const void* data, int sz) -{ - int sent = 0, /* plainText size */ - sendSz, - ret; - - if (ssl->error == WANT_WRITE) - ssl->error = 0; - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - int err; - CYASSL_MSG("handshake not complete, trying to finish"); - if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) - return err; - } - - /* last time system socket output buffer was full, try again to send */ - if (ssl->buffers.outputBuffer.length > 0) { - CYASSL_MSG("output buffer was full, trying to send again"); - if ( (ssl->error = SendBuffered(ssl)) < 0) { - CYASSL_ERROR(ssl->error); - if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset) - return 0; /* peer reset */ - return ssl->error; - } - else { - /* advance sent to previous sent + plain size just sent */ - sent = ssl->buffers.prevSent + ssl->buffers.plainSz; - CYASSL_MSG("sent write buffered data"); - } - } - - for (;;) { -#ifdef HAVE_MAX_FRAGMENT - int len = min(sz - sent, min(ssl->max_fragment, OUTPUT_RECORD_SIZE)); -#else - int len = min(sz - sent, OUTPUT_RECORD_SIZE); -#endif - byte* out; - byte* sendBuffer = (byte*)data + sent; /* may switch on comp */ - int buffSz = len; /* may switch on comp */ -#ifdef HAVE_LIBZ - byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; -#endif - - if (sent == sz) break; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - len = min(len, MAX_UDP_SIZE); - buffSz = len; - } -#endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, len + COMP_EXTRA + - MAX_MSG_EXTRA)) != 0) - return ssl->error = ret; - - /* get ouput buffer */ - out = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - -#ifdef HAVE_LIBZ - if (ssl->options.usingCompression) { - buffSz = myCompress(ssl, sendBuffer, buffSz, comp, sizeof(comp)); - if (buffSz < 0) { - return buffSz; - } - sendBuffer = comp; - } -#endif - sendSz = BuildMessage(ssl, out, sendBuffer, buffSz, - application_data); - - ssl->buffers.outputBuffer.length += sendSz; - - if ( (ret = SendBuffered(ssl)) < 0) { - CYASSL_ERROR(ret); - /* store for next call if WANT_WRITE or user embedSend() that - doesn't present like WANT_WRITE */ - ssl->buffers.plainSz = len; - ssl->buffers.prevSent = sent; - if (ret == SOCKET_ERROR_E && ssl->options.connReset) - return 0; /* peer reset */ - return ssl->error = ret; - } - - sent += len; - - /* only one message per attempt */ - if (ssl->options.partialWrite == 1) { - CYASSL_MSG("Paritial Write on, only sending one record"); - break; - } - } - - return sent; -} - -/* process input data */ -int ReceiveData(CYASSL* ssl, byte* output, int sz, int peek) -{ - int size; - - CYASSL_ENTER("ReceiveData()"); - - if (ssl->error == WANT_READ) - ssl->error = 0; - - if (ssl->error != 0 && ssl->error != WANT_WRITE) { - CYASSL_MSG("User calling CyaSSL_read in error state, not allowed"); - return ssl->error; - } - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - int err; - CYASSL_MSG("Handshake not complete, trying to finish"); - if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) - return err; - } - - while (ssl->buffers.clearOutputBuffer.length == 0) - if ( (ssl->error = ProcessReply(ssl)) < 0) { - CYASSL_ERROR(ssl->error); - if (ssl->error == ZERO_RETURN) { - CYASSL_MSG("Zero return, no more data coming"); - return 0; /* no more data coming */ - } - if (ssl->error == SOCKET_ERROR_E) { - if (ssl->options.connReset || ssl->options.isClosed) { - CYASSL_MSG("Peer reset or closed, connection done"); - return 0; /* peer reset or closed */ - } - } - return ssl->error; - } - - if (sz < (int)ssl->buffers.clearOutputBuffer.length) - size = sz; - else - size = ssl->buffers.clearOutputBuffer.length; - - XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size); - - if (peek == 0) { - ssl->buffers.clearOutputBuffer.length -= size; - ssl->buffers.clearOutputBuffer.buffer += size; - } - - if (ssl->buffers.clearOutputBuffer.length == 0 && - ssl->buffers.inputBuffer.dynamicFlag) - ShrinkInputBuffer(ssl, NO_FORCED_FREE); - - CYASSL_LEAVE("ReceiveData()", size); - return size; -} - - -/* send alert message */ -int SendAlert(CYASSL* ssl, int severity, int type) -{ - byte input[ALERT_SIZE]; - byte *output; - int sendSz; - int ret; - int dtlsExtra = 0; - - /* if sendalert is called again for nonbloking */ - if (ssl->options.sendAlertState != 0) { - ret = SendBuffered(ssl); - if (ret == 0) - ssl->options.sendAlertState = 0; - return ret; - } - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - dtlsExtra = DTLS_RECORD_EXTRA; - #endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, - ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - input[0] = (byte)severity; - input[1] = (byte)type; - ssl->alert_history.last_tx.code = type; - ssl->alert_history.last_tx.level = severity; - if (severity == alert_fatal) { - ssl->options.isClosed = 1; /* Don't send close_notify */ - } - - /* only send encrypted alert if handshake actually complete, otherwise - other side may not be able to handle it */ - if (ssl->keys.encryptionOn && ssl->options.handShakeState == HANDSHAKE_DONE) - sendSz = BuildMessage(ssl, output, input, ALERT_SIZE, alert); - else { - - AddRecordHeader(output, ALERT_SIZE, alert, ssl); - output += RECORD_HEADER_SZ; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - output += DTLS_RECORD_EXTRA; - #endif - XMEMCPY(output, input, ALERT_SIZE); - - sendSz = RECORD_HEADER_SZ + ALERT_SIZE; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - sendSz += DTLS_RECORD_EXTRA; - #endif - } - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("Alert", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap); - #endif - - ssl->buffers.outputBuffer.length += sendSz; - ssl->options.sendAlertState = 1; - - return SendBuffered(ssl); -} - - - -void SetErrorString(int error, char* str) -{ - const int max = CYASSL_MAX_ERROR_SZ; /* shorthand */ - -#ifdef NO_ERROR_STRINGS - - (void)error; - XSTRNCPY(str, "no support for error strings built in", max); - -#else - - /* pass to CTaoCrypt */ - if (error < MAX_CODE_E && error > MIN_CODE_E) { - CTaoCryptErrorString(error, str); - return; - } - - switch (error) { - - case UNSUPPORTED_SUITE : - XSTRNCPY(str, "unsupported cipher suite", max); - break; - - case INPUT_CASE_ERROR : - XSTRNCPY(str, "input state error", max); - break; - - case PREFIX_ERROR : - XSTRNCPY(str, "bad index to key rounds", max); - break; - - case MEMORY_ERROR : - XSTRNCPY(str, "out of memory", max); - break; - - case VERIFY_FINISHED_ERROR : - XSTRNCPY(str, "verify problem on finished", max); - break; - - case VERIFY_MAC_ERROR : - XSTRNCPY(str, "verify mac problem", max); - break; - - case PARSE_ERROR : - XSTRNCPY(str, "parse error on header", max); - break; - - case SIDE_ERROR : - XSTRNCPY(str, "wrong client/server type", max); - break; - - case NO_PEER_CERT : - XSTRNCPY(str, "peer didn't send cert", max); - break; - - case UNKNOWN_HANDSHAKE_TYPE : - XSTRNCPY(str, "weird handshake type", max); - break; - - case SOCKET_ERROR_E : - XSTRNCPY(str, "error state on socket", max); - break; - - case SOCKET_NODATA : - XSTRNCPY(str, "expected data, not there", max); - break; - - case INCOMPLETE_DATA : - XSTRNCPY(str, "don't have enough data to complete task", max); - break; - - case UNKNOWN_RECORD_TYPE : - XSTRNCPY(str, "unknown type in record hdr", max); - break; - - case DECRYPT_ERROR : - XSTRNCPY(str, "error during decryption", max); - break; - - case FATAL_ERROR : - XSTRNCPY(str, "revcd alert fatal error", max); - break; - - case ENCRYPT_ERROR : - XSTRNCPY(str, "error during encryption", max); - break; - - case FREAD_ERROR : - XSTRNCPY(str, "fread problem", max); - break; - - case NO_PEER_KEY : - XSTRNCPY(str, "need peer's key", max); - break; - - case NO_PRIVATE_KEY : - XSTRNCPY(str, "need the private key", max); - break; - - case NO_DH_PARAMS : - XSTRNCPY(str, "server missing DH params", max); - break; - - case RSA_PRIVATE_ERROR : - XSTRNCPY(str, "error during rsa priv op", max); - break; - - case MATCH_SUITE_ERROR : - XSTRNCPY(str, "can't match cipher suite", max); - break; - - case BUILD_MSG_ERROR : - XSTRNCPY(str, "build message failure", max); - break; - - case BAD_HELLO : - XSTRNCPY(str, "client hello malformed", max); - break; - - case DOMAIN_NAME_MISMATCH : - XSTRNCPY(str, "peer subject name mismatch", max); - break; - - case WANT_READ : - case SSL_ERROR_WANT_READ : - XSTRNCPY(str, "non-blocking socket wants data to be read", max); - break; - - case NOT_READY_ERROR : - XSTRNCPY(str, "handshake layer not ready yet, complete first", max); - break; - - case PMS_VERSION_ERROR : - XSTRNCPY(str, "premaster secret version mismatch error", max); - break; - - case VERSION_ERROR : - XSTRNCPY(str, "record layer version error", max); - break; - - case WANT_WRITE : - case SSL_ERROR_WANT_WRITE : - XSTRNCPY(str, "non-blocking socket write buffer full", max); - break; - - case BUFFER_ERROR : - XSTRNCPY(str, "malformed buffer input error", max); - break; - - case VERIFY_CERT_ERROR : - XSTRNCPY(str, "verify problem on certificate", max); - break; - - case VERIFY_SIGN_ERROR : - XSTRNCPY(str, "verify problem based on signature", max); - break; - - case CLIENT_ID_ERROR : - XSTRNCPY(str, "psk client identity error", max); - break; - - case SERVER_HINT_ERROR: - XSTRNCPY(str, "psk server hint error", max); - break; - - case PSK_KEY_ERROR: - XSTRNCPY(str, "psk key callback error", max); - break; - - case NTRU_KEY_ERROR: - XSTRNCPY(str, "NTRU key error", max); - break; - - case NTRU_DRBG_ERROR: - XSTRNCPY(str, "NTRU drbg error", max); - break; - - case NTRU_ENCRYPT_ERROR: - XSTRNCPY(str, "NTRU encrypt error", max); - break; - - case NTRU_DECRYPT_ERROR: - XSTRNCPY(str, "NTRU decrypt error", max); - break; - - case ZLIB_INIT_ERROR: - XSTRNCPY(str, "zlib init error", max); - break; - - case ZLIB_COMPRESS_ERROR: - XSTRNCPY(str, "zlib compress error", max); - break; - - case ZLIB_DECOMPRESS_ERROR: - XSTRNCPY(str, "zlib decompress error", max); - break; - - case GETTIME_ERROR: - XSTRNCPY(str, "gettimeofday() error", max); - break; - - case GETITIMER_ERROR: - XSTRNCPY(str, "getitimer() error", max); - break; - - case SIGACT_ERROR: - XSTRNCPY(str, "sigaction() error", max); - break; - - case SETITIMER_ERROR: - XSTRNCPY(str, "setitimer() error", max); - break; - - case LENGTH_ERROR: - XSTRNCPY(str, "record layer length error", max); - break; - - case PEER_KEY_ERROR: - XSTRNCPY(str, "cant decode peer key", max); - break; - - case ZERO_RETURN: - case SSL_ERROR_ZERO_RETURN: - XSTRNCPY(str, "peer sent close notify alert", max); - break; - - case ECC_CURVETYPE_ERROR: - XSTRNCPY(str, "Bad ECC Curve Type or unsupported", max); - break; - - case ECC_CURVE_ERROR: - XSTRNCPY(str, "Bad ECC Curve or unsupported", max); - break; - - case ECC_PEERKEY_ERROR: - XSTRNCPY(str, "Bad ECC Peer Key", max); - break; - - case ECC_MAKEKEY_ERROR: - XSTRNCPY(str, "ECC Make Key failure", max); - break; - - case ECC_EXPORT_ERROR: - XSTRNCPY(str, "ECC Export Key failure", max); - break; - - case ECC_SHARED_ERROR: - XSTRNCPY(str, "ECC DHE shared failure", max); - break; - - case NOT_CA_ERROR: - XSTRNCPY(str, "Not a CA by basic constraint error", max); - break; - - case BAD_PATH_ERROR: - XSTRNCPY(str, "Bad path for opendir error", max); - break; - - case BAD_CERT_MANAGER_ERROR: - XSTRNCPY(str, "Bad Cert Manager error", max); - break; - - case OCSP_CERT_REVOKED: - XSTRNCPY(str, "OCSP Cert revoked", max); - break; - - case CRL_CERT_REVOKED: - XSTRNCPY(str, "CRL Cert revoked", max); - break; - - case CRL_MISSING: - XSTRNCPY(str, "CRL missing, not loaded", max); - break; - - case MONITOR_RUNNING_E: - XSTRNCPY(str, "CRL monitor already running", max); - break; - - case THREAD_CREATE_E: - XSTRNCPY(str, "Thread creation problem", max); - break; - - case OCSP_NEED_URL: - XSTRNCPY(str, "OCSP need URL", max); - break; - - case OCSP_CERT_UNKNOWN: - XSTRNCPY(str, "OCSP Cert unknown", max); - break; - - case OCSP_LOOKUP_FAIL: - XSTRNCPY(str, "OCSP Responder lookup fail", max); - break; - - case MAX_CHAIN_ERROR: - XSTRNCPY(str, "Maximum Chain Depth Exceeded", max); - break; - - case COOKIE_ERROR: - XSTRNCPY(str, "DTLS Cookie Error", max); - break; - - case SEQUENCE_ERROR: - XSTRNCPY(str, "DTLS Sequence Error", max); - break; - - case SUITES_ERROR: - XSTRNCPY(str, "Suites Pointer Error", max); - break; - - case SSL_NO_PEM_HEADER: - XSTRNCPY(str, "No PEM Header Error", max); - break; - - case OUT_OF_ORDER_E: - XSTRNCPY(str, "Out of order message, fatal", max); - break; - - case BAD_KEA_TYPE_E: - XSTRNCPY(str, "Bad KEA type found", max); - break; - - case SANITY_CIPHER_E: - XSTRNCPY(str, "Sanity check on ciphertext failed", max); - break; - - case RECV_OVERFLOW_E: - XSTRNCPY(str, "Receive callback returned more than requested", max); - break; - - case GEN_COOKIE_E: - XSTRNCPY(str, "Generate Cookie Error", max); - break; - - case NO_PEER_VERIFY: - XSTRNCPY(str, "Need peer certificate verify Error", max); - break; - - case FWRITE_ERROR: - XSTRNCPY(str, "fwrite Error", max); - break; - - case CACHE_MATCH_ERROR: - XSTRNCPY(str, "Cache restore header match Error", max); - break; - - case UNKNOWN_SNI_HOST_NAME_E: - XSTRNCPY(str, "Unrecognized host name Error", max); - break; - - case KEYUSE_SIGNATURE_E: - XSTRNCPY(str, "Key Use digitalSignature not set Error", max); - break; - - case KEYUSE_ENCIPHER_E: - XSTRNCPY(str, "Key Use keyEncipherment not set Error", max); - break; - - case EXTKEYUSE_AUTH_E: - XSTRNCPY(str, "Ext Key Use server/client auth not set Error", max); - break; - - default : - XSTRNCPY(str, "unknown error number", max); - } - -#endif /* NO_ERROR_STRINGS */ -} - - - -/* be sure to add to cipher_name_idx too !!!! */ -static const char* const cipher_names[] = -{ -#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA - "RC4-SHA", -#endif - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 - "RC4-MD5", -#endif - -#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA - "DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA - "AES128-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA - "AES256-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA - "NULL-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 - "NULL-SHA256", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA - "DHE-RSA-AES128-SHA", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA - "DHE-RSA-AES256-SHA", -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 - "PSK-AES128-CBC-SHA256", -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA - "PSK-AES128-CBC-SHA", -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA - "PSK-AES256-CBC-SHA", -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 - "PSK-AES128-CCM-8", -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 - "PSK-AES256-CCM-8", -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 - "PSK-NULL-SHA256", -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA - "PSK-NULL-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 - "HC128-MD5", -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA - "HC128-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 - "HC128-B2B256", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 - "AES128-B2B256", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 - "AES256-B2B256", -#endif - -#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA - "RABBIT-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - "NTRU-RC4-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - "NTRU-DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - "NTRU-AES128-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - "NTRU-AES256-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 - "AES128-CCM-8", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 - "AES256-CCM-8", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 - "ECDHE-ECDSA-AES128-CCM-8", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 - "ECDHE-ECDSA-AES256-CCM-8", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - "ECDHE-RSA-AES128-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - "ECDHE-RSA-AES256-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - "ECDHE-ECDSA-AES128-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - "ECDHE-ECDSA-AES256-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA - "ECDHE-RSA-RC4-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - "ECDHE-RSA-DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - "ECDHE-ECDSA-RC4-SHA", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - "ECDHE-ECDSA-DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 - "AES128-SHA256", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 - "AES256-SHA256", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - "DHE-RSA-AES128-SHA256", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - "DHE-RSA-AES256-SHA256", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - "ECDH-RSA-AES128-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - "ECDH-RSA-AES256-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - "ECDH-ECDSA-AES128-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - "ECDH-ECDSA-AES256-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA - "ECDH-RSA-RC4-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - "ECDH-RSA-DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA - "ECDH-ECDSA-RC4-SHA", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - "ECDH-ECDSA-DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 - "AES128-GCM-SHA256", -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 - "AES256-GCM-SHA384", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - "DHE-RSA-AES128-GCM-SHA256", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - "DHE-RSA-AES256-GCM-SHA384", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - "ECDHE-RSA-AES128-GCM-SHA256", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - "ECDHE-RSA-AES256-GCM-SHA384", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - "ECDHE-ECDSA-AES128-GCM-SHA256", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - "ECDHE-ECDSA-AES256-GCM-SHA384", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - "ECDH-RSA-AES128-GCM-SHA256", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - "ECDH-RSA-AES256-GCM-SHA384", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - "ECDH-ECDSA-AES128-GCM-SHA256", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - "ECDH-ECDSA-AES256-GCM-SHA384", -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - "CAMELLIA128-SHA", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - "DHE-RSA-CAMELLIA128-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - "CAMELLIA256-SHA", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - "DHE-RSA-CAMELLIA256-SHA", -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - "CAMELLIA128-SHA256", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - "DHE-RSA-CAMELLIA128-SHA256", -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - "CAMELLIA256-SHA256", -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - "DHE-RSA-CAMELLIA256-SHA256", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - "ECDHE-RSA-AES128-SHA256", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - "ECDHE-ECDSA-AES128-SHA256", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - "ECDH-RSA-AES128-SHA256", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - "ECDH-ECDSA-AES128-SHA256", -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - "ECDHE-RSA-AES256-SHA384", -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - "ECDHE-ECDSA-AES256-SHA384", -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - "ECDH-RSA-AES256-SHA384", -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - "ECDH-ECDSA-AES256-SHA384", -#endif - -}; - - - -/* cipher suite number that matches above name table */ -static int cipher_name_idx[] = -{ - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA - SSL_RSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 - SSL_RSA_WITH_RC4_128_MD5, -#endif - -#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA - SSL_RSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA - TLS_RSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA - TLS_RSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA - TLS_RSA_WITH_NULL_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 - TLS_RSA_WITH_NULL_SHA256, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 - TLS_PSK_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA - TLS_PSK_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA - TLS_PSK_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 - TLS_PSK_WITH_AES_128_CCM_8, -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 - TLS_PSK_WITH_AES_256_CCM_8, -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 - TLS_PSK_WITH_NULL_SHA256, -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA - TLS_PSK_WITH_NULL_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 - TLS_RSA_WITH_HC_128_MD5, -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA - TLS_RSA_WITH_HC_128_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 - TLS_RSA_WITH_HC_128_B2B256, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 - TLS_RSA_WITH_AES_128_CBC_B2B256, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 - TLS_RSA_WITH_AES_256_CBC_B2B256, -#endif - -#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA - TLS_RSA_WITH_RABBIT_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - TLS_NTRU_RSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - TLS_NTRU_RSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - TLS_NTRU_RSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 - TLS_RSA_WITH_AES_128_CCM_8, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 - TLS_RSA_WITH_AES_256_CCM_8, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 - TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA - TLS_ECDHE_RSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 - TLS_RSA_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 - TLS_RSA_WITH_AES_256_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA - TLS_ECDH_RSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 - TLS_RSA_WITH_AES_128_GCM_SHA256, -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 - TLS_RSA_WITH_AES_256_GCM_SHA384, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 -#endif -}; - - -/* return true if set, else false */ -/* only supports full name from cipher_name[] delimited by : */ -int SetCipherList(Suites* s, const char* list) -{ - int ret = 0, i; - char name[MAX_SUITE_NAME]; - - char needle[] = ":"; - char* haystack = (char*)list; - char* prev; - - const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); - int idx = 0; - int haveRSA = 0, haveECDSA = 0; - - if (s == NULL) { - CYASSL_MSG("SetCipherList suite pointer error"); - return 0; - } - - if (!list) - return 0; - - if (*list == 0) return 1; /* CyaSSL default */ - - if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1; /* CyaSSL defualt */ - - for(;;) { - word32 len; - prev = haystack; - haystack = XSTRSTR(haystack, needle); - - if (!haystack) /* last cipher */ - len = min(sizeof(name), (word32)XSTRLEN(prev)); - else - len = min(sizeof(name), (word32)(haystack - prev)); - - XSTRNCPY(name, prev, len); - name[(len == sizeof(name)) ? len - 1 : len] = 0; - - for (i = 0; i < suiteSz; i++) - if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { - if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM")) - s->suites[idx++] = ECC_BYTE; /* ECC suite */ - else - s->suites[idx++] = 0x00; /* normal */ - s->suites[idx++] = (byte)cipher_name_idx[i]; - - /* The suites are either ECDSA, RSA, or PSK. The RSA suites - * don't necessarily have RSA in the name. */ - if ((haveECDSA == 0) && XSTRSTR(name, "ECDSA")) { - haveECDSA = 1; - } - else if ((haveRSA == 0) && (XSTRSTR(name, "PSK") == NULL)) { - haveRSA = 1; - } - - if (!ret) ret = 1; /* found at least one */ - break; - } - if (!haystack) break; - haystack++; - } - - if (ret) { - s->setSuites = 1; - s->suiteSz = (word16)idx; - - idx = 0; - - if (haveECDSA) { - #ifdef CYASSL_SHA384 - s->hashSigAlgo[idx++] = sha384_mac; - s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - #ifndef NO_SHA256 - s->hashSigAlgo[idx++] = sha256_mac; - s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - #endif - s->hashSigAlgo[idx++] = sha_mac; - s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; - } - - if (haveRSA) { - #ifdef CYASSL_SHA384 - s->hashSigAlgo[idx++] = sha384_mac; - s->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - #ifndef NO_SHA256 - s->hashSigAlgo[idx++] = sha256_mac; - s->hashSigAlgo[idx++] = rsa_sa_algo; - #endif - s->hashSigAlgo[idx++] = sha_mac; - s->hashSigAlgo[idx++] = rsa_sa_algo; - } - - s->hashSigAlgoSz = (word16)idx; - } - - return ret; -} - - -static void PickHashSigAlgo(CYASSL* ssl, - const byte* hashSigAlgo, word32 hashSigAlgoSz) -{ - word32 i; - - ssl->suites->sigAlgo = ssl->specs.sig_algo; - ssl->suites->hashAlgo = sha_mac; - - for (i = 0; i < hashSigAlgoSz; i += 2) { - if (hashSigAlgo[i+1] == ssl->specs.sig_algo) { - if (hashSigAlgo[i] == sha_mac) { - break; - } - #ifndef NO_SHA256 - else if (hashSigAlgo[i] == sha256_mac) { - ssl->suites->hashAlgo = sha256_mac; - break; - } - #endif - #ifdef CYASSL_SHA384 - else if (hashSigAlgo[i] == sha384_mac) { - ssl->suites->hashAlgo = sha384_mac; - break; - } - #endif - } - } -} - - -#ifdef CYASSL_CALLBACKS - - /* Initialisze HandShakeInfo */ - void InitHandShakeInfo(HandShakeInfo* info) - { - int i; - - info->cipherName[0] = 0; - for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) - info->packetNames[i][0] = 0; - info->numberPackets = 0; - info->negotiationError = 0; - } - - /* Set Final HandShakeInfo parameters */ - void FinishHandShakeInfo(HandShakeInfo* info, const CYASSL* ssl) - { - int i; - int sz = sizeof(cipher_name_idx)/sizeof(int); - - for (i = 0; i < sz; i++) - if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) { - if (ssl->options.cipherSuite0 == ECC_BYTE) - continue; /* ECC suites at end */ - XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ); - break; - } - - /* error max and min are negative numbers */ - if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR) - info->negotiationError = ssl->error; - } - - - /* Add name to info packet names, increase packet name count */ - void AddPacketName(const char* name, HandShakeInfo* info) - { - if (info->numberPackets < MAX_PACKETS_HANDSHAKE) { - XSTRNCPY(info->packetNames[info->numberPackets++], name, - MAX_PACKETNAME_SZ); - } - } - - - /* Initialisze TimeoutInfo */ - void InitTimeoutInfo(TimeoutInfo* info) - { - int i; - - info->timeoutName[0] = 0; - info->flags = 0; - - for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) { - info->packets[i].packetName[0] = 0; - info->packets[i].timestamp.tv_sec = 0; - info->packets[i].timestamp.tv_usec = 0; - info->packets[i].bufferValue = 0; - info->packets[i].valueSz = 0; - } - info->numberPackets = 0; - info->timeoutValue.tv_sec = 0; - info->timeoutValue.tv_usec = 0; - } - - - /* Free TimeoutInfo */ - void FreeTimeoutInfo(TimeoutInfo* info, void* heap) - { - int i; - (void)heap; - for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) - if (info->packets[i].bufferValue) { - XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO); - info->packets[i].bufferValue = 0; - } - - } - - - /* Add PacketInfo to TimeoutInfo */ - void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data, - int sz, void* heap) - { - if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) { - Timeval currTime; - - /* may add name after */ - if (name) - XSTRNCPY(info->packets[info->numberPackets].packetName, name, - MAX_PACKETNAME_SZ); - - /* add data, put in buffer if bigger than static buffer */ - info->packets[info->numberPackets].valueSz = sz; - if (sz < MAX_VALUE_SZ) - XMEMCPY(info->packets[info->numberPackets].value, data, sz); - else { - info->packets[info->numberPackets].bufferValue = - XMALLOC(sz, heap, DYNAMIC_TYPE_INFO); - if (!info->packets[info->numberPackets].bufferValue) - /* let next alloc catch, just don't fill, not fatal here */ - info->packets[info->numberPackets].valueSz = 0; - else - XMEMCPY(info->packets[info->numberPackets].bufferValue, - data, sz); - } - gettimeofday(&currTime, 0); - info->packets[info->numberPackets].timestamp.tv_sec = - currTime.tv_sec; - info->packets[info->numberPackets].timestamp.tv_usec = - currTime.tv_usec; - info->numberPackets++; - } - } - - - /* Add packet name to previsouly added packet info */ - void AddLateName(const char* name, TimeoutInfo* info) - { - /* make sure we have a valid previous one */ - if (info->numberPackets > 0 && info->numberPackets < - MAX_PACKETS_HANDSHAKE) { - XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name, - MAX_PACKETNAME_SZ); - } - } - - /* Add record header to previsouly added packet info */ - void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info) - { - /* make sure we have a valid previous one */ - if (info->numberPackets > 0 && info->numberPackets < - MAX_PACKETS_HANDSHAKE) { - if (info->packets[info->numberPackets - 1].bufferValue) - XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl, - RECORD_HEADER_SZ); - else - XMEMCPY(info->packets[info->numberPackets - 1].value, rl, - RECORD_HEADER_SZ); - } - } - -#endif /* CYASSL_CALLBACKS */ - - - -/* client only parts */ -#ifndef NO_CYASSL_CLIENT - - int SendClientHello(CYASSL* ssl) - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - int idSz = ssl->options.resuming ? ID_LEN : 0; - int ret; - - if (ssl->suites == NULL) { - CYASSL_MSG("Bad suites pointer in SendClientHello"); - return SUITES_ERROR; - } - - length = VERSION_SZ + RAN_LEN - + idSz + ENUM_LEN - + ssl->suites->suiteSz + SUITE_LEN - + COMP_LEN + ENUM_LEN; - -#ifdef HAVE_TLS_EXTENSIONS - length += TLSX_GetRequestSize(ssl); -#else - if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { - length += ssl->suites->hashSigAlgoSz + HELLO_EXT_SZ; - } -#endif - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - length += ENUM_LEN; /* cookie */ - if (ssl->arrays->cookieSz != 0) length += ssl->arrays->cookieSz; - sendSz = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ; - idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; - } -#endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, client_hello, ssl); - - /* client hello, first version */ - output[idx++] = ssl->version.major; - output[idx++] = ssl->version.minor; - ssl->chVersion = ssl->version; /* store in case changed */ - - /* then random */ - if (ssl->options.connectState == CONNECT_BEGIN) { - ret = RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); - if (ret != 0) - return ret; - - /* store random */ - XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN); - } else { -#ifdef CYASSL_DTLS - /* send same random on hello again */ - XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); -#endif - } - idx += RAN_LEN; - - /* then session id */ - output[idx++] = (byte)idSz; - if (idSz) { - XMEMCPY(output + idx, ssl->session.sessionID, ID_LEN); - idx += ID_LEN; - } - - /* then DTLS cookie */ -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - byte cookieSz = ssl->arrays->cookieSz; - - output[idx++] = cookieSz; - if (cookieSz) { - XMEMCPY(&output[idx], ssl->arrays->cookie, cookieSz); - idx += cookieSz; - } - } -#endif - /* then cipher suites */ - c16toa(ssl->suites->suiteSz, output + idx); - idx += 2; - XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); - idx += ssl->suites->suiteSz; - - /* last, compression */ - output[idx++] = COMP_LEN; - if (ssl->options.usingCompression) - output[idx++] = ZLIB_COMPRESSION; - else - output[idx++] = NO_COMPRESSION; - -#ifdef HAVE_TLS_EXTENSIONS - idx += TLSX_WriteRequest(ssl, output + idx); - - (void)idx; /* suppress analyzer warning, keep idx current */ -#else - if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) - { - int i; - /* add in the extensions length */ - c16toa(HELLO_EXT_LEN + ssl->suites->hashSigAlgoSz, output + idx); - idx += 2; - - c16toa(HELLO_EXT_SIG_ALGO, output + idx); - idx += 2; - c16toa(HELLO_EXT_SIGALGO_SZ+ssl->suites->hashSigAlgoSz, output+idx); - idx += 2; - c16toa(ssl->suites->hashSigAlgoSz, output + idx); - idx += 2; - for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, idx++) { - output[idx] = ssl->suites->hashSigAlgo[i]; - } - } -#endif - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - ssl->options.clientState = CLIENT_HELLO_COMPLETE; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz, - ssl->heap); -#endif - - ssl->buffers.outputBuffer.length += sendSz; - - return SendBuffered(ssl); - } - - - static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, - word32* inOutIdx, word32 size) - { - ProtocolVersion pv; - byte cookieSz; - word32 begin = *inOutIdx; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest", - &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); -#endif - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) { - DtlsPoolReset(ssl); - } -#endif - - if ((*inOutIdx - begin) + OPAQUE16_LEN + OPAQUE8_LEN > size) - return BUFFER_ERROR; - - XMEMCPY(&pv, input + *inOutIdx, OPAQUE16_LEN); - *inOutIdx += OPAQUE16_LEN; - - cookieSz = input[(*inOutIdx)++]; - - if (cookieSz) { - if ((*inOutIdx - begin) + cookieSz > size) - return BUFFER_ERROR; - -#ifdef CYASSL_DTLS - if (cookieSz <= MAX_COOKIE_LEN) { - XMEMCPY(ssl->arrays->cookie, input + *inOutIdx, cookieSz); - ssl->arrays->cookieSz = cookieSz; - } -#endif - *inOutIdx += cookieSz; - } - - ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; - return 0; - } - - - static int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 helloSz) - { - byte b; - ProtocolVersion pv; - byte compression; - word32 i = *inOutIdx; - word32 begin = i; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); -#endif - - /* protocol version, random and session id length check */ - if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - /* protocol version */ - XMEMCPY(&pv, input + i, OPAQUE16_LEN); - i += OPAQUE16_LEN; - - if (pv.minor > ssl->version.minor) { - CYASSL_MSG("Server using higher version, fatal error"); - return VERSION_ERROR; - } - else if (pv.minor < ssl->version.minor) { - CYASSL_MSG("server using lower version"); - - if (!ssl->options.downgrade) { - CYASSL_MSG(" no downgrade allowed, fatal error"); - return VERSION_ERROR; - } - - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - CYASSL_MSG(" downgrading to SSLv3"); - ssl->options.tls = 0; - ssl->options.tls1_1 = 0; - ssl->version.minor = SSLv3_MINOR; - } - else if (pv.minor == TLSv1_MINOR) { - /* turn off tls 1.1+ */ - CYASSL_MSG(" downgrading to TLSv1"); - ssl->options.tls1_1 = 0; - ssl->version.minor = TLSv1_MINOR; - } - else if (pv.minor == TLSv1_1_MINOR) { - CYASSL_MSG(" downgrading to TLSv1.1"); - ssl->version.minor = TLSv1_1_MINOR; - } - } - - /* random */ - XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); - i += RAN_LEN; - - /* session id */ - b = input[i++]; - - if (b == ID_LEN) { - if ((i - begin) + ID_LEN > helloSz) - return BUFFER_ERROR; - - XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN)); - i += ID_LEN; - ssl->options.haveSessionId = 1; - } - else if (b) { - CYASSL_MSG("Invalid session ID size"); - return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ - } - - /* suite and compression */ - if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - ssl->options.cipherSuite0 = input[i++]; - ssl->options.cipherSuite = input[i++]; - compression = input[i++]; - - if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) { - CYASSL_MSG("Server refused compression, turning off"); - ssl->options.usingCompression = 0; /* turn off if server refused */ - } - - *inOutIdx = i; - - /* tls extensions */ - if ( (i - begin) < helloSz) { -#ifdef HAVE_TLS_EXTENSIONS - if (IsTLS(ssl)) { - int ret = 0; - word16 totalExtSz; - Suites clSuites; /* just for compatibility right now */ - - if ((i - begin) + OPAQUE16_LEN > helloSz) - return BUFFER_ERROR; - - ato16(&input[i], &totalExtSz); - i += OPAQUE16_LEN; - - if ((i - begin) + totalExtSz > helloSz) - return BUFFER_ERROR; - - if ((ret = TLSX_Parse(ssl, (byte *) input + i, - totalExtSz, 0, &clSuites))) - return ret; - - i += totalExtSz; - *inOutIdx = i; - } - else -#endif - *inOutIdx = begin + helloSz; /* skip extensions */ - } - - ssl->options.serverState = SERVER_HELLO_COMPLETE; - - if (ssl->options.resuming) { - if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, - ssl->session.sessionID, ID_LEN) == 0) { - if (SetCipherSpecs(ssl) == 0) { - int ret = -1; - - XMEMCPY(ssl->arrays->masterSecret, - ssl->session.masterSecret, SECRET_LEN); - #ifdef NO_OLD_TLS - ret = DeriveTlsKeys(ssl); - #else - #ifndef NO_TLS - if (ssl->options.tls) - ret = DeriveTlsKeys(ssl); - #endif - if (!ssl->options.tls) - ret = DeriveKeys(ssl); - #endif - ssl->options.serverState = SERVER_HELLODONE_COMPLETE; - - return ret; - } - else { - CYASSL_MSG("Unsupported cipher suite, DoServerHello"); - return UNSUPPORTED_SUITE; - } - } - else { - CYASSL_MSG("Server denied resumption attempt"); - ssl->options.resuming = 0; /* server denied resumption try */ - } - } - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - DtlsPoolReset(ssl); - } - #endif - - return SetCipherSpecs(ssl); - } - - -#ifndef NO_CERTS - /* just read in and ignore for now TODO: */ - static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32* - inOutIdx, word32 size) - { - word16 len; - word32 begin = *inOutIdx; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("CertificateRequest", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("CertificateRequest", &ssl->timeoutInfo); - #endif - - if ((*inOutIdx - begin) + OPAQUE8_LEN > size) - return BUFFER_ERROR; - - len = input[(*inOutIdx)++]; - - if ((*inOutIdx - begin) + len > size) - return BUFFER_ERROR; - - /* types, read in here */ - *inOutIdx += len; - - /* signature and hash signature algorithm */ - if (IsAtLeastTLSv1_2(ssl)) { - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &len); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + len > size) - return BUFFER_ERROR; - - PickHashSigAlgo(ssl, input + *inOutIdx, len); - *inOutIdx += len; - } - - /* authorities */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &len); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + len > size) - return BUFFER_ERROR; - - while (len) { - word16 dnSz; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &dnSz); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + dnSz > size) - return BUFFER_ERROR; - - *inOutIdx += dnSz; - len -= OPAQUE16_LEN + dnSz; - } - - /* don't send client cert or cert verify if user hasn't provided - cert and private key */ - if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer) - ssl->options.sendVerify = SEND_CERT; - else if (IsTLS(ssl)) - ssl->options.sendVerify = SEND_BLANK_CERT; - - return 0; - } -#endif /* !NO_CERTS */ - - - static int DoServerKeyExchange(CYASSL* ssl, const byte* input, - word32* inOutIdx, word32 size) - { - word16 length = 0; - word32 begin = *inOutIdx; - int ret = 0; - - (void)length; /* shut up compiler warnings */ - (void)begin; - (void)ssl; - (void)input; - (void)size; - (void)ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("ServerKeyExchange", &ssl->timeoutInfo); - #endif - - #ifndef NO_PSK - if (ssl->specs.kea == psk_kea) { - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &length); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx, - min(length, MAX_PSK_ID_LEN)); - - ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0; - *inOutIdx += length; - - return 0; - } - #endif - #ifdef OPENSSL_EXTRA - if (ssl->specs.kea == diffie_hellman_kea) - { - /* p */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &length); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap, - DYNAMIC_TYPE_DH); - - if (ssl->buffers.serverDH_P.buffer) - ssl->buffers.serverDH_P.length = length; - else - return MEMORY_ERROR; - - XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length); - *inOutIdx += length; - - /* g */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &length); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap, - DYNAMIC_TYPE_DH); - - if (ssl->buffers.serverDH_G.buffer) - ssl->buffers.serverDH_G.length = length; - else - return MEMORY_ERROR; - - XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length); - *inOutIdx += length; - - /* pub */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &length); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap, - DYNAMIC_TYPE_DH); - - if (ssl->buffers.serverDH_Pub.buffer) - ssl->buffers.serverDH_Pub.length = length; - else - return MEMORY_ERROR; - - XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length); - *inOutIdx += length; - } /* dh_kea */ - #endif /* OPENSSL_EXTRA */ - - #ifdef HAVE_ECC - if (ssl->specs.kea == ecc_diffie_hellman_kea) - { - byte b; - - if ((*inOutIdx - begin) + ENUM_LEN + OPAQUE16_LEN + OPAQUE8_LEN > size) - return BUFFER_ERROR; - - b = input[(*inOutIdx)++]; - - if (b != named_curve) - return ECC_CURVETYPE_ERROR; - - *inOutIdx += 1; /* curve type, eat leading 0 */ - b = input[(*inOutIdx)++]; - - if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b != - secp160r1 && b != secp192r1 && b != secp224r1) - return ECC_CURVE_ERROR; - - length = input[(*inOutIdx)++]; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0) - return ECC_PEERKEY_ERROR; - - *inOutIdx += length; - ssl->peerEccKeyPresent = 1; - } - #endif /* HAVE_ECC */ - - #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) - { -#ifndef NO_OLD_TLS - Md5 md5; - Sha sha; -#endif -#ifndef NO_SHA256 - Sha256 sha256; - byte hash256[SHA256_DIGEST_SIZE]; -#endif -#ifdef CYASSL_SHA384 - Sha384 sha384; - byte hash384[SHA384_DIGEST_SIZE]; -#endif - byte hash[FINISHED_SZ]; - byte messageVerify[MAX_DH_SZ]; - byte hashAlgo = sha_mac; - byte sigAlgo = ssl->specs.sig_algo; - word16 verifySz = (word16) (*inOutIdx - begin); - - /* save message for hash verify */ - if (verifySz > sizeof(messageVerify)) - return BUFFER_ERROR; - - XMEMCPY(messageVerify, input + begin, verifySz); - - if (IsAtLeastTLSv1_2(ssl)) { - if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size) - return BUFFER_ERROR; - - hashAlgo = input[(*inOutIdx)++]; - sigAlgo = input[(*inOutIdx)++]; - } - - /* signature */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &length); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - /* inOutIdx updated at the end of the function */ - - /* verify signature */ -#ifndef NO_OLD_TLS - /* md5 */ - InitMd5(&md5); - Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); - Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); - Md5Update(&md5, messageVerify, verifySz); - Md5Final(&md5, hash); - - /* sha */ - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); - ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); - ShaUpdate(&sha, messageVerify, verifySz); - ShaFinal(&sha, hash + MD5_DIGEST_SIZE); -#endif - -#ifndef NO_SHA256 - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, messageVerify, verifySz); - if (ret != 0) - return ret; - ret = Sha256Final(&sha256, hash256); - if (ret != 0) - return ret; -#endif - -#ifdef CYASSL_SHA384 - ret = InitSha384(&sha384); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, messageVerify, verifySz); - if (ret != 0) - return ret; - ret = Sha384Final(&sha384, hash384); - if (ret != 0) - return ret; -#endif - -#ifndef NO_RSA - /* rsa */ - if (sigAlgo == rsa_sa_algo) - { - byte* out = NULL; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaVerifyCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - if (!ssl->peerRsaKeyPresent) - return NO_PEER_KEY; - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->RsaVerifyCb(ssl, (byte *) input + *inOutIdx, - length, &out, - ssl->buffers.peerRsaKey.buffer, - ssl->buffers.peerRsaKey.length, - ssl->RsaVerifyCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaSSL_VerifyInline((byte *) input + *inOutIdx, length, - &out, ssl->peerRsaKey); - } - - if (IsAtLeastTLSv1_2(ssl)) { - byte encodedSig[MAX_ENCODED_SIG_SZ]; - word32 encSigSz; -#ifndef NO_OLD_TLS - byte* digest = &hash[MD5_DIGEST_SIZE]; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; -#else - byte* digest = hash256; - int typeH = SHA256h; - int digestSz = SHA256_DIGEST_SIZE; -#endif - - if (hashAlgo == sha_mac) { - #ifndef NO_SHA - digest = &hash[MD5_DIGEST_SIZE]; - typeH = SHAh; - digestSz = SHA_DIGEST_SIZE; - #endif - } - else if (hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = hash384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - - encSigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); - - if (encSigSz != (word32)ret || !out || XMEMCMP(out, encodedSig, - min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) - return VERIFY_SIGN_ERROR; - } - else { - if (ret != sizeof(hash) || !out || XMEMCMP(out, - hash, sizeof(hash)) != 0) - return VERIFY_SIGN_ERROR; - } - } else -#endif -#ifdef HAVE_ECC - /* ecdsa */ - if (sigAlgo == ecc_dsa_sa_algo) { - int verify = 0; -#ifndef NO_OLD_TLS - byte* digest = &hash[MD5_DIGEST_SIZE]; - word32 digestSz = SHA_DIGEST_SIZE; -#else - byte* digest = hash256; - word32 digestSz = SHA256_DIGEST_SIZE; -#endif - byte doUserEcc = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->EccVerifyCb) - doUserEcc = 1; - #endif - - if (!ssl->peerEccDsaKeyPresent) - return NO_PEER_KEY; - - if (IsAtLeastTLSv1_2(ssl)) { - if (hashAlgo == sha_mac) { - #ifndef NO_SHA - digest = &hash[MD5_DIGEST_SIZE]; - digestSz = SHA_DIGEST_SIZE; - #endif - } - else if (hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = hash384; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - } - if (doUserEcc) { - #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length, - digest, digestSz, - ssl->buffers.peerEccDsaKey.buffer, - ssl->buffers.peerEccDsaKey.length, - &verify, ssl->EccVerifyCtx); - #endif - } - else { - ret = ecc_verify_hash(input + *inOutIdx, length, - digest, digestSz, &verify, ssl->peerEccDsaKey); - } - if (ret != 0 || verify == 0) - return VERIFY_SIGN_ERROR; - } - else -#endif /* HAVE_ECC */ - return ALGO_ID_E; - - /* signature length */ - *inOutIdx += length; - - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - - return 0; - } -#else /* HAVE_OPENSSL or HAVE_ECC */ - return NOT_COMPILED_IN; /* not supported by build */ -#endif /* HAVE_OPENSSL or HAVE_ECC */ - } - - - int SendClientKeyExchange(CYASSL* ssl) - { - byte encSecret[MAX_ENCRYPT_SZ]; - word32 encSz = 0; - word32 idx = 0; - int ret = 0; - byte doUserRsa = 0; - - (void)doUserRsa; - - #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - if (ssl->ctx->RsaEncCb) - doUserRsa = 1; - #endif /* NO_RSA */ - #endif /*HAVE_PK_CALLBACKS */ - - switch (ssl->specs.kea) { - #ifndef NO_RSA - case rsa_kea: - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, - SECRET_LEN); - if (ret != 0) - return ret; - - ssl->arrays->preMasterSecret[0] = ssl->chVersion.major; - ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor; - ssl->arrays->preMasterSz = SECRET_LEN; - - if (ssl->peerRsaKeyPresent == 0) - return NO_PEER_KEY; - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - encSz = sizeof(encSecret); - ret = ssl->ctx->RsaEncCb(ssl, - ssl->arrays->preMasterSecret, - SECRET_LEN, - encSecret, &encSz, - ssl->buffers.peerRsaKey.buffer, - ssl->buffers.peerRsaKey.length, - ssl->RsaEncCtx); - #endif /* NO_RSA */ - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaPublicEncrypt(ssl->arrays->preMasterSecret, - SECRET_LEN, encSecret, sizeof(encSecret), - ssl->peerRsaKey, ssl->rng); - if (ret > 0) { - encSz = ret; - ret = 0; /* set success to 0 */ - } - } - break; - #endif - #ifdef OPENSSL_EXTRA - case diffie_hellman_kea: - { - buffer serverP = ssl->buffers.serverDH_P; - buffer serverG = ssl->buffers.serverDH_G; - buffer serverPub = ssl->buffers.serverDH_Pub; - byte priv[ENCRYPT_LEN]; - word32 privSz = 0; - DhKey key; - - if (serverP.buffer == 0 || serverG.buffer == 0 || - serverPub.buffer == 0) - return NO_PEER_KEY; - - InitDhKey(&key); - ret = DhSetKey(&key, serverP.buffer, serverP.length, - serverG.buffer, serverG.length); - if (ret == 0) - /* for DH, encSecret is Yc, agree is pre-master */ - ret = DhGenerateKeyPair(&key, ssl->rng, priv, &privSz, - encSecret, &encSz); - if (ret == 0) - ret = DhAgree(&key, ssl->arrays->preMasterSecret, - &ssl->arrays->preMasterSz, priv, privSz, - serverPub.buffer, serverPub.length); - FreeDhKey(&key); - } - break; - #endif /* OPENSSL_EXTRA */ - #ifndef NO_PSK - case psk_kea: - { - byte* pms = ssl->arrays->preMasterSecret; - - ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, - ssl->arrays->server_hint, ssl->arrays->client_identity, - MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); - if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) - return PSK_KEY_ERROR; - encSz = (word32)XSTRLEN(ssl->arrays->client_identity); - if (encSz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR; - XMEMCPY(encSecret, ssl->arrays->client_identity, encSz); - - /* make psk pre master secret */ - /* length of key + length 0s + length of key + key */ - c16toa((word16)ssl->arrays->psk_keySz, pms); - pms += 2; - XMEMSET(pms, 0, ssl->arrays->psk_keySz); - pms += ssl->arrays->psk_keySz; - c16toa((word16)ssl->arrays->psk_keySz, pms); - pms += 2; - XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; - XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); - ssl->arrays->psk_keySz = 0; /* No further need */ - } - break; - #endif /* NO_PSK */ - #ifdef HAVE_NTRU - case ntru_kea: - { - word32 rc; - word16 cipherLen = sizeof(encSecret); - DRBG_HANDLE drbg; - static uint8_t const cyasslStr[] = { - 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' - }; - - ret = RNG_GenerateBlock(ssl->rng, - ssl->arrays->preMasterSecret, SECRET_LEN); - if (ret != 0) - return ret; - - ssl->arrays->preMasterSz = SECRET_LEN; - - if (ssl->peerNtruKeyPresent == 0) - return NO_PEER_KEY; - - rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr, - sizeof(cyasslStr), GetEntropy, - &drbg); - if (rc != DRBG_OK) - return NTRU_DRBG_ERROR; - - rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen, - ssl->peerNtruKey, - ssl->arrays->preMasterSz, - ssl->arrays->preMasterSecret, - &cipherLen, encSecret); - crypto_drbg_uninstantiate(drbg); - if (rc != NTRU_OK) - return NTRU_ENCRYPT_ERROR; - - encSz = cipherLen; - ret = 0; - } - break; - #endif /* HAVE_NTRU */ - #ifdef HAVE_ECC - case ecc_diffie_hellman_kea: - { - ecc_key myKey; - ecc_key* peerKey = NULL; - word32 size = sizeof(encSecret); - - if (ssl->specs.static_ecdh) { - /* TODO: EccDsa is really fixed Ecc change naming */ - if (!ssl->peerEccDsaKeyPresent || !ssl->peerEccDsaKey->dp) - return NO_PEER_KEY; - peerKey = ssl->peerEccDsaKey; - } - else { - if (!ssl->peerEccKeyPresent || !ssl->peerEccKey->dp) - return NO_PEER_KEY; - peerKey = ssl->peerEccKey; - } - - if (peerKey == NULL) - return NO_PEER_KEY; - - ecc_init(&myKey); - ret = ecc_make_key(ssl->rng, peerKey->dp->size, &myKey); - if (ret != 0) - return ECC_MAKEKEY_ERROR; - - /* precede export with 1 byte length */ - ret = ecc_export_x963(&myKey, encSecret + 1, &size); - encSecret[0] = (byte)size; - encSz = size + 1; - - if (ret != 0) - ret = ECC_EXPORT_ERROR; - else { - size = sizeof(ssl->arrays->preMasterSecret); - ret = ecc_shared_secret(&myKey, peerKey, - ssl->arrays->preMasterSecret, &size); - if (ret != 0) - ret = ECC_SHARED_ERROR; - } - - ssl->arrays->preMasterSz = size; - ecc_free(&myKey); - } - break; - #endif /* HAVE_ECC */ - default: - return ALGO_ID_E; /* unsupported kea */ - } - - if (ret == 0) { - byte *output; - int sendSz; - word32 tlsSz = 0; - - if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea) - tlsSz = 2; - - if (ssl->specs.kea == ecc_diffie_hellman_kea) /* always off */ - tlsSz = 0; - - sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; - idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; - } - #endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl); - - if (tlsSz) { - c16toa((word16)encSz, &output[idx]); - idx += 2; - } - XMEMCPY(output + idx, encSecret, encSz); - /* if add more to output, adjust idx - idx += encSz; */ - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - #endif - - ssl->buffers.outputBuffer.length += sendSz; - - if (ssl->options.groupMessages) - ret = 0; - else - ret = SendBuffered(ssl); - } - - if (ret == 0 || ret == WANT_WRITE) { - int tmpRet = MakeMasterSecret(ssl); - if (tmpRet != 0) - ret = tmpRet; /* save WANT_WRITE unless more serious */ - ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - } - /* No further need for PMS */ - XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz); - ssl->arrays->preMasterSz = 0; - - return ret; - } - -#ifndef NO_CERTS - int SendCertificateVerify(CYASSL* ssl) - { - byte *output; - int sendSz = 0, length, ret; - word32 idx = 0; - word32 sigOutSz = 0; -#ifndef NO_RSA - RsaKey key; - int initRsaKey = 0; -#endif - int usingEcc = 0; -#ifdef HAVE_ECC - ecc_key eccKey; -#endif - - (void)idx; - - if (ssl->options.sendVerify == SEND_BLANK_CERT) - return 0; /* sent blank cert, can't verify */ - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, MAX_CERT_VERIFY_SZ)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - ret = BuildCertHashes(ssl, &ssl->certHashes); - if (ret != 0) - return ret; - -#ifdef HAVE_ECC - ecc_init(&eccKey); -#endif -#ifndef NO_RSA - ret = InitRsaKey(&key, ssl->heap); - if (ret == 0) initRsaKey = 1; - if (ret == 0) - ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key, - ssl->buffers.key.length); - if (ret == 0) - sigOutSz = RsaEncryptSize(&key); - else -#endif - { - #ifdef HAVE_ECC - CYASSL_MSG("Trying ECC client cert, RSA didn't work"); - - idx = 0; - ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &eccKey, - ssl->buffers.key.length); - if (ret == 0) { - CYASSL_MSG("Using ECC client cert"); - usingEcc = 1; - sigOutSz = MAX_ENCODED_SIG_SZ; - } - else { - CYASSL_MSG("Bad client cert type"); - } - #endif - } - if (ret == 0) { - byte* verify = (byte*)&output[RECORD_HEADER_SZ + - HANDSHAKE_HEADER_SZ]; -#ifndef NO_OLD_TLS - byte* signBuffer = ssl->certHashes.md5; -#else - byte* signBuffer = NULL; -#endif - word32 signSz = FINISHED_SZ; - byte encodedSig[MAX_ENCODED_SIG_SZ]; - word32 extraSz = 0; /* tls 1.2 hash/sig */ - - (void)encodedSig; - (void)signSz; - (void)signBuffer; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - #endif - length = sigOutSz; - if (IsAtLeastTLSv1_2(ssl)) { - verify[0] = ssl->suites->hashAlgo; - verify[1] = usingEcc ? ecc_dsa_sa_algo : rsa_sa_algo; - extraSz = HASH_SIG_SIZE; - } - - if (usingEcc) { -#ifdef HAVE_ECC - word32 localSz = MAX_ENCODED_SIG_SZ; - word32 digestSz; - byte* digest; - byte doUserEcc = 0; -#ifndef NO_OLD_TLS - /* old tls default */ - digestSz = SHA_DIGEST_SIZE; - digest = ssl->certHashes.sha; -#else - /* new tls default */ - digestSz = SHA256_DIGEST_SIZE; - digest = ssl->certHashes.sha256; -#endif - - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - if (ssl->ctx->EccSignCb) - doUserEcc = 1; - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - - if (IsAtLeastTLSv1_2(ssl)) { - if (ssl->suites->hashAlgo == sha_mac) { - #ifndef NO_SHA - digest = ssl->certHashes.sha; - digestSz = SHA_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = ssl->certHashes.sha256; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = ssl->certHashes.sha384; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - } - - if (doUserEcc) { - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ret = ssl->ctx->EccSignCb(ssl, digest, digestSz, - encodedSig, &localSz, - ssl->buffers.key.buffer, - ssl->buffers.key.length, - ssl->EccSignCtx); - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = ecc_sign_hash(digest, digestSz, encodedSig, - &localSz, ssl->rng, &eccKey); - } - if (ret == 0) { - length = localSz; - c16toa((word16)length, verify + extraSz); /* prepend hdr */ - XMEMCPY(verify + extraSz + VERIFY_HEADER,encodedSig,length); - } -#endif - } -#ifndef NO_RSA - else { - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - if (IsAtLeastTLSv1_2(ssl)) { -#ifndef NO_OLD_TLS - byte* digest = ssl->certHashes.sha; - int digestSz = SHA_DIGEST_SIZE; - int typeH = SHAh; -#else - byte* digest = ssl->certHashes.sha256; - int digestSz = SHA256_DIGEST_SIZE; - int typeH = SHA256h; -#endif - - if (ssl->suites->hashAlgo == sha_mac) { - #ifndef NO_SHA - digest = ssl->certHashes.sha; - typeH = SHAh; - digestSz = SHA_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = ssl->certHashes.sha256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = ssl->certHashes.sha384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - - signSz = EncodeSignature(encodedSig, digest,digestSz,typeH); - signBuffer = encodedSig; - } - - c16toa((word16)length, verify + extraSz); /* prepend hdr */ - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - word32 ioLen = ENCRYPT_LEN; - ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, - verify + extraSz + VERIFY_HEADER, - &ioLen, - ssl->buffers.key.buffer, - ssl->buffers.key.length, - ssl->RsaSignCtx); - #endif /* NO_RSA */ - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz + - VERIFY_HEADER, ENCRYPT_LEN, &key, ssl->rng); - } - - if (ret > 0) - ret = 0; /* RSA reset */ - } -#endif - if (ret == 0) { - AddHeaders(output, length + extraSz + VERIFY_HEADER, - certificate_verify, ssl); - - sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + - extraSz + VERIFY_HEADER; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - } - } -#ifndef NO_RSA - if (initRsaKey) - FreeRsaKey(&key); -#endif -#ifdef HAVE_ECC - ecc_free(&eccKey); -#endif - - if (ret == 0) { - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("CertificateVerify", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("CertificateVerify", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - #endif - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); - } - else - return ret; - } -#endif /* NO_CERTS */ - - -#endif /* NO_CYASSL_CLIENT */ - - -#ifndef NO_CYASSL_SERVER - - int SendServerHello(CYASSL* ssl) - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - int ret; - - length = VERSION_SZ + RAN_LEN - + ID_LEN + ENUM_LEN - + SUITE_LEN - + ENUM_LEN; - -#ifdef HAVE_TLS_EXTENSIONS - length += TLSX_GetResponseSize(ssl); -#endif - - /* check for avalaible size */ - if ((ret = CheckAvailableSize(ssl, MAX_HELLO_SZ)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - AddHeaders(output, length, server_hello, ssl); - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - /* now write to output */ - /* first version */ - output[idx++] = ssl->version.major; - output[idx++] = ssl->version.minor; - - /* then random */ - if (!ssl->options.resuming) { - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, - RAN_LEN); - if (ret != 0) - return ret; - } - - XMEMCPY(output + idx, ssl->arrays->serverRandom, RAN_LEN); - idx += RAN_LEN; - -#ifdef SHOW_SECRETS - { - int j; - printf("server random: "); - for (j = 0; j < RAN_LEN; j++) - printf("%02x", ssl->arrays->serverRandom[j]); - printf("\n"); - } -#endif - /* then session id */ - output[idx++] = ID_LEN; - - if (!ssl->options.resuming) { - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, ID_LEN); - if (ret != 0) - return ret; - } - - XMEMCPY(output + idx, ssl->arrays->sessionID, ID_LEN); - idx += ID_LEN; - - /* then cipher suite */ - output[idx++] = ssl->options.cipherSuite0; - output[idx++] = ssl->options.cipherSuite; - - /* then compression */ - if (ssl->options.usingCompression) - output[idx++] = ZLIB_COMPRESSION; - else - output[idx++] = NO_COMPRESSION; - - /* last, extensions */ -#ifdef HAVE_TLS_EXTENSIONS - if (IsTLS(ssl)) - TLSX_WriteResponse(ssl, output + idx); -#endif - - ssl->buffers.outputBuffer.length += sendSz; - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz, - ssl->heap); - #endif - - ssl->options.serverState = SERVER_HELLO_COMPLETE; - - if (ssl->options.groupMessages) - return 0; - else - return SendBuffered(ssl); - } - - -#ifdef HAVE_ECC - - static byte SetCurveId(int size) - { - switch(size) { - case 20: - return secp160r1; - case 24: - return secp192r1; - case 28: - return secp224r1; - case 32: - return secp256r1; - case 48: - return secp384r1; - case 66: - return secp521r1; - default: - return 0; - } - } - -#endif /* HAVE_ECC */ - - - int SendServerKeyExchange(CYASSL* ssl) - { - int ret = 0; - (void)ssl; - - #ifndef NO_PSK - if (ssl->specs.kea == psk_kea) - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - if (ssl->arrays->server_hint[0] == 0) return 0; /* don't send */ - - /* include size part */ - length = (word32)XSTRLEN(ssl->arrays->server_hint); - if (length > MAX_PSK_ID_LEN) return SERVER_HINT_ERROR; - length += HINT_LEN_SZ; - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, server_key_exchange, ssl); - - /* key data */ - c16toa((word16)(length - HINT_LEN_SZ), output + idx); - idx += HINT_LEN_SZ; - XMEMCPY(output + idx, ssl->arrays->server_hint,length -HINT_LEN_SZ); - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - ret = 0; - else - ret = SendBuffered(ssl); - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - } - #endif /*NO_PSK */ - - #ifdef HAVE_ECC - if (ssl->specs.kea == ecc_diffie_hellman_kea) - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - byte exportBuf[MAX_EXPORT_ECC_SZ]; - word32 expSz = sizeof(exportBuf); - word32 sigSz; - word32 preSigSz, preSigIdx; -#ifndef NO_RSA - RsaKey rsaKey; -#endif - ecc_key dsaKey; - - if (ssl->specs.static_ecdh) { - CYASSL_MSG("Using Static ECDH, not sending ServerKeyExchagne"); - return 0; - } - - /* curve type, named curve, length(1) */ - length = ENUM_LEN + CURVE_LEN + ENUM_LEN; - /* pub key size */ - CYASSL_MSG("Using ephemeral ECDH"); - if (ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0) - return ECC_EXPORT_ERROR; - length += expSz; - - preSigSz = length; - preSigIdx = idx; - -#ifndef NO_RSA - ret = InitRsaKey(&rsaKey, ssl->heap); - if (ret != 0) return ret; -#endif - ecc_init(&dsaKey); - - /* sig length */ - length += LENGTH_SZ; - - if (!ssl->buffers.key.buffer) { -#ifndef NO_RSA - FreeRsaKey(&rsaKey); -#endif - ecc_free(&dsaKey); - return NO_PRIVATE_KEY; - } - -#ifndef NO_RSA - if (ssl->specs.sig_algo == rsa_sa_algo) { - /* rsa sig size */ - word32 i = 0; - ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, - &rsaKey, ssl->buffers.key.length); - if (ret != 0) return ret; - sigSz = RsaEncryptSize(&rsaKey); - } else -#endif - if (ssl->specs.sig_algo == ecc_dsa_sa_algo) { - /* ecdsa sig size */ - word32 i = 0; - ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, - &dsaKey, ssl->buffers.key.length); - if (ret != 0) return ret; - sigSz = ecc_sig_size(&dsaKey); /* worst case estimate */ - } - else { -#ifndef NO_RSA - FreeRsaKey(&rsaKey); -#endif - ecc_free(&dsaKey); - return ALGO_ID_E; /* unsupported type */ - } - length += sigSz; - - if (IsAtLeastTLSv1_2(ssl)) - length += HASH_SIG_SIZE; - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - preSigIdx = idx; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { -#ifndef NO_RSA - FreeRsaKey(&rsaKey); -#endif - ecc_free(&dsaKey); - return ret; - } - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - /* record and message headers will be added below, when we're sure - of the sig length */ - - /* key exchange data */ - output[idx++] = named_curve; - output[idx++] = 0x00; /* leading zero */ - output[idx++] = SetCurveId(ecc_size(ssl->eccTempKey)); - output[idx++] = (byte)expSz; - XMEMCPY(output + idx, exportBuf, expSz); - idx += expSz; - if (IsAtLeastTLSv1_2(ssl)) { - output[idx++] = ssl->suites->hashAlgo; - output[idx++] = ssl->suites->sigAlgo; - } - - /* Signtaure length will be written later, when we're sure what it - is */ - - /* do signature */ - { -#ifndef NO_OLD_TLS - Md5 md5; - Sha sha; -#endif - byte hash[FINISHED_SZ]; - #ifndef NO_SHA256 - Sha256 sha256; - byte hash256[SHA256_DIGEST_SIZE]; - #endif - #ifdef CYASSL_SHA384 - Sha384 sha384; - byte hash384[SHA384_DIGEST_SIZE]; - #endif - -#ifndef NO_OLD_TLS - /* md5 */ - InitMd5(&md5); - Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); - Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); - Md5Update(&md5, output + preSigIdx, preSigSz); - Md5Final(&md5, hash); - - /* sha */ - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); - ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); - ShaUpdate(&sha, output + preSigIdx, preSigSz); - ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); -#endif - - #ifndef NO_SHA256 - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha256Final(&sha256, hash256); - if (ret != 0) - return ret; - #endif - - #ifdef CYASSL_SHA384 - ret = InitSha384(&sha384); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha384Final(&sha384, hash384); - if (ret != 0) - return ret; - #endif -#ifndef NO_RSA - if (ssl->suites->sigAlgo == rsa_sa_algo) { - byte* signBuffer = hash; - word32 signSz = sizeof(hash); - byte encodedSig[MAX_ENCODED_SIG_SZ]; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - if (IsAtLeastTLSv1_2(ssl)) { - byte* digest = &hash[MD5_DIGEST_SIZE]; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; - - if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = hash384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - - signSz = EncodeSignature(encodedSig, digest, digestSz, - typeH); - signBuffer = encodedSig; - } - /* write sig size here */ - c16toa((word16)sigSz, output + idx); - idx += LENGTH_SZ; - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - word32 ioLen = sigSz; - ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, - output + idx, - &ioLen, - ssl->buffers.key.buffer, - ssl->buffers.key.length, - ssl->RsaSignCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaSSL_Sign(signBuffer, signSz, output + idx, - sigSz, &rsaKey, ssl->rng); - if (ret > 0) - ret = 0; /* reset on success */ - } - FreeRsaKey(&rsaKey); - ecc_free(&dsaKey); - if (ret < 0) - return ret; - } else -#endif - if (ssl->suites->sigAlgo == ecc_dsa_sa_algo) { -#ifndef NO_OLD_TLS - byte* digest = &hash[MD5_DIGEST_SIZE]; - word32 digestSz = SHA_DIGEST_SIZE; -#else - byte* digest = hash256; - word32 digestSz = SHA256_DIGEST_SIZE; -#endif - word32 sz = sigSz; - byte doUserEcc = 0; - - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - if (ssl->ctx->EccSignCb) - doUserEcc = 1; - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - - if (IsAtLeastTLSv1_2(ssl)) { - if (ssl->suites->hashAlgo == sha_mac) { - #ifndef NO_SHA - digest = &hash[MD5_DIGEST_SIZE]; - digestSz = SHA_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = hash384; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - } - - if (doUserEcc) { - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ret = ssl->ctx->EccSignCb(ssl, digest, digestSz, - output + LENGTH_SZ + idx, &sz, - ssl->buffers.key.buffer, - ssl->buffers.key.length, - ssl->EccSignCtx); - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = ecc_sign_hash(digest, digestSz, - output + LENGTH_SZ + idx, &sz, ssl->rng, &dsaKey); - } -#ifndef NO_RSA - FreeRsaKey(&rsaKey); -#endif - ecc_free(&dsaKey); - if (ret < 0) return ret; - - /* Now that we know the real sig size, write it. */ - c16toa((word16)sz, output + idx); - - /* And adjust length and sendSz from estimates */ - length += sz - sigSz; - sendSz += sz - sigSz; - } - } - - AddHeaders(output, length, server_key_exchange, ssl); - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - ret = 0; - else - ret = SendBuffered(ssl); - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - } - #endif /* HAVE_ECC */ - - #ifdef OPENSSL_EXTRA - if (ssl->specs.kea == diffie_hellman_kea) { - byte *output; - word32 length = 0, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - word32 sigSz = 0, i = 0; - word32 preSigSz = 0, preSigIdx = 0; - RsaKey rsaKey; - DhKey dhKey; - - if (ssl->buffers.serverDH_P.buffer == NULL || - ssl->buffers.serverDH_G.buffer == NULL) - return NO_DH_PARAMS; - - if (ssl->buffers.serverDH_Pub.buffer == NULL) { - ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( - ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, - DYNAMIC_TYPE_DH); - if (ssl->buffers.serverDH_Pub.buffer == NULL) - return MEMORY_E; - } - - if (ssl->buffers.serverDH_Priv.buffer == NULL) { - ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( - ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, - DYNAMIC_TYPE_DH); - if (ssl->buffers.serverDH_Priv.buffer == NULL) - return MEMORY_E; - } - - InitDhKey(&dhKey); - ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length, - ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - if (ret == 0) - ret = DhGenerateKeyPair(&dhKey, ssl->rng, - ssl->buffers.serverDH_Priv.buffer, - &ssl->buffers.serverDH_Priv.length, - ssl->buffers.serverDH_Pub.buffer, - &ssl->buffers.serverDH_Pub.length); - FreeDhKey(&dhKey); - - if (ret == 0) { - ret = InitRsaKey(&rsaKey, ssl->heap); - if (ret != 0) return ret; - } - if (ret == 0) { - length = LENGTH_SZ * 3; /* p, g, pub */ - length += ssl->buffers.serverDH_P.length + - ssl->buffers.serverDH_G.length + - ssl->buffers.serverDH_Pub.length; - - preSigIdx = idx; - preSigSz = length; - - /* sig length */ - length += LENGTH_SZ; - - if (!ssl->buffers.key.buffer) - return NO_PRIVATE_KEY; - - ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, &rsaKey, - ssl->buffers.key.length); - if (ret == 0) { - sigSz = RsaEncryptSize(&rsaKey); - length += sigSz; - } - } - if (ret != 0) { - FreeRsaKey(&rsaKey); - return ret; - } - - if (IsAtLeastTLSv1_2(ssl)) - length += HASH_SIG_SIZE; - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - preSigIdx = idx; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { - FreeRsaKey(&rsaKey); - return ret; - } - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, server_key_exchange, ssl); - - /* add p, g, pub */ - c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length); - idx += ssl->buffers.serverDH_P.length; - - /* g */ - c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - idx += ssl->buffers.serverDH_G.length; - - /* pub */ - c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, - ssl->buffers.serverDH_Pub.length); - idx += ssl->buffers.serverDH_Pub.length; - - /* Add signature */ - if (IsAtLeastTLSv1_2(ssl)) { - output[idx++] = ssl->suites->hashAlgo; - output[idx++] = ssl->suites->sigAlgo; - } - /* size */ - c16toa((word16)sigSz, output + idx); - idx += LENGTH_SZ; - - /* do signature */ - { -#ifndef NO_OLD_TLS - Md5 md5; - Sha sha; -#endif - byte hash[FINISHED_SZ]; - #ifndef NO_SHA256 - Sha256 sha256; - byte hash256[SHA256_DIGEST_SIZE]; - #endif - #ifdef CYASSL_SHA384 - Sha384 sha384; - byte hash384[SHA384_DIGEST_SIZE]; - #endif - -#ifndef NO_OLD_TLS - /* md5 */ - InitMd5(&md5); - Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); - Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); - Md5Update(&md5, output + preSigIdx, preSigSz); - Md5Final(&md5, hash); - - /* sha */ - ret = InitSha(&sha); - if (ret != 0) - return ret; - ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); - ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); - ShaUpdate(&sha, output + preSigIdx, preSigSz); - ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); -#endif - - #ifndef NO_SHA256 - ret = InitSha256(&sha256); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha256Final(&sha256, hash256); - if (ret != 0) - return ret; - #endif - - #ifdef CYASSL_SHA384 - ret = InitSha384(&sha384); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); - if (ret != 0) - return ret; - ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); - if (ret != 0) - return ret; - ret = Sha384Final(&sha384, hash384); - if (ret != 0) - return ret; - #endif -#ifndef NO_RSA - if (ssl->suites->sigAlgo == rsa_sa_algo) { - byte* signBuffer = hash; - word32 signSz = sizeof(hash); - byte encodedSig[MAX_ENCODED_SIG_SZ]; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - if (IsAtLeastTLSv1_2(ssl)) { - byte* digest = &hash[MD5_DIGEST_SIZE]; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; - - if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = hash384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - - signSz = EncodeSignature(encodedSig, digest, digestSz, - typeH); - signBuffer = encodedSig; - } - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - word32 ioLen = sigSz; - ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, - output + idx, - &ioLen, - ssl->buffers.key.buffer, - ssl->buffers.key.length, - ssl->RsaSignCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = RsaSSL_Sign(signBuffer, signSz, output + idx, - sigSz, &rsaKey, ssl->rng); - } - FreeRsaKey(&rsaKey); - if (ret < 0) - return ret; - } -#endif - } - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) - ret = 0; - else - ret = SendBuffered(ssl); - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - } - #endif /* OPENSSL_EXTRA */ - - return ret; - } - - - /* cipher requirements */ - enum { - REQUIRES_RSA, - REQUIRES_DHE, - REQUIRES_ECC_DSA, - REQUIRES_ECC_STATIC, - REQUIRES_PSK, - REQUIRES_NTRU, - REQUIRES_RSA_SIG - }; - - - - /* Does this cipher suite (first, second) have the requirement - an ephemeral key exchange will still require the key for signing - the key exchange so ECHDE_RSA requires an rsa key thus rsa_kea */ - static int CipherRequires(byte first, byte second, int requirement) - { - /* ECC extensions */ - if (first == ECC_BYTE) { - - switch (second) { - -#ifndef NO_RSA - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; - -#ifndef NO_DES3 - case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; -#endif - -#ifndef NO_RC4 - case TLS_ECDHE_RSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_ECDH_RSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; -#endif -#endif /* NO_RSA */ - -#ifndef NO_DES3 - case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; -#endif -#ifndef NO_RC4 - case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; -#endif -#ifndef NO_RSA - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; -#endif - - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; - - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; - - case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; - -#ifndef NO_RSA - case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; - - case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : - if (requirement == REQUIRES_ECC_STATIC) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; - - case TLS_RSA_WITH_AES_128_CCM_8 : - case TLS_RSA_WITH_AES_256_CCM_8 : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; - - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - break; - - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : - if (requirement == REQUIRES_RSA_SIG) - return 1; - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; -#endif - - case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 : - case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : - if (requirement == REQUIRES_ECC_DSA) - return 1; - break; - - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : - if (requirement == REQUIRES_ECC_DSA) - return 1; - if (requirement == REQUIRES_ECC_STATIC) - return 1; - break; - - case TLS_PSK_WITH_AES_128_CCM: - case TLS_PSK_WITH_AES_256_CCM: - case TLS_PSK_WITH_AES_128_CCM_8: - case TLS_PSK_WITH_AES_256_CCM_8: - if (requirement == REQUIRES_PSK) - return 1; - break; - - default: - CYASSL_MSG("Unsupported cipher suite, CipherRequires ECC"); - return 0; - } /* switch */ - } /* if */ - if (first != ECC_BYTE) { /* normal suites */ - switch (second) { - -#ifndef NO_RSA - case SSL_RSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_NTRU_RSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; - - case SSL_RSA_WITH_RC4_128_MD5 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case SSL_RSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; - - case TLS_RSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_AES_128_CBC_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; - - case TLS_RSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_AES_256_CBC_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_NULL_SHA : - case TLS_RSA_WITH_NULL_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; -#endif - - case TLS_PSK_WITH_AES_128_CBC_SHA256 : - case TLS_PSK_WITH_AES_128_CBC_SHA : - case TLS_PSK_WITH_AES_256_CBC_SHA : - case TLS_PSK_WITH_NULL_SHA256 : - case TLS_PSK_WITH_NULL_SHA : - if (requirement == REQUIRES_PSK) - return 1; - break; - -#ifndef NO_RSA - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_DHE) - return 1; - break; - - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_DHE) - return 1; - break; - - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_DHE) - return 1; - break; - - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_DHE) - return 1; - break; - - case TLS_RSA_WITH_HC_128_MD5 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_HC_128_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_HC_128_B2B256: - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_AES_128_CBC_B2B256: - case TLS_RSA_WITH_AES_256_CBC_B2B256: - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_RABBIT_SHA : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_RSA_WITH_AES_128_GCM_SHA256 : - case TLS_RSA_WITH_AES_256_GCM_SHA384 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : - case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_DHE) - return 1; - break; - - case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA : - case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA : - case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 : - case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - break; - - case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA : - case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA : - case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 : - case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 : - if (requirement == REQUIRES_RSA) - return 1; - if (requirement == REQUIRES_RSA_SIG) - return 1; - if (requirement == REQUIRES_DHE) - return 1; - break; -#endif - - default: - CYASSL_MSG("Unsupported cipher suite, CipherRequires"); - return 0; - } /* switch */ - } /* if ECC / Normal suites else */ - - return 0; - } - - - /* Make sure client setup is valid for this suite, true on success */ - int VerifyClientSuite(CYASSL* ssl) - { - int havePSK = 0; - byte first = ssl->options.cipherSuite0; - byte second = ssl->options.cipherSuite; - - CYASSL_ENTER("VerifyClientSuite"); - - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #endif - - if (CipherRequires(first, second, REQUIRES_PSK)) { - CYASSL_MSG("Requires PSK"); - if (havePSK == 0) { - CYASSL_MSG("Don't have PSK"); - return 0; - } - } - - return 1; /* success */ - } - - - /* Make sure server cert/key are valid for this suite, true on success */ - static int VerifyServerSuite(CYASSL* ssl, word16 idx) - { - int haveRSA = !ssl->options.haveStaticECC; - int havePSK = 0; - byte first; - byte second; - - CYASSL_ENTER("VerifyServerSuite"); - - if (ssl->suites == NULL) { - CYASSL_MSG("Suites pointer error"); - return 0; - } - - first = ssl->suites->suites[idx]; - second = ssl->suites->suites[idx+1]; - - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #endif - - if (ssl->options.haveNTRU) - haveRSA = 0; - - if (CipherRequires(first, second, REQUIRES_RSA)) { - CYASSL_MSG("Requires RSA"); - if (haveRSA == 0) { - CYASSL_MSG("Don't have RSA"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_DHE)) { - CYASSL_MSG("Requires DHE"); - if (ssl->options.haveDH == 0) { - CYASSL_MSG("Don't have DHE"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_ECC_DSA)) { - CYASSL_MSG("Requires ECCDSA"); - if (ssl->options.haveECDSAsig == 0) { - CYASSL_MSG("Don't have ECCDSA"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) { - CYASSL_MSG("Requires static ECC"); - if (ssl->options.haveStaticECC == 0) { - CYASSL_MSG("Don't have static ECC"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_PSK)) { - CYASSL_MSG("Requires PSK"); - if (havePSK == 0) { - CYASSL_MSG("Don't have PSK"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_NTRU)) { - CYASSL_MSG("Requires NTRU"); - if (ssl->options.haveNTRU == 0) { - CYASSL_MSG("Don't have NTRU"); - return 0; - } - } - - if (CipherRequires(first, second, REQUIRES_RSA_SIG)) { - CYASSL_MSG("Requires RSA Signature"); - if (ssl->options.side == CYASSL_SERVER_END && - ssl->options.haveECDSAsig == 1) { - CYASSL_MSG("Don't have RSA Signature"); - return 0; - } - } - -#ifdef HAVE_SUPPORTED_CURVES - if (!TLSX_ValidateEllipticCurves(ssl, first, second)) { - CYASSL_MSG("Don't have matching curves"); - return 0; - } -#endif - - /* ECCDHE is always supported if ECC on */ - - return 1; - } - - - static int MatchSuite(CYASSL* ssl, Suites* peerSuites) - { - word16 i, j; - - CYASSL_ENTER("MatchSuite"); - - /* & 0x1 equivalent % 2 */ - if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1) - return MATCH_SUITE_ERROR; - - if (ssl->suites == NULL) - return SUITES_ERROR; - /* start with best, if a match we are good */ - for (i = 0; i < ssl->suites->suiteSz; i += 2) - for (j = 0; j < peerSuites->suiteSz; j += 2) - if (ssl->suites->suites[i] == peerSuites->suites[j] && - ssl->suites->suites[i+1] == peerSuites->suites[j+1] ) { - - if (VerifyServerSuite(ssl, i)) { - int result; - CYASSL_MSG("Verified suite validity"); - ssl->options.cipherSuite0 = ssl->suites->suites[i]; - ssl->options.cipherSuite = ssl->suites->suites[i+1]; - result = SetCipherSpecs(ssl); - if (result == 0) - PickHashSigAlgo(ssl, peerSuites->hashSigAlgo, - peerSuites->hashSigAlgoSz); - return result; - } - else { - CYASSL_MSG("Could not verify suite validity, continue"); - } - } - - return MATCH_SUITE_ERROR; - } - - - /* process old style client hello, deprecate? */ - int ProcessOldClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 inSz, word16 sz) - { - word32 idx = *inOutIdx; - word16 sessionSz; - word16 randomSz; - word16 i, j; - ProtocolVersion pv; - Suites clSuites; - - (void)inSz; - CYASSL_MSG("Got old format client hello"); -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ClientHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("ClientHello", &ssl->timeoutInfo); -#endif - - /* manually hash input since different format */ -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - Md5Update(&ssl->hashMd5, input + idx, sz); -#endif -#ifndef NO_SHA - ShaUpdate(&ssl->hashSha, input + idx, sz); -#endif -#endif -#ifndef NO_SHA256 - if (IsAtLeastTLSv1_2(ssl)) { - int shaRet = Sha256Update(&ssl->hashSha256, input + idx, sz); - - if (shaRet != 0) - return shaRet; - } -#endif - - /* does this value mean client_hello? */ - idx++; - - /* version */ - pv.major = input[idx++]; - pv.minor = input[idx++]; - ssl->chVersion = pv; /* store */ - - if (ssl->version.minor > pv.minor) { - byte haveRSA = 0; - byte havePSK = 0; - if (!ssl->options.downgrade) { - CYASSL_MSG("Client trying to connect with lesser version"); - return VERSION_ERROR; - } - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - CYASSL_MSG(" downgrading to SSLv3"); - ssl->options.tls = 0; - ssl->options.tls1_1 = 0; - ssl->version.minor = SSLv3_MINOR; - } - else if (pv.minor == TLSv1_MINOR) { - CYASSL_MSG(" downgrading to TLSv1"); - /* turn off tls 1.1+ */ - ssl->options.tls1_1 = 0; - ssl->version.minor = TLSv1_MINOR; - } - else if (pv.minor == TLSv1_1_MINOR) { - CYASSL_MSG(" downgrading to TLSv1.1"); - ssl->version.minor = TLSv1_1_MINOR; - } -#ifndef NO_RSA - haveRSA = 1; -#endif -#ifndef NO_PSK - havePSK = ssl->options.havePSK; -#endif - - InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, - ssl->options.haveDH, ssl->options.haveNTRU, - ssl->options.haveECDSAsig, ssl->options.haveStaticECC, - ssl->options.side); - } - - /* suite size */ - ato16(&input[idx], &clSuites.suiteSz); - idx += 2; - - if (clSuites.suiteSz > MAX_SUITE_SZ) - return BUFFER_ERROR; - clSuites.hashSigAlgoSz = 0; - - /* session size */ - ato16(&input[idx], &sessionSz); - idx += 2; - - if (sessionSz > ID_LEN) - return BUFFER_ERROR; - - /* random size */ - ato16(&input[idx], &randomSz); - idx += 2; - - if (randomSz > RAN_LEN) - return BUFFER_ERROR; - - /* suites */ - for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) { - byte first = input[idx++]; - if (!first) { /* implicit: skip sslv2 type */ - XMEMCPY(&clSuites.suites[j], &input[idx], 2); - j += 2; - } - idx += 2; - } - clSuites.suiteSz = j; - - /* session id */ - if (sessionSz) { - XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz); - idx += sessionSz; - ssl->options.resuming = 1; - } - - /* random */ - if (randomSz < RAN_LEN) - XMEMSET(ssl->arrays->clientRandom, 0, RAN_LEN - randomSz); - XMEMCPY(&ssl->arrays->clientRandom[RAN_LEN - randomSz], input + idx, - randomSz); - idx += randomSz; - - if (ssl->options.usingCompression) - ssl->options.usingCompression = 0; /* turn off */ - - ssl->options.clientState = CLIENT_HELLO_COMPLETE; - *inOutIdx = idx; - - ssl->options.haveSessionId = 1; - /* DoClientHello uses same resume code */ - if (ssl->options.resuming) { /* let's try */ - int ret = -1; - CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); - if (!session) { - CYASSL_MSG("Session lookup for resume failed"); - ssl->options.resuming = 0; - } else { - if (MatchSuite(ssl, &clSuites) < 0) { - CYASSL_MSG("Unsupported cipher suite, OldClientHello"); - return UNSUPPORTED_SUITE; - } - #ifdef SESSION_CERTS - ssl->session = *session; /* restore session certs. */ - #endif - - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, - RAN_LEN); - if (ret != 0) - return ret; - - #ifdef NO_OLD_TLS - ret = DeriveTlsKeys(ssl); - #else - #ifndef NO_TLS - if (ssl->options.tls) - ret = DeriveTlsKeys(ssl); - #endif - if (!ssl->options.tls) - ret = DeriveKeys(ssl); - #endif - ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - - return ret; - } - } - - return MatchSuite(ssl, &clSuites); - } - - - static int DoClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 helloSz) - { - byte b; - ProtocolVersion pv; - Suites clSuites; - word32 i = *inOutIdx; - word32 begin = i; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); -#endif - - /* protocol version, random and session id length check */ - if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - /* protocol version */ - XMEMCPY(&pv, input + i, OPAQUE16_LEN); - ssl->chVersion = pv; /* store */ - i += OPAQUE16_LEN; - - if (ssl->version.minor > pv.minor) { - byte haveRSA = 0; - byte havePSK = 0; - - if (!ssl->options.downgrade) { - CYASSL_MSG("Client trying to connect with lesser version"); - return VERSION_ERROR; - } - - if (pv.minor == SSLv3_MINOR) { - /* turn off tls */ - CYASSL_MSG(" downgrading to SSLv3"); - ssl->options.tls = 0; - ssl->options.tls1_1 = 0; - ssl->version.minor = SSLv3_MINOR; - } - else if (pv.minor == TLSv1_MINOR) { - /* turn off tls 1.1+ */ - CYASSL_MSG(" downgrading to TLSv1"); - ssl->options.tls1_1 = 0; - ssl->version.minor = TLSv1_MINOR; - } - else if (pv.minor == TLSv1_1_MINOR) { - CYASSL_MSG(" downgrading to TLSv1.1"); - ssl->version.minor = TLSv1_1_MINOR; - } -#ifndef NO_RSA - haveRSA = 1; -#endif -#ifndef NO_PSK - havePSK = ssl->options.havePSK; -#endif - InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, - ssl->options.haveDH, ssl->options.haveNTRU, - ssl->options.haveECDSAsig, ssl->options.haveStaticECC, - ssl->options.side); - } - - /* random */ - XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); - i += RAN_LEN; - -#ifdef SHOW_SECRETS - { - int j; - printf("client random: "); - for (j = 0; j < RAN_LEN; j++) - printf("%02x", ssl->arrays->clientRandom[j]); - printf("\n"); - } -#endif - - /* session id */ - b = input[i++]; - - if (b == ID_LEN) { - if ((i - begin) + ID_LEN > helloSz) - return BUFFER_ERROR; - - XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN); - i += ID_LEN; - ssl->options.resuming = 1; /* client wants to resume */ - CYASSL_MSG("Client wants to resume session"); - } - else if (b) { - CYASSL_MSG("Invalid session ID size"); - return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ - } - - #ifdef CYASSL_DTLS - /* cookie */ - if (ssl->options.dtls) { - - if ((i - begin) + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - b = input[i++]; - - if (b) { - byte cookie[MAX_COOKIE_LEN]; - - if (b > MAX_COOKIE_LEN) - return BUFFER_ERROR; - - if ((i - begin) + b > helloSz) - return BUFFER_ERROR; - - if (ssl->ctx->CBIOCookie == NULL) { - CYASSL_MSG("Your Cookie callback is null, please set"); - return COOKIE_ERROR; - } - - if ((ssl->ctx->CBIOCookie(ssl, cookie, COOKIE_SZ, - ssl->IOCB_CookieCtx) != COOKIE_SZ) - || (b != COOKIE_SZ) - || (XMEMCMP(cookie, input + i, b) != 0)) { - return COOKIE_ERROR; - } - - i += b; - } - } - #endif - - /* suites */ - if ((i - begin) + OPAQUE16_LEN > helloSz) - return BUFFER_ERROR; - - ato16(&input[i], &clSuites.suiteSz); - i += OPAQUE16_LEN; - - /* suites and compression length check */ - if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - if (clSuites.suiteSz > MAX_SUITE_SZ) - return BUFFER_ERROR; - - XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); - i += clSuites.suiteSz; - clSuites.hashSigAlgoSz = 0; - - /* compression length */ - b = input[i++]; - - if ((i - begin) + b > helloSz) - return BUFFER_ERROR; - - if (ssl->options.usingCompression) { - int match = 0; - - while (b--) { - byte comp = input[i++]; - - if (comp == ZLIB_COMPRESSION) - match = 1; - } - - if (!match) { - CYASSL_MSG("Not matching compression, turning off"); - ssl->options.usingCompression = 0; /* turn off */ - } - } - else - i += b; /* ignore, since we're not on */ - - *inOutIdx = i; - - /* tls extensions */ - if ((i - begin) < helloSz) { -#ifdef HAVE_TLS_EXTENSIONS - if (IsTLS(ssl)) { - int ret = 0; -#else - if (IsAtLeastTLSv1_2(ssl)) { -#endif - /* Process the hello extension. Skip unsupported. */ - word16 totalExtSz; - - if ((i - begin) + OPAQUE16_LEN > helloSz) - return BUFFER_ERROR; - - ato16(&input[i], &totalExtSz); - i += OPAQUE16_LEN; - - if ((i - begin) + totalExtSz > helloSz) - return BUFFER_ERROR; - -#ifdef HAVE_TLS_EXTENSIONS - if ((ret = TLSX_Parse(ssl, (byte *) input + i, - totalExtSz, 1, &clSuites))) - return ret; - - i += totalExtSz; -#else - while (totalExtSz) { - word16 extId, extSz; - - if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz) - return BUFFER_ERROR; - - ato16(&input[i], &extId); - i += OPAQUE16_LEN; - ato16(&input[i], &extSz); - i += OPAQUE16_LEN; - - if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz) - return BUFFER_ERROR; - - if (extId == HELLO_EXT_SIG_ALGO) { - ato16(&input[i], &clSuites.hashSigAlgoSz); - i += OPAQUE16_LEN; - - if (OPAQUE16_LEN + clSuites.hashSigAlgoSz > extSz) - return BUFFER_ERROR; - - XMEMCPY(clSuites.hashSigAlgo, &input[i], - min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX)); - i += clSuites.hashSigAlgoSz; - } - else - i += extSz; - - totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz; - } -#endif - *inOutIdx = i; - } - else - *inOutIdx = begin + helloSz; /* skip extensions */ - } - - ssl->options.clientState = CLIENT_HELLO_COMPLETE; - ssl->options.haveSessionId = 1; - - /* ProcessOld uses same resume code */ - if (ssl->options.resuming && (!ssl->options.dtls || - ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */ - int ret = -1; - CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); - - if (!session) { - CYASSL_MSG("Session lookup for resume failed"); - ssl->options.resuming = 0; - } - else { - if (MatchSuite(ssl, &clSuites) < 0) { - CYASSL_MSG("Unsupported cipher suite, ClientHello"); - return UNSUPPORTED_SUITE; - } - #ifdef SESSION_CERTS - ssl->session = *session; /* restore session certs. */ - #endif - - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, - RAN_LEN); - if (ret != 0) - return ret; - - #ifdef NO_OLD_TLS - ret = DeriveTlsKeys(ssl); - #else - #ifndef NO_TLS - if (ssl->options.tls) - ret = DeriveTlsKeys(ssl); - #endif - if (!ssl->options.tls) - ret = DeriveKeys(ssl); - #endif - ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - - return ret; - } - } - return MatchSuite(ssl, &clSuites); - } - -#if !defined(NO_RSA) || defined(HAVE_ECC) - static int DoCertificateVerify(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 size) - { - word16 sz = 0; - int ret = VERIFY_CERT_ERROR; /* start in error state */ - byte hashAlgo = sha_mac; - byte sigAlgo = anonymous_sa_algo; - word32 begin = *inOutIdx; - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("CertificateVerify", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("CertificateVerify", &ssl->timeoutInfo); - #endif - - - if (IsAtLeastTLSv1_2(ssl)) { - if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size) - return BUFFER_ERROR; - - hashAlgo = input[(*inOutIdx)++]; - sigAlgo = input[(*inOutIdx)++]; - } - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &sz); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + sz > size || sz > ENCRYPT_LEN) - return BUFFER_ERROR; - - /* RSA */ -#ifndef NO_RSA - if (ssl->peerRsaKeyPresent != 0) { - byte* out = NULL; - int outLen = 0; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaVerifyCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - - CYASSL_MSG("Doing RSA peer cert verify"); - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - outLen = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, sz, - &out, - ssl->buffers.peerRsaKey.buffer, - ssl->buffers.peerRsaKey.length, - ssl->RsaVerifyCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - outLen = RsaSSL_VerifyInline(input + *inOutIdx, sz, &out, - ssl->peerRsaKey); - } - - if (IsAtLeastTLSv1_2(ssl)) { - byte encodedSig[MAX_ENCODED_SIG_SZ]; - word32 sigSz; - byte* digest = ssl->certHashes.sha; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; - - if (sigAlgo != rsa_sa_algo) { - CYASSL_MSG("Oops, peer sent RSA key but not in verify"); - } - - if (hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = ssl->certHashes.sha256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = ssl->certHashes.sha384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - - sigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); - - if (outLen == (int)sigSz && out && XMEMCMP(out, encodedSig, - min(sigSz, MAX_ENCODED_SIG_SZ)) == 0) - ret = 0; /* verified */ - } - else { - if (outLen == FINISHED_SZ && out && XMEMCMP(out, - &ssl->certHashes, FINISHED_SZ) == 0) - ret = 0; /* verified */ - } - } -#endif -#ifdef HAVE_ECC - if (ssl->peerEccDsaKeyPresent) { - int verify = 0; - int err = -1; - byte* digest = ssl->certHashes.sha; - word32 digestSz = SHA_DIGEST_SIZE; - byte doUserEcc = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->EccVerifyCb) - doUserEcc = 1; - #endif - - CYASSL_MSG("Doing ECC peer cert verify"); - - if (IsAtLeastTLSv1_2(ssl)) { - if (sigAlgo != ecc_dsa_sa_algo) { - CYASSL_MSG("Oops, peer sent ECC key but not in verify"); - } - - if (hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = ssl->certHashes.sha256; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (hashAlgo == sha384_mac) { - #ifdef CYASSL_SHA384 - digest = ssl->certHashes.sha384; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - } - - if (doUserEcc) { - #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, sz, digest, - digestSz, - ssl->buffers.peerEccDsaKey.buffer, - ssl->buffers.peerEccDsaKey.length, - &verify, ssl->EccVerifyCtx); - #endif - } - else { - err = ecc_verify_hash(input + *inOutIdx, sz, digest, digestSz, - &verify, ssl->peerEccDsaKey); - } - - if (err == 0 && verify == 1) - ret = 0; /* verified */ - } -#endif - *inOutIdx += sz; - - if (ret == 0) - ssl->options.havePeerVerify = 1; - - return ret; - } -#endif /* !NO_RSA || HAVE_ECC */ - - int SendServerHelloDone(CYASSL* ssl) - { - byte *output; - int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int ret; - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, 0, server_hello_done, ssl); - - #ifdef CYASSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return 0; - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ServerHelloDone", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz, - ssl->heap); -#endif - ssl->options.serverState = SERVER_HELLODONE_COMPLETE; - - ssl->buffers.outputBuffer.length += sendSz; - - return SendBuffered(ssl); - } - -#ifdef CYASSL_DTLS - int SendHelloVerifyRequest(CYASSL* ssl) - { - byte* output; - byte cookieSz = COOKIE_SZ; - int length = VERSION_SZ + ENUM_LEN + cookieSz; - int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; - int sendSz = length + idx; - int ret; - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - /* get ouput buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, hello_verify_request, ssl); - - output[idx++] = ssl->chVersion.major; - output[idx++] = ssl->chVersion.minor; - - output[idx++] = cookieSz; - if (ssl->ctx->CBIOCookie == NULL) { - CYASSL_MSG("Your Cookie callback is null, please set"); - return COOKIE_ERROR; - } - if ((ret = ssl->ctx->CBIOCookie(ssl, output + idx, cookieSz, - ssl->IOCB_CookieCtx)) < 0) - return ret; - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - -#ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output, - sendSz, ssl->heap); -#endif - ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; - - ssl->buffers.outputBuffer.length += sendSz; - - return SendBuffered(ssl); - } -#endif - - static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32* inOutIdx, - word32 size) - { - int ret = 0; - word32 length = 0; - byte* out = NULL; - word32 begin = *inOutIdx; - - (void)length; /* shut up compiler warnings */ - (void)out; - (void)input; - (void)size; - - if (ssl->options.side != CYASSL_SERVER_END) { - CYASSL_MSG("Client received client keyexchange, attack?"); - CYASSL_ERROR(ssl->error = SIDE_ERROR); - return SSL_FATAL_ERROR; - } - - if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { - CYASSL_MSG("Client sending keyexchange at wrong time"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - #ifndef NO_CERTS - if (ssl->options.verifyPeer && ssl->options.failNoCert) - if (!ssl->options.havePeerCert) { - CYASSL_MSG("client didn't present peer cert"); - return NO_PEER_CERT; - } - #endif - - #ifdef CYASSL_CALLBACKS - if (ssl->hsInfoOn) - AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); - if (ssl->toInfoOn) - AddLateName("ClientKeyExchange", &ssl->timeoutInfo); - #endif - - switch (ssl->specs.kea) { - #ifndef NO_RSA - case rsa_kea: - { - word32 idx = 0; - RsaKey key; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaDecCb) - doUserRsa = 1; - #endif - - ret = InitRsaKey(&key, ssl->heap); - if (ret != 0) return ret; - - if (ssl->buffers.key.buffer) - ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, - &key, ssl->buffers.key.length); - else - return NO_PRIVATE_KEY; - - if (ret == 0) { - length = RsaEncryptSize(&key); - ssl->arrays->preMasterSz = SECRET_LEN; - - if (ssl->options.tls) { - word16 check; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &check); - *inOutIdx += OPAQUE16_LEN; - - if ((word32) check != length) { - CYASSL_MSG("RSA explicit size doesn't match"); - FreeRsaKey(&key); - return RSA_PRIVATE_ERROR; - } - } - - if ((*inOutIdx - begin) + length > size) { - CYASSL_MSG("RSA message too big"); - FreeRsaKey(&key); - return BUFFER_ERROR; - } - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->RsaDecCb(ssl, - input + *inOutIdx, length, &out, - ssl->buffers.key.buffer, - ssl->buffers.key.length, - ssl->RsaDecCtx); - #endif - } - else { - ret = RsaPrivateDecryptInline(input + *inOutIdx, length, - &out, &key); - } - - *inOutIdx += length; - - if (ret == SECRET_LEN) { - XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN); - if (ssl->arrays->preMasterSecret[0] != - ssl->chVersion.major - || ssl->arrays->preMasterSecret[1] != - ssl->chVersion.minor) - ret = PMS_VERSION_ERROR; - else - ret = MakeMasterSecret(ssl); - } - else { - ret = RSA_PRIVATE_ERROR; - } - } - - FreeRsaKey(&key); - } - break; - #endif - #ifndef NO_PSK - case psk_kea: - { - byte* pms = ssl->arrays->preMasterSecret; - word16 ci_sz; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &ci_sz); - *inOutIdx += OPAQUE16_LEN; - - if (ci_sz > MAX_PSK_ID_LEN) - return CLIENT_ID_ERROR; - - if ((*inOutIdx - begin) + ci_sz > size) - return BUFFER_ERROR; - - XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz); - *inOutIdx += ci_sz; - - ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0; - ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, - ssl->arrays->client_identity, ssl->arrays->psk_key, - MAX_PSK_KEY_LEN); - - if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) - return PSK_KEY_ERROR; - - /* make psk pre master secret */ - /* length of key + length 0s + length of key + key */ - c16toa((word16) ssl->arrays->psk_keySz, pms); - pms += OPAQUE16_LEN; - - XMEMSET(pms, 0, ssl->arrays->psk_keySz); - pms += ssl->arrays->psk_keySz; - - c16toa((word16) ssl->arrays->psk_keySz, pms); - pms += OPAQUE16_LEN; - - XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; - - ret = MakeMasterSecret(ssl); - - /* No further need for PSK */ - XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); - ssl->arrays->psk_keySz = 0; - } - break; - #endif /* NO_PSK */ - #ifdef HAVE_NTRU - case ntru_kea: - { - word16 cipherLen; - word16 plainLen = sizeof(ssl->arrays->preMasterSecret); - - if (!ssl->buffers.key.buffer) - return NO_PRIVATE_KEY; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &cipherLen); - *inOutIdx += OPAQUE16_LEN; - - if (cipherLen > MAX_NTRU_ENCRYPT_SZ) - return NTRU_KEY_ERROR; - - if ((*inOutIdx - begin) + cipherLen > size) - return BUFFER_ERROR; - - if (NTRU_OK != crypto_ntru_decrypt( - (word16) ssl->buffers.key.length, - ssl->buffers.key.buffer, cipherLen, - input + *inOutIdx, &plainLen, - ssl->arrays->preMasterSecret)) - return NTRU_DECRYPT_ERROR; - - if (plainLen != SECRET_LEN) - return NTRU_DECRYPT_ERROR; - - *inOutIdx += cipherLen; - - ssl->arrays->preMasterSz = plainLen; - ret = MakeMasterSecret(ssl); - } - break; - #endif /* HAVE_NTRU */ - #ifdef HAVE_ECC - case ecc_diffie_hellman_kea: - { - if ((*inOutIdx - begin) + OPAQUE8_LEN > size) - return BUFFER_ERROR; - - length = input[(*inOutIdx)++]; - - if ((*inOutIdx - begin) + length > size) - return BUFFER_ERROR; - - if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey)) - return ECC_PEERKEY_ERROR; - - *inOutIdx += length; - ssl->peerEccKeyPresent = 1; - - length = sizeof(ssl->arrays->preMasterSecret); - - if (ssl->specs.static_ecdh) { - ecc_key staticKey; - word32 i = 0; - - ecc_init(&staticKey); - ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, - &staticKey, ssl->buffers.key.length); - - if (ret == 0) - ret = ecc_shared_secret(&staticKey, ssl->peerEccKey, - ssl->arrays->preMasterSecret, &length); - - ecc_free(&staticKey); - } - else - ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey, - ssl->arrays->preMasterSecret, &length); - - if (ret != 0) - return ECC_SHARED_ERROR; - - ssl->arrays->preMasterSz = length; - ret = MakeMasterSecret(ssl); - } - break; - #endif /* HAVE_ECC */ - #ifdef OPENSSL_EXTRA - case diffie_hellman_kea: - { - word16 clientPubSz; - DhKey dhKey; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &clientPubSz); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + clientPubSz > size) - return BUFFER_ERROR; - - InitDhKey(&dhKey); - ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length, - ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - if (ret == 0) - ret = DhAgree(&dhKey, ssl->arrays->preMasterSecret, - &ssl->arrays->preMasterSz, - ssl->buffers.serverDH_Priv.buffer, - ssl->buffers.serverDH_Priv.length, - input + *inOutIdx, clientPubSz); - FreeDhKey(&dhKey); - - *inOutIdx += clientPubSz; - - if (ret == 0) - ret = MakeMasterSecret(ssl); - } - break; - #endif /* OPENSSL_EXTRA */ - default: - { - CYASSL_MSG("Bad kea type"); - ret = BAD_KEA_TYPE_E; - } - break; - } - - /* No further need for PMS */ - XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz); - ssl->arrays->preMasterSz = 0; - - if (ret == 0) { - ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - #ifndef NO_CERTS - if (ssl->options.verifyPeer) - ret = BuildCertHashes(ssl, &ssl->certHashes); - #endif - } - - return ret; - } - -#endif /* NO_CYASSL_SERVER */ - +/* internal.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <cyassl/ctaocrypt/settings.h> + +#include <cyassl/internal.h> +#include <cyassl/error-ssl.h> +#include <cyassl/ctaocrypt/asn.h> + +#ifdef HAVE_LIBZ + #include "zlib.h" +#endif + +#ifdef HAVE_NTRU + #include "crypto_ntru.h" +#endif + +#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) + #ifdef FREESCALE_MQX + #include <fio.h> + #else + #include <stdio.h> + #endif +#endif + +#ifdef __sun + #include <sys/filio.h> +#endif + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + + +#if defined(OPENSSL_EXTRA) && defined(NO_DH) + #error OPENSSL_EXTRA needs DH, please remove NO_DH +#endif + +#if defined(CYASSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS) + #error \ +CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS +#endif + + +#ifndef NO_CYASSL_CLIENT + static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*, + word32); + static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); + static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*, + word32); + #ifndef NO_CERTS + static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*, + word32); + #endif +#endif + + +#ifndef NO_CYASSL_SERVER + static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32); + static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32*, word32); + #if !defined(NO_RSA) || defined(HAVE_ECC) + static int DoCertificateVerify(CYASSL* ssl, byte*, word32*, word32); + #endif +#endif + + +#ifdef CYASSL_DTLS + static INLINE int DtlsCheckWindow(DtlsState* state); + static INLINE int DtlsUpdateWindow(DtlsState* state); +#endif + + +typedef enum { + doProcessInit = 0, +#ifndef NO_CYASSL_SERVER + runProcessOldClientHello, +#endif + getRecordLayerHeader, + getData, + runProcessingOneMessage +} processReply; + +#ifndef NO_OLD_TLS +static int SSL_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz, + int content, int verify); + +#endif + +#ifndef NO_CERTS +static int BuildCertHashes(CYASSL* ssl, Hashes* hashes); +#endif + +static void PickHashSigAlgo(CYASSL* ssl, + const byte* hashSigAlgo, word32 hashSigAlgoSz); + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +int IsTLS(const CYASSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR) + return 1; + + return 0; +} + + +int IsAtLeastTLSv1_2(const CYASSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR) + return 1; + if (ssl->version.major == DTLS_MAJOR && ssl->version.minor <= DTLSv1_2_MINOR) + return 1; + + return 0; +} + + +#ifdef HAVE_NTRU + +static byte GetEntropy(ENTROPY_CMD cmd, byte* out) +{ + /* TODO: add locking? */ + static RNG rng; + + if (cmd == INIT) + return (InitRng(&rng) == 0) ? 1 : 0; + + if (out == NULL) + return 0; + + if (cmd == GET_BYTE_OF_ENTROPY) + return (RNG_GenerateBlock(&rng, out, 1) == 0) ? 1 : 0; + + if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) { + *out = 1; + return 1; + } + + return 0; +} + +#endif /* HAVE_NTRU */ + +/* used by ssl.c too */ +void c32to24(word32 in, word24 out) +{ + out[0] = (in >> 16) & 0xff; + out[1] = (in >> 8) & 0xff; + out[2] = in & 0xff; +} + + +#ifdef CYASSL_DTLS + +static INLINE void c32to48(word32 in, byte out[6]) +{ + out[0] = 0; + out[1] = 0; + out[2] = (in >> 24) & 0xff; + out[3] = (in >> 16) & 0xff; + out[4] = (in >> 8) & 0xff; + out[5] = in & 0xff; +} + +#endif /* CYASSL_DTLS */ + + +/* convert 16 bit integer to opaque */ +static INLINE void c16toa(word16 u16, byte* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + + +/* convert 32 bit integer to opaque */ +static INLINE void c32toa(word32 u32, byte* c) +{ + c[0] = (u32 >> 24) & 0xff; + c[1] = (u32 >> 16) & 0xff; + c[2] = (u32 >> 8) & 0xff; + c[3] = u32 & 0xff; +} + + +/* convert a 24 bit integer into a 32 bit one */ +static INLINE void c24to32(const word24 u24, word32* u32) +{ + *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; +} + + +/* convert opaque to 16 bit integer */ +static INLINE void ato16(const byte* c, word16* u16) +{ + *u16 = (word16) ((c[0] << 8) | (c[1])); +} + + +#ifdef CYASSL_DTLS + +/* convert opaque to 32 bit integer */ +static INLINE void ato32(const byte* c, word32* u32) +{ + *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; +} + +#endif /* CYASSL_DTLS */ + + +#ifdef HAVE_LIBZ + + /* alloc user allocs to work with zlib */ + static void* myAlloc(void* opaque, unsigned int item, unsigned int size) + { + (void)opaque; + return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ); + } + + + static void myFree(void* opaque, void* memory) + { + (void)opaque; + XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ); + } + + + /* init zlib comp/decomp streams, 0 on success */ + static int InitStreams(CYASSL* ssl) + { + ssl->c_stream.zalloc = (alloc_func)myAlloc; + ssl->c_stream.zfree = (free_func)myFree; + ssl->c_stream.opaque = (voidpf)ssl->heap; + + if (deflateInit(&ssl->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) + return ZLIB_INIT_ERROR; + + ssl->didStreamInit = 1; + + ssl->d_stream.zalloc = (alloc_func)myAlloc; + ssl->d_stream.zfree = (free_func)myFree; + ssl->d_stream.opaque = (voidpf)ssl->heap; + + if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR; + + return 0; + } + + + static void FreeStreams(CYASSL* ssl) + { + if (ssl->didStreamInit) { + deflateEnd(&ssl->c_stream); + inflateEnd(&ssl->d_stream); + } + } + + + /* compress in to out, return out size or error */ + static int myCompress(CYASSL* ssl, byte* in, int inSz, byte* out, int outSz) + { + int err; + int currTotal = (int)ssl->c_stream.total_out; + + ssl->c_stream.next_in = in; + ssl->c_stream.avail_in = inSz; + ssl->c_stream.next_out = out; + ssl->c_stream.avail_out = outSz; + + err = deflate(&ssl->c_stream, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR; + + return (int)ssl->c_stream.total_out - currTotal; + } + + + /* decompress in to out, returnn out size or error */ + static int myDeCompress(CYASSL* ssl, byte* in,int inSz, byte* out,int outSz) + { + int err; + int currTotal = (int)ssl->d_stream.total_out; + + ssl->d_stream.next_in = in; + ssl->d_stream.avail_in = inSz; + ssl->d_stream.next_out = out; + ssl->d_stream.avail_out = outSz; + + err = inflate(&ssl->d_stream, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR; + + return (int)ssl->d_stream.total_out - currTotal; + } + +#endif /* HAVE_LIBZ */ + + +void InitSSL_Method(CYASSL_METHOD* method, ProtocolVersion pv) +{ + method->version = pv; + method->side = CYASSL_CLIENT_END; + method->downgrade = 0; +} + + +/* Initialze SSL context, return 0 on success */ +int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method) +{ + ctx->method = method; + ctx->refCount = 1; /* so either CTX_free or SSL_free can release */ +#ifndef NO_CERTS + ctx->certificate.buffer = 0; + ctx->certChain.buffer = 0; + ctx->privateKey.buffer = 0; + ctx->serverDH_P.buffer = 0; + ctx->serverDH_G.buffer = 0; +#endif + ctx->haveDH = 0; + ctx->haveNTRU = 0; /* start off */ + ctx->haveECDSAsig = 0; /* start off */ + ctx->haveStaticECC = 0; /* start off */ + ctx->heap = ctx; /* defaults to self */ +#ifndef NO_PSK + ctx->havePSK = 0; + ctx->server_hint[0] = 0; + ctx->client_psk_cb = 0; + ctx->server_psk_cb = 0; +#endif /* NO_PSK */ +#ifdef HAVE_ECC + ctx->eccTempKeySz = ECDHE_SIZE; +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + ctx->passwd_cb = 0; + ctx->userdata = 0; +#endif /* OPENSSL_EXTRA */ + + ctx->timeout = DEFAULT_TIMEOUT; + +#ifndef CYASSL_USER_IO + ctx->CBIORecv = EmbedReceive; + ctx->CBIOSend = EmbedSend; + #ifdef CYASSL_DTLS + if (method->version.major == DTLS_MAJOR) { + ctx->CBIORecv = EmbedReceiveFrom; + ctx->CBIOSend = EmbedSendTo; + ctx->CBIOCookie = EmbedGenerateCookie; + } + #endif +#else + /* user will set */ + ctx->CBIORecv = NULL; + ctx->CBIOSend = NULL; + #ifdef CYASSL_DTLS + ctx->CBIOCookie = NULL; + #endif +#endif /* CYASSL_USER_IO */ +#ifdef HAVE_NETX + ctx->CBIORecv = NetX_Receive; + ctx->CBIOSend = NetX_Send; +#endif + ctx->partialWrite = 0; + ctx->verifyCallback = 0; + +#ifndef NO_CERTS + ctx->cm = CyaSSL_CertManagerNew(); +#endif +#ifdef HAVE_NTRU + if (method->side == CYASSL_CLIENT_END) + ctx->haveNTRU = 1; /* always on cliet side */ + /* server can turn on by loading key */ +#endif +#ifdef HAVE_ECC + if (method->side == CYASSL_CLIENT_END) { + ctx->haveECDSAsig = 1; /* always on cliet side */ + ctx->haveStaticECC = 1; /* server can turn on by loading key */ + } +#endif + ctx->suites.setSuites = 0; /* user hasn't set yet */ + /* remove DH later if server didn't set, add psk later */ + InitSuites(&ctx->suites, method->version, TRUE, FALSE, TRUE, ctx->haveNTRU, + ctx->haveECDSAsig, ctx->haveStaticECC, method->side); + ctx->verifyPeer = 0; + ctx->verifyNone = 0; + ctx->failNoCert = 0; + ctx->sessionCacheOff = 0; /* initially on */ + ctx->sessionCacheFlushOff = 0; /* initially on */ + ctx->sendVerify = 0; + ctx->quietShutdown = 0; + ctx->groupMessages = 0; +#ifdef HAVE_CAVIUM + ctx->devId = NO_CAVIUM_DEVICE; +#endif +#ifdef HAVE_TLS_EXTENSIONS + ctx->extensions = NULL; +#endif +#ifdef ATOMIC_USER + ctx->MacEncryptCb = NULL; + ctx->DecryptVerifyCb = NULL; +#endif +#ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ctx->EccSignCb = NULL; + ctx->EccVerifyCb = NULL; + #endif /* HAVE_ECC */ + #ifndef NO_RSA + ctx->RsaSignCb = NULL; + ctx->RsaVerifyCb = NULL; + ctx->RsaEncCb = NULL; + ctx->RsaDecCb = NULL; + #endif /* NO_RSA */ +#endif /* HAVE_PK_CALLBACKS */ + + if (InitMutex(&ctx->countMutex) < 0) { + CYASSL_MSG("Mutex error on CTX init"); + return BAD_MUTEX_E; + } +#ifndef NO_CERTS + if (ctx->cm == NULL) { + CYASSL_MSG("Bad Cert Manager New"); + return BAD_CERT_MANAGER_ERROR; + } +#endif + return 0; +} + + +/* In case contexts are held in array and don't want to free actual ctx */ +void SSL_CtxResourceFree(CYASSL_CTX* ctx) +{ + XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); + +#ifndef NO_CERTS + XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH); + XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH); + XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY); + XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT); + XFREE(ctx->certChain.buffer, ctx->heap, DYNAMIC_TYPE_CERT); + CyaSSL_CertManagerFree(ctx->cm); +#endif +#ifdef HAVE_TLS_EXTENSIONS + TLSX_FreeAll(ctx->extensions); +#endif +} + + +void FreeSSL_Ctx(CYASSL_CTX* ctx) +{ + int doFree = 0; + + if (LockMutex(&ctx->countMutex) != 0) { + CYASSL_MSG("Couldn't lock count mutex"); + return; + } + ctx->refCount--; + if (ctx->refCount == 0) + doFree = 1; + UnLockMutex(&ctx->countMutex); + + if (doFree) { + CYASSL_MSG("CTX ref count down to 0, doing full free"); + SSL_CtxResourceFree(ctx); + FreeMutex(&ctx->countMutex); + XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX); + } + else { + (void)ctx; + CYASSL_MSG("CTX ref count not 0 yet, no free"); + } +} + + +/* Set cipher pointers to null */ +void InitCiphers(CYASSL* ssl) +{ +#ifdef BUILD_ARC4 + ssl->encrypt.arc4 = NULL; + ssl->decrypt.arc4 = NULL; +#endif +#ifdef BUILD_DES3 + ssl->encrypt.des3 = NULL; + ssl->decrypt.des3 = NULL; +#endif +#ifdef BUILD_AES + ssl->encrypt.aes = NULL; + ssl->decrypt.aes = NULL; +#endif +#ifdef HAVE_CAMELLIA + ssl->encrypt.cam = NULL; + ssl->decrypt.cam = NULL; +#endif +#ifdef HAVE_HC128 + ssl->encrypt.hc128 = NULL; + ssl->decrypt.hc128 = NULL; +#endif +#ifdef BUILD_RABBIT + ssl->encrypt.rabbit = NULL; + ssl->decrypt.rabbit = NULL; +#endif + ssl->encrypt.setup = 0; + ssl->decrypt.setup = 0; +} + + +/* Free ciphers */ +void FreeCiphers(CYASSL* ssl) +{ + (void)ssl; +#ifdef BUILD_ARC4 + #ifdef HAVE_CAVIUM + if (ssl->devId != NO_CAVIUM_DEVICE) { + Arc4FreeCavium(ssl->encrypt.arc4); + Arc4FreeCavium(ssl->decrypt.arc4); + } + #endif + XFREE(ssl->encrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef BUILD_DES3 + #ifdef HAVE_CAVIUM + if (ssl->devId != NO_CAVIUM_DEVICE) { + Des3_FreeCavium(ssl->encrypt.des3); + Des3_FreeCavium(ssl->decrypt.des3); + } + #endif + XFREE(ssl->encrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef BUILD_AES + #ifdef HAVE_CAVIUM + if (ssl->devId != NO_CAVIUM_DEVICE) { + AesFreeCavium(ssl->encrypt.aes); + AesFreeCavium(ssl->decrypt.aes); + } + #endif + XFREE(ssl->encrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef HAVE_CAMELLIA + XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef HAVE_HC128 + XFREE(ssl->encrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef BUILD_RABBIT + XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +} + + +void InitCipherSpecs(CipherSpecs* cs) +{ + cs->bulk_cipher_algorithm = INVALID_BYTE; + cs->cipher_type = INVALID_BYTE; + cs->mac_algorithm = INVALID_BYTE; + cs->kea = INVALID_BYTE; + cs->sig_algo = INVALID_BYTE; + + cs->hash_size = 0; + cs->static_ecdh = 0; + cs->key_size = 0; + cs->iv_size = 0; + cs->block_size = 0; +} + + +void InitSuites(Suites* suites, ProtocolVersion pv, byte haveRSA, byte havePSK, + byte haveDH, byte haveNTRU, byte haveECDSAsig, + byte haveStaticECC, int side) +{ + word16 idx = 0; + int tls = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR; + int tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR; + int haveRSAsig = 1; + + (void)tls; /* shut up compiler */ + (void)tls1_2; + (void)haveDH; + (void)havePSK; + (void)haveNTRU; + (void)haveStaticECC; + + if (suites == NULL) { + CYASSL_MSG("InitSuites pointer error"); + return; + } + + if (suites->setSuites) + return; /* trust user settings, don't override */ + + if (side == CYASSL_SERVER_END && haveStaticECC) { + haveRSA = 0; /* can't do RSA with ECDSA key */ + (void)haveRSA; /* some builds won't read */ + } + + if (side == CYASSL_SERVER_END && haveECDSAsig) { + haveRSAsig = 0; /* can't have RSA sig if signed by ECDSA */ + (void)haveRSAsig; /* non ecc builds won't read */ + } + +#ifdef CYASSL_DTLS + if (pv.major == DTLS_MAJOR) { + tls = 1; + tls1_2 = pv.minor <= DTLSv1_2_MINOR; + } +#endif + +#ifdef HAVE_RENEGOTIATION_INDICATION + if (side == CYASSL_CLIENT_END) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveRSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveRSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + if (tls1_2 && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + if (tls && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + if (tls && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + if (tls && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + if (tls && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + if (tls && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + if (tls && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveECDSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveRSAsig && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CCM_8; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CCM_8; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + if (tls && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM_8; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + if (tls && havePSK) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM_8; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA256; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + if (haveRSA ) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + if (haveRSA ) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + if (haveRSA ) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_B2B256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_B2B256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_B2B256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_WITH_RSA_CAMELLIA_256_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256; + } +#endif + + suites->suiteSz = idx; + + { + idx = 0; + + if (haveECDSAsig) { + #ifdef CYASSL_SHA384 + suites->hashSigAlgo[idx++] = sha384_mac; + suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + #ifndef NO_SHA256 + suites->hashSigAlgo[idx++] = sha256_mac; + suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + #ifndef NO_SHA + suites->hashSigAlgo[idx++] = sha_mac; + suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + } + + if (haveRSAsig) { + #ifdef CYASSL_SHA384 + suites->hashSigAlgo[idx++] = sha384_mac; + suites->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + #ifndef NO_SHA256 + suites->hashSigAlgo[idx++] = sha256_mac; + suites->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + #ifndef NO_SHA + suites->hashSigAlgo[idx++] = sha_mac; + suites->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + } + + suites->hashSigAlgoSz = idx; + } +} + + +#ifndef NO_CERTS + + +void InitX509Name(CYASSL_X509_NAME* name, int dynamicFlag) +{ + (void)dynamicFlag; + + if (name != NULL) { + name->name = name->staticName; + name->dynamicName = 0; +#ifdef OPENSSL_EXTRA + XMEMSET(&name->fullName, 0, sizeof(DecodedName)); +#endif /* OPENSSL_EXTRA */ + } +} + + +void FreeX509Name(CYASSL_X509_NAME* name) +{ + if (name != NULL) { + if (name->dynamicName) + XFREE(name->name, NULL, DYNAMIC_TYPE_SUBJECT_CN); +#ifdef OPENSSL_EXTRA + if (name->fullName.fullName != NULL) + XFREE(name->fullName.fullName, NULL, DYNAMIC_TYPE_X509); +#endif /* OPENSSL_EXTRA */ + } +} + + +/* Initialize CyaSSL X509 type */ +void InitX509(CYASSL_X509* x509, int dynamicFlag) +{ + InitX509Name(&x509->issuer, 0); + InitX509Name(&x509->subject, 0); + x509->version = 0; + x509->pubKey.buffer = NULL; + x509->sig.buffer = NULL; + x509->derCert.buffer = NULL; + x509->altNames = NULL; + x509->altNamesNext = NULL; + x509->dynamicMemory = (byte)dynamicFlag; + x509->isCa = 0; +#ifdef HAVE_ECC + x509->pkCurveOID = 0; +#endif /* HAVE_ECC */ +#ifdef OPENSSL_EXTRA + x509->pathLength = 0; + x509->basicConstSet = 0; + x509->basicConstCrit = 0; + x509->basicConstPlSet = 0; + x509->subjAltNameSet = 0; + x509->subjAltNameCrit = 0; + x509->authKeyIdSet = 0; + x509->authKeyIdCrit = 0; + x509->authKeyId = NULL; + x509->authKeyIdSz = 0; + x509->subjKeyIdSet = 0; + x509->subjKeyIdCrit = 0; + x509->subjKeyId = NULL; + x509->subjKeyIdSz = 0; + x509->keyUsageSet = 0; + x509->keyUsageCrit = 0; + x509->keyUsage = 0; + #ifdef CYASSL_SEP + x509->certPolicySet = 0; + x509->certPolicyCrit = 0; + #endif /* CYASSL_SEP */ +#endif /* OPENSSL_EXTRA */ +} + + +/* Free CyaSSL X509 type */ +void FreeX509(CYASSL_X509* x509) +{ + if (x509 == NULL) + return; + + FreeX509Name(&x509->issuer); + FreeX509Name(&x509->subject); + if (x509->pubKey.buffer) + XFREE(x509->pubKey.buffer, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_SUBJECT_CN); + XFREE(x509->sig.buffer, NULL, DYNAMIC_TYPE_SIGNATURE); + #ifdef OPENSSL_EXTRA + XFREE(x509->authKeyId, NULL, 0); + XFREE(x509->subjKeyId, NULL, 0); + #endif /* OPENSSL_EXTRA */ + if (x509->altNames) + FreeAltNames(x509->altNames, NULL); + if (x509->dynamicMemory) + XFREE(x509, NULL, DYNAMIC_TYPE_X509); +} + +#endif /* NO_CERTS */ + + +/* init everything to 0, NULL, default values before calling anything that may + fail so that desctructor has a "good" state to cleanup */ +int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) +{ + int ret; + byte haveRSA = 0; + byte havePSK = 0; + + ssl->ctx = ctx; /* only for passing to calls, options could change */ + ssl->version = ctx->method->version; + ssl->suites = NULL; + +#ifdef HAVE_LIBZ + ssl->didStreamInit = 0; +#endif +#ifndef NO_RSA + haveRSA = 1; +#endif + +#ifndef NO_CERTS + ssl->buffers.certificate.buffer = 0; + ssl->buffers.key.buffer = 0; + ssl->buffers.certChain.buffer = 0; +#endif + ssl->buffers.inputBuffer.length = 0; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; + ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.inputBuffer.dynamicFlag = 0; + ssl->buffers.inputBuffer.offset = 0; + ssl->buffers.outputBuffer.length = 0; + ssl->buffers.outputBuffer.idx = 0; + ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; + ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.outputBuffer.dynamicFlag = 0; + ssl->buffers.outputBuffer.offset = 0; + ssl->buffers.domainName.buffer = 0; +#ifndef NO_CERTS + ssl->buffers.serverDH_P.buffer = 0; + ssl->buffers.serverDH_G.buffer = 0; + ssl->buffers.serverDH_Pub.buffer = 0; + ssl->buffers.serverDH_Priv.buffer = 0; +#endif + ssl->buffers.clearOutputBuffer.buffer = 0; + ssl->buffers.clearOutputBuffer.length = 0; + ssl->buffers.prevSent = 0; + ssl->buffers.plainSz = 0; +#ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ssl->buffers.peerEccDsaKey.buffer = 0; + ssl->buffers.peerEccDsaKey.length = 0; + #endif /* HAVE_ECC */ + #ifndef NO_RSA + ssl->buffers.peerRsaKey.buffer = 0; + ssl->buffers.peerRsaKey.length = 0; + #endif /* NO_RSA */ +#endif /* HAVE_PK_CALLBACKS */ + +#ifdef KEEP_PEER_CERT + InitX509(&ssl->peerCert, 0); +#endif + +#ifdef HAVE_ECC + ssl->eccTempKeySz = ctx->eccTempKeySz; + ssl->pkCurveOID = ctx->pkCurveOID; + ssl->peerEccKeyPresent = 0; + ssl->peerEccDsaKeyPresent = 0; + ssl->eccDsaKeyPresent = 0; + ssl->eccTempKeyPresent = 0; + ssl->peerEccKey = NULL; + ssl->peerEccDsaKey = NULL; + ssl->eccDsaKey = NULL; + ssl->eccTempKey = NULL; +#endif + + ssl->timeout = ctx->timeout; + ssl->rfd = -1; /* set to invalid descriptor */ + ssl->wfd = -1; + ssl->rflags = 0; /* no user flags yet */ + ssl->wflags = 0; /* no user flags yet */ + ssl->biord = 0; + ssl->biowr = 0; + + ssl->IOCB_ReadCtx = &ssl->rfd; /* prevent invalid pointer access if not */ + ssl->IOCB_WriteCtx = &ssl->wfd; /* correctly set */ +#ifdef HAVE_NETX + ssl->nxCtx.nxSocket = NULL; + ssl->nxCtx.nxPacket = NULL; + ssl->nxCtx.nxOffset = 0; + ssl->nxCtx.nxWait = 0; + ssl->IOCB_ReadCtx = &ssl->nxCtx; /* default NetX IO ctx, same for read */ + ssl->IOCB_WriteCtx = &ssl->nxCtx; /* and write */ +#endif +#ifdef CYASSL_DTLS + ssl->IOCB_CookieCtx = NULL; /* we don't use for default cb */ + ssl->dtls_expected_rx = MAX_MTU; + ssl->keys.dtls_state.window = 0; + ssl->keys.dtls_state.nextEpoch = 0; + ssl->keys.dtls_state.nextSeq = 0; +#endif + +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + InitMd5(&ssl->hashMd5); +#endif +#ifndef NO_SHA + ret = InitSha(&ssl->hashSha); + if (ret != 0) { + return ret; + } +#endif +#endif +#ifndef NO_SHA256 + ret = InitSha256(&ssl->hashSha256); + if (ret != 0) { + return ret; + } +#endif +#ifdef CYASSL_SHA384 + ret = InitSha384(&ssl->hashSha384); + if (ret != 0) { + return ret; + } +#endif +#ifndef NO_RSA + ssl->peerRsaKey = NULL; + ssl->peerRsaKeyPresent = 0; +#endif + ssl->verifyCallback = ctx->verifyCallback; + ssl->verifyCbCtx = NULL; + ssl->options.side = ctx->method->side; + ssl->options.downgrade = ctx->method->downgrade; + ssl->error = 0; + ssl->options.connReset = 0; + ssl->options.isClosed = 0; + ssl->options.closeNotify = 0; + ssl->options.sentNotify = 0; + ssl->options.usingCompression = 0; + if (ssl->options.side == CYASSL_SERVER_END) + ssl->options.haveDH = ctx->haveDH; + else + ssl->options.haveDH = 0; + ssl->options.haveNTRU = ctx->haveNTRU; + ssl->options.haveECDSAsig = ctx->haveECDSAsig; + ssl->options.haveStaticECC = ctx->haveStaticECC; + ssl->options.havePeerCert = 0; + ssl->options.havePeerVerify = 0; + ssl->options.usingPSK_cipher = 0; + ssl->options.sendAlertState = 0; +#ifndef NO_PSK + havePSK = ctx->havePSK; + ssl->options.havePSK = ctx->havePSK; + ssl->options.client_psk_cb = ctx->client_psk_cb; + ssl->options.server_psk_cb = ctx->server_psk_cb; +#endif /* NO_PSK */ + + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = doProcessInit; + +#ifdef CYASSL_DTLS + ssl->keys.dtls_sequence_number = 0; + ssl->keys.dtls_state.curSeq = 0; + ssl->keys.dtls_state.nextSeq = 0; + ssl->keys.dtls_handshake_number = 0; + ssl->keys.dtls_expected_peer_handshake_number = 0; + ssl->keys.dtls_epoch = 0; + ssl->keys.dtls_state.curEpoch = 0; + ssl->keys.dtls_state.nextEpoch = 0; + ssl->dtls_timeout_init = DTLS_TIMEOUT_INIT; + ssl->dtls_timeout_max = DTLS_TIMEOUT_MAX; + ssl->dtls_timeout = ssl->dtls_timeout_init; + ssl->dtls_pool = NULL; + ssl->dtls_msg_list = NULL; +#endif + ssl->keys.encryptSz = 0; + ssl->keys.padSz = 0; + ssl->keys.encryptionOn = 0; /* initially off */ + ssl->keys.decryptedCur = 0; /* initially off */ + ssl->options.sessionCacheOff = ctx->sessionCacheOff; + ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff; + + ssl->options.verifyPeer = ctx->verifyPeer; + ssl->options.verifyNone = ctx->verifyNone; + ssl->options.failNoCert = ctx->failNoCert; + ssl->options.sendVerify = ctx->sendVerify; + + ssl->options.resuming = 0; + ssl->options.haveSessionId = 0; + #ifndef NO_OLD_TLS + ssl->hmac = SSL_hmac; /* default to SSLv3 */ + #else + ssl->hmac = TLS_hmac; + #endif + ssl->heap = ctx->heap; /* defaults to self */ + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->options.dtls = ssl->version.major == DTLS_MAJOR; + ssl->options.partialWrite = ctx->partialWrite; + ssl->options.quietShutdown = ctx->quietShutdown; + ssl->options.certOnly = 0; + ssl->options.groupMessages = ctx->groupMessages; + ssl->options.usingNonblock = 0; + ssl->options.saveArrays = 0; + +#ifndef NO_CERTS + /* ctx still owns certificate, certChain, key, dh, and cm */ + ssl->buffers.certificate = ctx->certificate; + ssl->buffers.certChain = ctx->certChain; + ssl->buffers.key = ctx->privateKey; + if (ssl->options.side == CYASSL_SERVER_END) { + ssl->buffers.serverDH_P = ctx->serverDH_P; + ssl->buffers.serverDH_G = ctx->serverDH_G; + } +#endif + ssl->buffers.weOwnCert = 0; + ssl->buffers.weOwnKey = 0; + ssl->buffers.weOwnDH = 0; + +#ifdef CYASSL_DTLS + ssl->buffers.dtlsCtx.fd = -1; + ssl->buffers.dtlsCtx.peer.sa = NULL; + ssl->buffers.dtlsCtx.peer.sz = 0; +#endif + +#ifdef KEEP_PEER_CERT + ssl->peerCert.issuer.sz = 0; + ssl->peerCert.subject.sz = 0; +#endif + +#ifdef SESSION_CERTS + ssl->session.chain.count = 0; +#endif + +#ifndef NO_CLIENT_CACHE + ssl->session.idLen = 0; +#endif + + ssl->cipher.ssl = ssl; + +#ifdef FORTRESS + ssl->ex_data[0] = 0; + ssl->ex_data[1] = 0; + ssl->ex_data[2] = 0; +#endif + +#ifdef CYASSL_CALLBACKS + ssl->hsInfoOn = 0; + ssl->toInfoOn = 0; +#endif + +#ifdef HAVE_CAVIUM + ssl->devId = ctx->devId; +#endif + +#ifdef HAVE_TLS_EXTENSIONS + ssl->extensions = NULL; +#ifdef HAVE_MAX_FRAGMENT + ssl->max_fragment = MAX_RECORD_SIZE; +#endif +#ifdef HAVE_TRUNCATED_HMAC + ssl->truncated_hmac = 0; +#endif +#endif + + ssl->rng = NULL; + ssl->arrays = NULL; + + /* default alert state (none) */ + ssl->alert_history.last_rx.code = -1; + ssl->alert_history.last_rx.level = -1; + ssl->alert_history.last_tx.code = -1; + ssl->alert_history.last_tx.level = -1; + + InitCiphers(ssl); + InitCipherSpecs(&ssl->specs); +#ifdef ATOMIC_USER + ssl->MacEncryptCtx = NULL; + ssl->DecryptVerifyCtx = NULL; +#endif +#ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ssl->EccSignCtx = NULL; + ssl->EccVerifyCtx = NULL; + #endif /* HAVE_ECC */ + #ifndef NO_RSA + ssl->RsaSignCtx = NULL; + ssl->RsaVerifyCtx = NULL; + ssl->RsaEncCtx = NULL; + ssl->RsaDecCtx = NULL; + #endif /* NO_RSA */ +#endif /* HAVE_PK_CALLBACKS */ + + /* all done with init, now can return errors, call other stuff */ + + /* increment CTX reference count */ + if (LockMutex(&ctx->countMutex) != 0) { + CYASSL_MSG("Couldn't lock CTX count mutex"); + return BAD_MUTEX_E; + } + ctx->refCount++; + UnLockMutex(&ctx->countMutex); + + /* arrays */ + ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays == NULL) { + CYASSL_MSG("Arrays Memory error"); + return MEMORY_E; + } + XMEMSET(ssl->arrays, 0, sizeof(Arrays)); + +#ifndef NO_PSK + ssl->arrays->client_identity[0] = 0; + if (ctx->server_hint[0]) { /* set in CTX */ + XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint, MAX_PSK_ID_LEN); + ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0'; + } + else + ssl->arrays->server_hint[0] = 0; +#endif /* NO_PSK */ + +#ifdef CYASSL_DTLS + ssl->arrays->cookieSz = 0; +#endif + + /* RNG */ + ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG); + if (ssl->rng == NULL) { + CYASSL_MSG("RNG Memory error"); + return MEMORY_E; + } + + if ( (ret = InitRng(ssl->rng)) != 0) { + CYASSL_MSG("RNG Init error"); + return ret; + } + + /* suites */ + ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, + DYNAMIC_TYPE_SUITES); + if (ssl->suites == NULL) { + CYASSL_MSG("Suites Memory error"); + return MEMORY_E; + } + *ssl->suites = ctx->suites; + + /* peer key */ +#ifndef NO_RSA + ssl->peerRsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey), ssl->heap, + DYNAMIC_TYPE_RSA); + if (ssl->peerRsaKey == NULL) { + CYASSL_MSG("PeerRsaKey Memory error"); + return MEMORY_E; + } + ret = InitRsaKey(ssl->peerRsaKey, ctx->heap); + if (ret != 0) return ret; +#endif +#ifndef NO_CERTS + /* make sure server has cert and key unless using PSK */ + if (ssl->options.side == CYASSL_SERVER_END && !havePSK) + if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) { + CYASSL_MSG("Server missing certificate and/or private key"); + return NO_PRIVATE_KEY; + } +#endif +#ifdef HAVE_ECC + ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->peerEccKey == NULL) { + CYASSL_MSG("PeerEccKey Memory error"); + return MEMORY_E; + } + ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->peerEccDsaKey == NULL) { + CYASSL_MSG("PeerEccDsaKey Memory error"); + return MEMORY_E; + } + ssl->eccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->eccDsaKey == NULL) { + CYASSL_MSG("EccDsaKey Memory error"); + return MEMORY_E; + } + ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->eccTempKey == NULL) { + CYASSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + ecc_init(ssl->peerEccKey); + ecc_init(ssl->peerEccDsaKey); + ecc_init(ssl->eccDsaKey); + ecc_init(ssl->eccTempKey); +#endif + + /* make sure server has DH parms, and add PSK if there, add NTRU too */ + if (ssl->options.side == CYASSL_SERVER_END) + InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveStaticECC, + ssl->options.side); + else + InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, TRUE, + ssl->options.haveNTRU, ssl->options.haveECDSAsig, + ssl->options.haveStaticECC, ssl->options.side); + + return 0; +} + + +/* free use of temporary arrays */ +void FreeArrays(CYASSL* ssl, int keep) +{ + if (ssl->arrays && keep) { + /* keeps session id for user retrieval */ + XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN); + } + XFREE(ssl->arrays, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays = NULL; +} + + +/* In case holding SSL object in array and don't want to free actual ssl */ +void SSL_ResourceFree(CYASSL* ssl) +{ + FreeCiphers(ssl); + FreeArrays(ssl, 0); + XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); + XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); + XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); + +#ifndef NO_CERTS + XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH); + /* parameters (p,g) may be owned by ctx */ + if (ssl->buffers.weOwnDH || ssl->options.side == CYASSL_CLIENT_END) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH); + } + + /* CYASSL_CTX always owns certChain */ + if (ssl->buffers.weOwnCert) + XFREE(ssl->buffers.certificate.buffer, ssl->heap, DYNAMIC_TYPE_CERT); + if (ssl->buffers.weOwnKey) + XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY); +#endif +#ifndef NO_RSA + if (ssl->peerRsaKey) { + FreeRsaKey(ssl->peerRsaKey); + XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA); + } +#endif + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, FORCED_FREE); + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); +#ifdef CYASSL_DTLS + if (ssl->dtls_pool != NULL) { + DtlsPoolReset(ssl); + XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE); + } + if (ssl->dtls_msg_list != NULL) { + DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap); + ssl->dtls_msg_list = NULL; + } + XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.peer.sa = NULL; +#endif +#if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS) + FreeX509(&ssl->peerCert); +#endif +#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) + CyaSSL_BIO_free(ssl->biord); + if (ssl->biord != ssl->biowr) /* in case same as write */ + CyaSSL_BIO_free(ssl->biowr); +#endif +#ifdef HAVE_LIBZ + FreeStreams(ssl); +#endif +#ifdef HAVE_ECC + if (ssl->peerEccKey) { + if (ssl->peerEccKeyPresent) + ecc_free(ssl->peerEccKey); + XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC); + } + if (ssl->peerEccDsaKey) { + if (ssl->peerEccDsaKeyPresent) + ecc_free(ssl->peerEccDsaKey); + XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); + } + if (ssl->eccTempKey) { + if (ssl->eccTempKeyPresent) + ecc_free(ssl->eccTempKey); + XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC); + } + if (ssl->eccDsaKey) { + if (ssl->eccDsaKeyPresent) + ecc_free(ssl->eccDsaKey); + XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); + } +#endif +#ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); + #endif /* HAVE_ECC */ + #ifndef NO_RSA + XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA); + #endif /* NO_RSA */ +#endif /* HAVE_PK_CALLBACKS */ +#ifdef HAVE_TLS_EXTENSIONS + TLSX_FreeAll(ssl->extensions); +#endif +#ifdef HAVE_NETX + if (ssl->nxCtx.nxPacket) + nx_packet_release(ssl->nxCtx.nxPacket); +#endif +} + + +/* Free any handshake resources no longer needed */ +void FreeHandshakeResources(CYASSL* ssl) +{ + /* input buffer */ + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + + /* suites */ + XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); + ssl->suites = NULL; + + /* RNG */ + if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) { + XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); + ssl->rng = NULL; + } + +#ifdef CYASSL_DTLS + /* DTLS_POOL */ + if (ssl->options.dtls && ssl->dtls_pool != NULL) { + DtlsPoolReset(ssl); + XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); + ssl->dtls_pool = NULL; + } +#endif + + /* arrays */ + if (ssl->options.saveArrays) + FreeArrays(ssl, 1); + +#ifndef NO_RSA + /* peerRsaKey */ + if (ssl->peerRsaKey) { + FreeRsaKey(ssl->peerRsaKey); + XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA); + ssl->peerRsaKey = NULL; + } +#endif + +#ifdef HAVE_ECC + if (ssl->peerEccKey) + { + if (ssl->peerEccKeyPresent) { + ecc_free(ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + } + XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->peerEccKey = NULL; + } + if (ssl->peerEccDsaKey) + { + if (ssl->peerEccDsaKeyPresent) { + ecc_free(ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->peerEccDsaKey = NULL; + } + if (ssl->eccTempKey) + { + if (ssl->eccTempKeyPresent) { + ecc_free(ssl->eccTempKey); + ssl->eccTempKeyPresent = 0; + } + XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->eccTempKey = NULL; + } + if (ssl->eccDsaKey) + { + if (ssl->eccDsaKeyPresent) { + ecc_free(ssl->eccDsaKey); + ssl->eccDsaKeyPresent = 0; + } + XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->eccDsaKey = NULL; + } +#endif +#ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC); + ssl->buffers.peerEccDsaKey.buffer = NULL; + #endif /* HAVE_ECC */ + #ifndef NO_RSA + XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA); + ssl->buffers.peerRsaKey.buffer = NULL; + #endif /* NO_RSA */ +#endif /* HAVE_PK_CALLBACKS */ +} + + +void FreeSSL(CYASSL* ssl) +{ + FreeSSL_Ctx(ssl->ctx); /* will decrement and free underyling CTX if 0 */ + SSL_ResourceFree(ssl); + XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL); +} + + +#ifdef CYASSL_DTLS + +int DtlsPoolInit(CYASSL* ssl) +{ + if (ssl->dtls_pool == NULL) { + DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool), + ssl->heap, DYNAMIC_TYPE_DTLS_POOL); + if (pool == NULL) { + CYASSL_MSG("DTLS Buffer Pool Memory error"); + return MEMORY_E; + } + else { + int i; + + for (i = 0; i < DTLS_POOL_SZ; i++) { + pool->buf[i].length = 0; + pool->buf[i].buffer = NULL; + } + pool->used = 0; + ssl->dtls_pool = pool; + } + } + return 0; +} + + +int DtlsPoolSave(CYASSL* ssl, const byte *src, int sz) +{ + DtlsPool *pool = ssl->dtls_pool; + if (pool != NULL && pool->used < DTLS_POOL_SZ) { + buffer *pBuf = &pool->buf[pool->used]; + pBuf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + if (pBuf->buffer == NULL) { + CYASSL_MSG("DTLS Buffer Memory error"); + return MEMORY_ERROR; + } + XMEMCPY(pBuf->buffer, src, sz); + pBuf->length = (word32)sz; + pool->used++; + } + return 0; +} + + +void DtlsPoolReset(CYASSL* ssl) +{ + DtlsPool *pool = ssl->dtls_pool; + if (pool != NULL) { + buffer *pBuf; + int i, used; + + used = pool->used; + for (i = 0, pBuf = &pool->buf[0]; i < used; i++, pBuf++) { + XFREE(pBuf->buffer, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + pBuf->buffer = NULL; + pBuf->length = 0; + } + pool->used = 0; + } + ssl->dtls_timeout = ssl->dtls_timeout_init; +} + + +int DtlsPoolTimeout(CYASSL* ssl) +{ + int result = -1; + if (ssl->dtls_timeout < ssl->dtls_timeout_max) { + ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; + result = 0; + } + return result; +} + + +int DtlsPoolSend(CYASSL* ssl) +{ + int ret; + DtlsPool *pool = ssl->dtls_pool; + + if (pool != NULL && pool->used > 0) { + int i; + for (i = 0; i < pool->used; i++) { + int sendResult; + buffer* buf = &pool->buf[i]; + + DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer; + + word16 message_epoch; + ato16(dtls->epoch, &message_epoch); + if (message_epoch == ssl->keys.dtls_epoch) { + /* Increment record sequence number on retransmitted handshake + * messages */ + c32to48(ssl->keys.dtls_sequence_number, dtls->sequence_number); + ssl->keys.dtls_sequence_number++; + } + else { + /* The Finished message is sent with the next epoch, keep its + * sequence number */ + } + + if ((ret = CheckAvailableSize(ssl, buf->length)) != 0) + return ret; + + XMEMCPY(ssl->buffers.outputBuffer.buffer, buf->buffer, buf->length); + ssl->buffers.outputBuffer.idx = 0; + ssl->buffers.outputBuffer.length = buf->length; + + sendResult = SendBuffered(ssl); + if (sendResult < 0) { + return sendResult; + } + } + } + return 0; +} + + +/* functions for managing DTLS datagram reordering */ + +/* Need to allocate space for the handshake message header. The hashing + * routines assume the message pointer is still within the buffer that + * has the headers, and will include those headers in the hash. The store + * routines need to take that into account as well. New will allocate + * extra space for the headers. */ +DtlsMsg* DtlsMsgNew(word32 sz, void* heap) +{ + DtlsMsg* msg = NULL; + + msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); + + if (msg != NULL) { + msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ, + heap, DYNAMIC_TYPE_NONE); + if (msg->buf != NULL) { + msg->next = NULL; + msg->seq = 0; + msg->sz = sz; + msg->fragSz = 0; + msg->msg = msg->buf + DTLS_HANDSHAKE_HEADER_SZ; + } + else { + XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); + msg = NULL; + } + } + + return msg; +} + +void DtlsMsgDelete(DtlsMsg* item, void* heap) +{ + (void)heap; + + if (item != NULL) { + if (item->buf != NULL) + XFREE(item->buf, heap, DYNAMIC_TYPE_NONE); + XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG); + } +} + + +void DtlsMsgListDelete(DtlsMsg* head, void* heap) +{ + DtlsMsg* next; + while (head) { + next = head->next; + DtlsMsgDelete(head, heap); + head = next; + } +} + + +void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type, + word32 fragOffset, word32 fragSz) +{ + if (msg != NULL && data != NULL && msg->fragSz <= msg->sz) { + msg->seq = seq; + msg->type = type; + msg->fragSz += fragSz; + /* If fragOffset is zero, this is either a full message that is out + * of order, or the first fragment of a fragmented message. Copy the + * handshake message header as well as the message data. */ + if (fragOffset == 0) + XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ, + fragSz + DTLS_HANDSHAKE_HEADER_SZ); + else { + /* If fragOffet is non-zero, this is an additional fragment that + * needs to be copied to its location in the message buffer. Also + * copy the total size of the message over the fragment size. The + * hash routines look at a defragmented message if it had actually + * come across as a single handshake message. */ + XMEMCPY(msg->msg + fragOffset, data, fragSz); + c32to24(msg->sz, msg->msg - DTLS_HANDSHAKE_FRAG_SZ); + } + } +} + + +DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq) +{ + while (head != NULL && head->seq != seq) { + head = head->next; + } + return head; +} + + +DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, + word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap) +{ + + /* See if seq exists in the list. If it isn't in the list, make + * a new item of size dataSz, copy fragSz bytes from data to msg->msg + * starting at offset fragOffset, and add fragSz to msg->fragSz. If + * the seq is in the list and it isn't full, copy fragSz bytes from + * data to msg->msg starting at offset fragOffset, and add fragSz to + * msg->fragSz. The new item should be inserted into the list in its + * proper position. + * + * 1. Find seq in list, or where seq should go in list. If seq not in + * list, create new item and insert into list. Either case, keep + * pointer to item. + * 2. If msg->fragSz + fragSz < sz, copy data to msg->msg at offset + * fragOffset. Add fragSz to msg->fragSz. + */ + + if (head != NULL) { + DtlsMsg* cur = DtlsMsgFind(head, seq); + if (cur == NULL) { + cur = DtlsMsgNew(dataSz, heap); + if (cur != NULL) { + DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz); + head = DtlsMsgInsert(head, cur); + } + } + else { + DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz); + } + } + else { + head = DtlsMsgNew(dataSz, heap); + DtlsMsgSet(head, seq, data, type, fragOffset, fragSz); + } + + return head; +} + + +/* DtlsMsgInsert() is an in-order insert. */ +DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item) +{ + if (head == NULL || item->seq < head->seq) { + item->next = head; + head = item; + } + else if (head->next == NULL) { + head->next = item; + } + else { + DtlsMsg* cur = head->next; + DtlsMsg* prev = head; + while (cur) { + if (item->seq < cur->seq) { + item->next = cur; + prev->next = item; + break; + } + prev = cur; + cur = cur->next; + } + if (cur == NULL) { + prev->next = item; + } + } + + return head; +} + +#endif /* CYASSL_DTLS */ + +#ifndef NO_OLD_TLS + +ProtocolVersion MakeSSLv3(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = SSLv3_MINOR; + + return pv; +} + +#endif /* NO_OLD_TLS */ + + +#ifdef CYASSL_DTLS + +ProtocolVersion MakeDTLSv1(void) +{ + ProtocolVersion pv; + pv.major = DTLS_MAJOR; + pv.minor = DTLS_MINOR; + + return pv; +} + +ProtocolVersion MakeDTLSv1_2(void) +{ + ProtocolVersion pv; + pv.major = DTLS_MAJOR; + pv.minor = DTLSv1_2_MINOR; + + return pv; +} + +#endif /* CYASSL_DTLS */ + + + + +#ifdef USE_WINDOWS_API + + word32 LowResTimer(void) + { + static int init = 0; + static LARGE_INTEGER freq; + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (word32)(count.QuadPart / freq.QuadPart); + } + +#elif defined(HAVE_RTP_SYS) + + #include "rtptime.h" + + word32 LowResTimer(void) + { + return (word32)rtp_get_system_sec(); + } + + +#elif defined(MICRIUM) + + word32 LowResTimer(void) + { + NET_SECURE_OS_TICK clk; + + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + clk = NetSecure_OS_TimeGet(); + #endif + return (word32)clk; + } + + +#elif defined(MICROCHIP_TCPIP_V5) + + word32 LowResTimer(void) + { + return (word32) TickGet(); + } + + +#elif defined(MICROCHIP_TCPIP) + + #if defined(MICROCHIP_MPLAB_HARMONY) + + #include <system/tmr/sys_tmr.h> + + word32 LowResTimer(void) + { + return (word32) SYS_TMR_TickCountGet(); + } + + #else + + word32 LowResTimer(void) + { + return (word32) SYS_TICK_Get(); + } + + #endif + +#elif defined(FREESCALE_MQX) + + word32 LowResTimer(void) + { + TIME_STRUCT mqxTime; + + _time_get_elapsed(&mqxTime); + + return (word32) mqxTime.SECONDS; + } + + +#elif defined(USER_TICKS) +#if 0 + word32 LowResTimer(void) + { + /* + write your own clock tick function if don't want time(0) + needs second accuracy but doesn't have to correlated to EPOCH + */ + } +#endif +#else /* !USE_WINDOWS_API && !HAVE_RTP_SYS && !MICRIUM && !USER_TICKS */ + + #include <time.h> + + word32 LowResTimer(void) + { + return (word32)time(0); + } + + +#endif /* USE_WINDOWS_API */ + + +/* add output to md5 and sha handshake hashes, exclude record header */ +static int HashOutput(CYASSL* ssl, const byte* output, int sz, int ivSz) +{ + const byte* adj = output + RECORD_HEADER_SZ + ivSz; + sz -= RECORD_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + adj += DTLS_RECORD_EXTRA; + sz -= DTLS_RECORD_EXTRA; + } +#endif +#ifndef NO_OLD_TLS +#ifndef NO_SHA + ShaUpdate(&ssl->hashSha, adj, sz); +#endif +#ifndef NO_MD5 + Md5Update(&ssl->hashMd5, adj, sz); +#endif +#endif + + if (IsAtLeastTLSv1_2(ssl)) { + int ret; + +#ifndef NO_SHA256 + ret = Sha256Update(&ssl->hashSha256, adj, sz); + if (ret != 0) + return ret; +#endif +#ifdef CYASSL_SHA384 + ret = Sha384Update(&ssl->hashSha384, adj, sz); + if (ret != 0) + return ret; +#endif + } + + return 0; +} + + +/* add input to md5 and sha handshake hashes, include handshake header */ +static int HashInput(CYASSL* ssl, const byte* input, int sz) +{ + const byte* adj = input - HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + adj -= DTLS_HANDSHAKE_EXTRA; + sz += DTLS_HANDSHAKE_EXTRA; + } +#endif + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + ShaUpdate(&ssl->hashSha, adj, sz); +#endif +#ifndef NO_MD5 + Md5Update(&ssl->hashMd5, adj, sz); +#endif +#endif + + if (IsAtLeastTLSv1_2(ssl)) { + int ret; + +#ifndef NO_SHA256 + ret = Sha256Update(&ssl->hashSha256, adj, sz); + if (ret != 0) + return ret; +#endif +#ifdef CYASSL_SHA384 + ret = Sha384Update(&ssl->hashSha384, adj, sz); + if (ret != 0) + return ret; +#endif + } + + return 0; +} + + +/* add record layer header for message */ +static void AddRecordHeader(byte* output, word32 length, byte type, CYASSL* ssl) +{ + RecordLayerHeader* rl; + + /* record layer header */ + rl = (RecordLayerHeader*)output; + rl->type = type; + rl->pvMajor = ssl->version.major; /* type and version same in each */ + rl->pvMinor = ssl->version.minor; + + if (!ssl->options.dtls) + c16toa((word16)length, rl->length); + else { +#ifdef CYASSL_DTLS + DtlsRecordLayerHeader* dtls; + + /* dtls record layer header extensions */ + dtls = (DtlsRecordLayerHeader*)output; + c16toa(ssl->keys.dtls_epoch, dtls->epoch); + c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number); + c16toa((word16)length, dtls->length); +#endif + } +} + + +/* add handshake header for message */ +static void AddHandShakeHeader(byte* output, word32 length, byte type, + CYASSL* ssl) +{ + HandShakeHeader* hs; + (void)ssl; + + /* handshake header */ + hs = (HandShakeHeader*)output; + hs->type = type; + c32to24(length, hs->length); /* type and length same for each */ +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsHandShakeHeader* dtls; + + /* dtls handshake header extensions */ + dtls = (DtlsHandShakeHeader*)output; + c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq); + c32to24(0, dtls->fragment_offset); + c32to24(length, dtls->fragment_length); + } +#endif +} + + +/* add both headers for handshake message */ +static void AddHeaders(byte* output, word32 length, byte type, CYASSL* ssl) +{ + if (!ssl->options.dtls) { + AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl); + AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl); + } +#ifdef CYASSL_DTLS + else { + AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl); + AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl); + } +#endif +} + + +/* return bytes received, -1 on error */ +static int Receive(CYASSL* ssl, byte* buf, word32 sz) +{ + int recvd; + + if (ssl->ctx->CBIORecv == NULL) { + CYASSL_MSG("Your IO Recv callback is null, please set"); + return -1; + } + +retry: + recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx); + if (recvd < 0) + switch (recvd) { + case CYASSL_CBIO_ERR_GENERAL: /* general/unknown error */ + return -1; + + case CYASSL_CBIO_ERR_WANT_READ: /* want read, would block */ + return WANT_READ; + + case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ + #ifdef USE_WINDOWS_API + if (ssl->options.dtls) { + goto retry; + } + #endif + ssl->options.connReset = 1; + return -1; + + case CYASSL_CBIO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef CYASSL_CALLBACKS + if (ssl->toInfoOn) { + struct itimerval timeout; + getitimer(ITIMER_REAL, &timeout); + if (timeout.it_value.tv_sec == 0 && + timeout.it_value.tv_usec == 0) { + XSTRNCPY(ssl->timeoutInfo.timeoutName, + "recv() timeout", MAX_TIMEOUT_NAME_SZ); + CYASSL_MSG("Got our timeout"); + return WANT_READ; + } + } + #endif + goto retry; + + case CYASSL_CBIO_ERR_CONN_CLOSE: /* peer closed connection */ + ssl->options.isClosed = 1; + return -1; + + case CYASSL_CBIO_ERR_TIMEOUT: +#ifdef CYASSL_DTLS + if (DtlsPoolTimeout(ssl) == 0 && DtlsPoolSend(ssl) == 0) + goto retry; + else +#endif + return -1; + + default: + return recvd; + } + + return recvd; +} + + +/* Switch dynamic output buffer back to static, buffer is assumed clear */ +void ShrinkOutputBuffer(CYASSL* ssl) +{ + CYASSL_MSG("Shrinking output buffer\n"); + XFREE(ssl->buffers.outputBuffer.buffer - ssl->buffers.outputBuffer.offset, + ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; + ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.outputBuffer.dynamicFlag = 0; + ssl->buffers.outputBuffer.offset = 0; +} + + +/* Switch dynamic input buffer back to static, keep any remaining input */ +/* forced free means cleaning up */ +void ShrinkInputBuffer(CYASSL* ssl, int forcedFree) +{ + int usedLength = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (!forcedFree && usedLength > STATIC_BUFFER_LEN) + return; + + CYASSL_MSG("Shrinking input buffer\n"); + + if (!forcedFree && usedLength) + XMEMCPY(ssl->buffers.inputBuffer.staticBuffer, + ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + usedLength); + + XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, + ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; + ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.inputBuffer.dynamicFlag = 0; + ssl->buffers.inputBuffer.offset = 0; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; +} + + +int SendBuffered(CYASSL* ssl) +{ + if (ssl->ctx->CBIOSend == NULL) { + CYASSL_MSG("Your IO Send callback is null, please set"); + return SOCKET_ERROR_E; + } + + while (ssl->buffers.outputBuffer.length > 0) { + int sent = ssl->ctx->CBIOSend(ssl, + (char*)ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx, + (int)ssl->buffers.outputBuffer.length, + ssl->IOCB_WriteCtx); + if (sent < 0) { + switch (sent) { + + case CYASSL_CBIO_ERR_WANT_WRITE: /* would block */ + return WANT_WRITE; + + case CYASSL_CBIO_ERR_CONN_RST: /* connection reset */ + ssl->options.connReset = 1; + break; + + case CYASSL_CBIO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef CYASSL_CALLBACKS + if (ssl->toInfoOn) { + struct itimerval timeout; + getitimer(ITIMER_REAL, &timeout); + if (timeout.it_value.tv_sec == 0 && + timeout.it_value.tv_usec == 0) { + XSTRNCPY(ssl->timeoutInfo.timeoutName, + "send() timeout", MAX_TIMEOUT_NAME_SZ); + CYASSL_MSG("Got our timeout"); + return WANT_WRITE; + } + } + #endif + continue; + + case CYASSL_CBIO_ERR_CONN_CLOSE: /* epipe / conn closed */ + ssl->options.connReset = 1; /* treat same as reset */ + break; + + default: + return SOCKET_ERROR_E; + } + + return SOCKET_ERROR_E; + } + + ssl->buffers.outputBuffer.idx += sent; + ssl->buffers.outputBuffer.length -= sent; + } + + ssl->buffers.outputBuffer.idx = 0; + + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); + + return 0; +} + + +/* Grow the output buffer */ +static INLINE int GrowOutputBuffer(CYASSL* ssl, int size) +{ + byte* tmp; + byte hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ : + RECORD_HEADER_SZ; + byte align = CYASSL_GENERAL_ALIGNMENT; + /* the encrypted data will be offset from the front of the buffer by + the header, if the user wants encrypted alignment they need + to define their alignment requirement */ + + if (align) { + while (align < hdrSz) + align *= 2; + } + + tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length + align, + ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + CYASSL_MSG("growing output buffer\n"); + + if (!tmp) return MEMORY_E; + if (align) + tmp += align - hdrSz; + + if (ssl->buffers.outputBuffer.length) + XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer, + ssl->buffers.outputBuffer.length); + + if (ssl->buffers.outputBuffer.dynamicFlag) + XFREE(ssl->buffers.outputBuffer.buffer - + ssl->buffers.outputBuffer.offset, ssl->heap, + DYNAMIC_TYPE_OUT_BUFFER); + ssl->buffers.outputBuffer.dynamicFlag = 1; + if (align) + ssl->buffers.outputBuffer.offset = align - hdrSz; + else + ssl->buffers.outputBuffer.offset = 0; + ssl->buffers.outputBuffer.buffer = tmp; + ssl->buffers.outputBuffer.bufferSize = size + + ssl->buffers.outputBuffer.length; + return 0; +} + + +/* Grow the input buffer, should only be to read cert or big app data */ +int GrowInputBuffer(CYASSL* ssl, int size, int usedLength) +{ + byte* tmp; + byte hdrSz = DTLS_RECORD_HEADER_SZ; + byte align = ssl->options.dtls ? CYASSL_GENERAL_ALIGNMENT : 0; + /* the encrypted data will be offset from the front of the buffer by + the dtls record header, if the user wants encrypted alignment they need + to define their alignment requirement. in tls we read record header + to get size of record and put actual data back at front, so don't need */ + + if (align) { + while (align < hdrSz) + align *= 2; + } + tmp = (byte*) XMALLOC(size + usedLength + align, ssl->heap, + DYNAMIC_TYPE_IN_BUFFER); + CYASSL_MSG("growing input buffer\n"); + + if (!tmp) return MEMORY_E; + if (align) + tmp += align - hdrSz; + + if (usedLength) + XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, usedLength); + + if (ssl->buffers.inputBuffer.dynamicFlag) + XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, + ssl->heap,DYNAMIC_TYPE_IN_BUFFER); + + ssl->buffers.inputBuffer.dynamicFlag = 1; + if (align) + ssl->buffers.inputBuffer.offset = align - hdrSz; + else + ssl->buffers.inputBuffer.offset = 0; + ssl->buffers.inputBuffer.buffer = tmp; + ssl->buffers.inputBuffer.bufferSize = size + usedLength; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + + return 0; +} + + +/* check available size into output buffer, make room if needed */ +int CheckAvailableSize(CYASSL *ssl, int size) +{ + if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length + < (word32)size) { + if (GrowOutputBuffer(ssl, size) < 0) + return MEMORY_E; + } + + return 0; +} + + +/* do all verify and sanity checks on record header */ +static int GetRecordHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, + RecordLayerHeader* rh, word16 *size) +{ + if (!ssl->options.dtls) { + XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ); + *inOutIdx += RECORD_HEADER_SZ; + ato16(rh->length, size); + } + else { +#ifdef CYASSL_DTLS + /* type and version in same sport */ + XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ); + *inOutIdx += ENUM_LEN + VERSION_SZ; + ato16(input + *inOutIdx, &ssl->keys.dtls_state.curEpoch); + *inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */ + ato32(input + *inOutIdx, &ssl->keys.dtls_state.curSeq); + *inOutIdx += 4; /* advance past rest of seq */ + ato16(input + *inOutIdx, size); + *inOutIdx += LENGTH_SZ; +#endif + } + + /* catch version mismatch */ + if ((rh->pvMajor != ssl->version.major) || (rh->pvMinor != ssl->version.minor)){ + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.acceptState == ACCEPT_BEGIN) + CYASSL_MSG("Client attempting to connect with different version"); + else if (ssl->options.side == CYASSL_CLIENT_END && + ssl->options.downgrade && + ssl->options.connectState < FIRST_REPLY_DONE) + CYASSL_MSG("Server attempting to accept with different version"); + else { + CYASSL_MSG("SSL version error"); + return VERSION_ERROR; /* only use requested version */ + } + } + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if (DtlsCheckWindow(&ssl->keys.dtls_state) != 1) + return SEQUENCE_ERROR; + } +#endif + + /* record layer length check */ +#ifdef HAVE_MAX_FRAGMENT + if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) + return LENGTH_ERROR; +#else + if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) + return LENGTH_ERROR; +#endif + + /* verify record type here as well */ + switch (rh->type) { + case handshake: + case change_cipher_spec: + case application_data: + case alert: + break; + case no_type: + default: + CYASSL_MSG("Unknown Record Type"); + return UNKNOWN_RECORD_TYPE; + } + + /* haven't decrypted this record yet */ + ssl->keys.decryptedCur = 0; + + return 0; +} + + +static int GetHandShakeHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, + byte *type, word32 *size) +{ + const byte *ptr = input + *inOutIdx; + (void)ssl; + *inOutIdx += HANDSHAKE_HEADER_SZ; + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} + + +#ifdef CYASSL_DTLS +static int GetDtlsHandShakeHeader(CYASSL* ssl, const byte* input, + word32* inOutIdx, byte *type, word32 *size, + word32 *fragOffset, word32 *fragSz) +{ + word32 idx = *inOutIdx; + + *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; + + *type = input[idx++]; + c24to32(input + idx, size); + idx += BYTE3_LEN; + + ato16(input + idx, &ssl->keys.dtls_peer_handshake_number); + idx += DTLS_HANDSHAKE_SEQ_SZ; + + c24to32(input + idx, fragOffset); + idx += DTLS_HANDSHAKE_FRAG_SZ; + c24to32(input + idx, fragSz); + + return 0; +} +#endif + + +#ifndef NO_OLD_TLS +/* fill with MD5 pad size since biggest required */ +static const byte PAD1[PAD_MD5] = + { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; +static const byte PAD2[PAD_MD5] = + { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + +/* calculate MD5 hash for finished */ +static void BuildMD5(CYASSL* ssl, Hashes* hashes, const byte* sender) +{ + byte md5_result[MD5_DIGEST_SIZE]; + + /* make md5 inner */ + Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER); + Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD1, PAD_MD5); + Md5Final(&ssl->hashMd5, md5_result); + + /* make md5 outer */ + Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD2, PAD_MD5); + Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE); + + Md5Final(&ssl->hashMd5, hashes->md5); +} + + +/* calculate SHA hash for finished */ +static void BuildSHA(CYASSL* ssl, Hashes* hashes, const byte* sender) +{ + byte sha_result[SHA_DIGEST_SIZE]; + + /* make sha inner */ + ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER); + ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA); + ShaFinal(&ssl->hashSha, sha_result); + + /* make sha outer */ + ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA); + ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE); + + ShaFinal(&ssl->hashSha, hashes->sha); +} +#endif + + +static int BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) +{ + /* store current states, building requires get_digest which resets state */ +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + Md5 md5 = ssl->hashMd5; +#endif +#ifndef NO_SHA + Sha sha = ssl->hashSha; +#endif +#endif +#ifndef NO_SHA256 + Sha256 sha256 = ssl->hashSha256; +#endif +#ifdef CYASSL_SHA384 + Sha384 sha384 = ssl->hashSha384; +#endif + + int ret = 0; + +#ifndef NO_TLS + if (ssl->options.tls) { + ret = BuildTlsFinished(ssl, hashes, sender); + } +#endif +#ifndef NO_OLD_TLS + if (!ssl->options.tls) { + BuildMD5(ssl, hashes, sender); + BuildSHA(ssl, hashes, sender); + } +#endif + + /* restore */ +#ifndef NO_OLD_TLS + #ifndef NO_MD5 + ssl->hashMd5 = md5; + #endif + #ifndef NO_SHA + ssl->hashSha = sha; + #endif +#endif + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ssl->hashSha256 = sha256; + #endif + #ifdef CYASSL_SHA384 + ssl->hashSha384 = sha384; + #endif + } + + return ret; +} + + +#ifndef NO_CERTS + + +/* Match names with wildcards, each wildcard can represent a single name + component or fragment but not mulitple names, i.e., + *.z.com matches y.z.com but not x.y.z.com + + return 1 on success */ +static int MatchDomainName(const char* pattern, int len, const char* str) +{ + char p, s; + + if (pattern == NULL || str == NULL || len <= 0) + return 0; + + while (len > 0) { + + p = (char)XTOLOWER(*pattern++); + if (p == 0) + break; + + if (p == '*') { + while (--len > 0 && (p = (char)XTOLOWER(*pattern++)) == '*') + ; + + if (len == 0) + p = '\0'; + + while ( (s = (char)XTOLOWER(*str)) != '\0') { + if (s == p) + break; + if (s == '.') + return 0; + str++; + } + } + else { + if (p != (char)XTOLOWER(*str)) + return 0; + } + + if (*str != '\0') + str++; + + if (len > 0) + len--; + } + + return *str == '\0'; +} + + +/* try to find an altName match to domain, return 1 on success */ +static int CheckAltNames(DecodedCert* dCert, char* domain) +{ + int match = 0; + DNS_entry* altName = NULL; + + CYASSL_MSG("Checking AltNames"); + + if (dCert) + altName = dCert->altNames; + + while (altName) { + CYASSL_MSG(" individual AltName check"); + + if (MatchDomainName(altName->name,(int)XSTRLEN(altName->name), domain)){ + match = 1; + break; + } + + altName = altName->next; + } + + return match; +} + + +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) + +/* Copy parts X509 needs from Decoded cert, 0 on success */ +int CopyDecodedToX509(CYASSL_X509* x509, DecodedCert* dCert) +{ + int ret = 0; + + if (x509 == NULL || dCert == NULL) + return BAD_FUNC_ARG; + + x509->version = dCert->version + 1; + + XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX); + x509->issuer.name[ASN_NAME_MAX - 1] = '\0'; + x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1; +#ifdef OPENSSL_EXTRA + if (dCert->issuerName.fullName != NULL) { + XMEMCPY(&x509->issuer.fullName, + &dCert->issuerName, sizeof(DecodedName)); + x509->issuer.fullName.fullName = (char*)XMALLOC( + dCert->issuerName.fullNameLen, NULL, DYNAMIC_TYPE_X509); + if (x509->issuer.fullName.fullName != NULL) + XMEMCPY(x509->issuer.fullName.fullName, + dCert->issuerName.fullName, dCert->issuerName.fullNameLen); + } +#endif /* OPENSSL_EXTRA */ + + XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX); + x509->subject.name[ASN_NAME_MAX - 1] = '\0'; + x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1; +#ifdef OPENSSL_EXTRA + if (dCert->subjectName.fullName != NULL) { + XMEMCPY(&x509->subject.fullName, + &dCert->subjectName, sizeof(DecodedName)); + x509->subject.fullName.fullName = (char*)XMALLOC( + dCert->subjectName.fullNameLen, NULL, DYNAMIC_TYPE_X509); + if (x509->subject.fullName.fullName != NULL) + XMEMCPY(x509->subject.fullName.fullName, + dCert->subjectName.fullName, dCert->subjectName.fullNameLen); + } +#endif /* OPENSSL_EXTRA */ + + XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE); + x509->serialSz = dCert->serialSz; + if (dCert->subjectCNLen < ASN_NAME_MAX) { + XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen); + x509->subjectCN[dCert->subjectCNLen] = '\0'; + } + else + x509->subjectCN[0] = '\0'; + +#ifdef CYASSL_SEP + { + int minSz = min(dCert->deviceTypeSz, EXTERNAL_SERIAL_SIZE); + if (minSz > 0) { + x509->deviceTypeSz = minSz; + XMEMCPY(x509->deviceType, dCert->deviceType, minSz); + } + else + x509->deviceTypeSz = 0; + minSz = min(dCert->hwTypeSz, EXTERNAL_SERIAL_SIZE); + if (minSz != 0) { + x509->hwTypeSz = minSz; + XMEMCPY(x509->hwType, dCert->hwType, minSz); + } + else + x509->hwTypeSz = 0; + minSz = min(dCert->hwSerialNumSz, EXTERNAL_SERIAL_SIZE); + if (minSz != 0) { + x509->hwSerialNumSz = minSz; + XMEMCPY(x509->hwSerialNum, dCert->hwSerialNum, minSz); + } + else + x509->hwSerialNumSz = 0; + } +#endif /* CYASSL_SEP */ + { + int minSz = min(dCert->beforeDateLen, MAX_DATE_SZ); + if (minSz != 0) { + x509->notBeforeSz = minSz; + XMEMCPY(x509->notBefore, dCert->beforeDate, minSz); + } + else + x509->notBeforeSz = 0; + minSz = min(dCert->afterDateLen, MAX_DATE_SZ); + if (minSz != 0) { + x509->notAfterSz = minSz; + XMEMCPY(x509->notAfter, dCert->afterDate, minSz); + } + else + x509->notAfterSz = 0; + } + + if (dCert->publicKey != NULL && dCert->pubKeySize != 0) { + x509->pubKey.buffer = (byte*)XMALLOC( + dCert->pubKeySize, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + if (x509->pubKey.buffer != NULL) { + x509->pubKeyOID = dCert->keyOID; + x509->pubKey.length = dCert->pubKeySize; + XMEMCPY(x509->pubKey.buffer, dCert->publicKey, dCert->pubKeySize); + } + else + ret = MEMORY_E; + } + + if (dCert->signature != NULL && dCert->sigLength != 0) { + x509->sig.buffer = (byte*)XMALLOC( + dCert->sigLength, NULL, DYNAMIC_TYPE_SIGNATURE); + if (x509->sig.buffer == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(x509->sig.buffer, dCert->signature, dCert->sigLength); + x509->sig.length = dCert->sigLength; + x509->sigOID = dCert->signatureOID; + } + } + + /* store cert for potential retrieval */ + x509->derCert.buffer = (byte*)XMALLOC(dCert->maxIdx, NULL, + DYNAMIC_TYPE_CERT); + if (x509->derCert.buffer == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(x509->derCert.buffer, dCert->source, dCert->maxIdx); + x509->derCert.length = dCert->maxIdx; + } + + x509->altNames = dCert->altNames; + dCert->altNames = NULL; /* takes ownership */ + x509->altNamesNext = x509->altNames; /* index hint */ + + x509->isCa = dCert->isCA; +#ifdef OPENSSL_EXTRA + x509->pathLength = dCert->pathLength; + x509->keyUsage = dCert->extKeyUsage; + + x509->basicConstSet = dCert->extBasicConstSet; + x509->basicConstCrit = dCert->extBasicConstCrit; + x509->basicConstPlSet = dCert->extBasicConstPlSet; + x509->subjAltNameSet = dCert->extSubjAltNameSet; + x509->subjAltNameCrit = dCert->extSubjAltNameCrit; + x509->authKeyIdSet = dCert->extAuthKeyIdSet; + x509->authKeyIdCrit = dCert->extAuthKeyIdCrit; + if (dCert->extAuthKeyIdSrc != NULL && dCert->extAuthKeyIdSz != 0) { + x509->authKeyId = (byte*)XMALLOC(dCert->extAuthKeyIdSz, NULL, 0); + if (x509->authKeyId != NULL) { + XMEMCPY(x509->authKeyId, + dCert->extAuthKeyIdSrc, dCert->extAuthKeyIdSz); + x509->authKeyIdSz = dCert->extAuthKeyIdSz; + } + else + ret = MEMORY_E; + } + x509->subjKeyIdSet = dCert->extSubjKeyIdSet; + x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit; + if (dCert->extSubjKeyIdSrc != NULL && dCert->extSubjKeyIdSz != 0) { + x509->subjKeyId = (byte*)XMALLOC(dCert->extSubjKeyIdSz, NULL, 0); + if (x509->subjKeyId != NULL) { + XMEMCPY(x509->subjKeyId, + dCert->extSubjKeyIdSrc, dCert->extSubjKeyIdSz); + x509->subjKeyIdSz = dCert->extSubjKeyIdSz; + } + else + ret = MEMORY_E; + } + x509->keyUsageSet = dCert->extKeyUsageSet; + x509->keyUsageCrit = dCert->extKeyUsageCrit; + #ifdef CYASSL_SEP + x509->certPolicySet = dCert->extCertPolicySet; + x509->certPolicyCrit = dCert->extCertPolicyCrit; + #endif /* CYASSL_SEP */ +#endif /* OPENSSL_EXTRA */ +#ifdef HAVE_ECC + x509->pkCurveOID = dCert->pkCurveOID; +#endif /* HAVE_ECC */ + + return ret; +} + +#endif /* KEEP_PEER_CERT || SESSION_CERTS */ + + +static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 size) +{ + word32 listSz, begin = *inOutIdx; + int ret = 0; + int anyError = 0; + int totalCerts = 0; /* number of certs in certs buffer */ + int count; + char domain[ASN_NAME_MAX]; + buffer certs[MAX_CHAIN_DEPTH]; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo); + #endif + + if ((*inOutIdx - begin) + OPAQUE24_LEN > size) + return BUFFER_ERROR; + + c24to32(input + *inOutIdx, &listSz); + *inOutIdx += OPAQUE24_LEN; + +#ifdef HAVE_MAX_FRAGMENT + if (listSz > ssl->max_fragment) + return BUFFER_E; +#else + if (listSz > MAX_RECORD_SIZE) + return BUFFER_E; +#endif + + if ((*inOutIdx - begin) + listSz != size) + return BUFFER_ERROR; + + CYASSL_MSG("Loading peer's cert chain"); + /* first put cert chain into buffer so can verify top down + we're sent bottom up */ + while (listSz) { + word32 certSz; + + if (totalCerts >= MAX_CHAIN_DEPTH) + return MAX_CHAIN_ERROR; + + if ((*inOutIdx - begin) + OPAQUE24_LEN > size) + return BUFFER_ERROR; + + c24to32(input + *inOutIdx, &certSz); + *inOutIdx += OPAQUE24_LEN; + + if ((*inOutIdx - begin) + certSz > size) + return BUFFER_ERROR; + + certs[totalCerts].length = certSz; + certs[totalCerts].buffer = input + *inOutIdx; + +#ifdef SESSION_CERTS + if (ssl->session.chain.count < MAX_CHAIN_DEPTH && + certSz < MAX_X509_SIZE) { + ssl->session.chain.certs[ssl->session.chain.count].length = certSz; + XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer, + input + *inOutIdx, certSz); + ssl->session.chain.count++; + } else { + CYASSL_MSG("Couldn't store chain cert for session"); + } +#endif + + *inOutIdx += certSz; + listSz -= certSz + CERT_HEADER_SZ; + + totalCerts++; + CYASSL_MSG(" Put another cert into chain"); + } + + count = totalCerts; + + /* verify up to peer's first */ + while (count > 1) { + buffer myCert = certs[count - 1]; + DecodedCert dCert; + byte* subjectHash; + + InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); + ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, + ssl->ctx->cm); + #ifndef NO_SKID + subjectHash = dCert.extSubjKeyId; + #else + subjectHash = dCert.subjectHash; + #endif + + if (ret == 0 && dCert.isCA == 0) { + CYASSL_MSG("Chain cert is not a CA, not adding as one"); + } + else if (ret == 0 && ssl->options.verifyNone) { + CYASSL_MSG("Chain cert not verified by option, not adding as CA"); + } + else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) { + buffer add; + add.length = myCert.length; + add.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, + DYNAMIC_TYPE_CA); + CYASSL_MSG("Adding CA from chain"); + + if (add.buffer == NULL) + return MEMORY_E; + XMEMCPY(add.buffer, myCert.buffer, myCert.length); + + ret = AddCA(ssl->ctx->cm, add, CYASSL_CHAIN_CA, + ssl->ctx->verifyPeer); + if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ + } + else if (ret != 0) { + CYASSL_MSG("Failed to verify CA from chain"); + } + else { + CYASSL_MSG("Verified CA from chain and already had it"); + } + +#ifdef HAVE_CRL + if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) { + CYASSL_MSG("Doing Non Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); + + if (ret != 0) { + CYASSL_MSG("\tCRL check not ok"); + } + } +#endif /* HAVE_CRL */ + + if (ret != 0 && anyError == 0) + anyError = ret; /* save error from last time */ + + FreeDecodedCert(&dCert); + count--; + } + + /* peer's, may not have one if blank client cert sent by TLSv1.2 */ + if (count) { + buffer myCert = certs[0]; + DecodedCert dCert; + int fatal = 0; + + CYASSL_MSG("Verifying Peer's cert"); + + InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); + ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, + ssl->ctx->cm); + if (ret == 0) { + CYASSL_MSG("Verified Peer's cert"); + fatal = 0; + } + else if (ret == ASN_PARSE_E) { + CYASSL_MSG("Got Peer cert ASN PARSE ERROR, fatal"); + fatal = 1; + } + else { + CYASSL_MSG("Failed to verify Peer's cert"); + if (ssl->verifyCallback) { + CYASSL_MSG("\tCallback override available, will continue"); + fatal = 0; + } + else { + CYASSL_MSG("\tNo callback override available, fatal"); + fatal = 1; + } + } + +#ifdef HAVE_OCSP + if (fatal == 0 && ssl->ctx->cm->ocspEnabled) { + ret = CheckCertOCSP(ssl->ctx->cm->ocsp, &dCert); + if (ret != 0) { + CYASSL_MSG("\tOCSP Lookup not ok"); + fatal = 0; + } + } +#endif + +#ifdef HAVE_CRL + if (fatal == 0 && ssl->ctx->cm->crlEnabled) { + int doCrlLookup = 1; + + #ifdef HAVE_OCSP + if (ssl->ctx->cm->ocspEnabled) { + doCrlLookup = (ret == OCSP_CERT_UNKNOWN); + } + #endif /* HAVE_OCSP */ + + if (doCrlLookup) { + CYASSL_MSG("Doing Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); + + if (ret != 0) { + CYASSL_MSG("\tCRL check not ok"); + fatal = 0; + } + } + } + +#endif /* HAVE_CRL */ + +#ifdef KEEP_PEER_CERT + { + /* set X509 format for peer cert even if fatal */ + int copyRet = CopyDecodedToX509(&ssl->peerCert, &dCert); + if (copyRet == MEMORY_E) + fatal = 1; + } +#endif + +#ifndef IGNORE_KEY_EXTENSIONS + if (dCert.extKeyUsageSet) { + if ((ssl->specs.kea == rsa_kea) && + (dCert.extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) { + ret = KEYUSE_ENCIPHER_E; + } + if ((ssl->specs.sig_algo == rsa_sa_algo || + ssl->specs.sig_algo == ecc_dsa_sa_algo) && + (dCert.extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { + CYASSL_MSG("KeyUse Digital Sig not set"); + ret = KEYUSE_SIGNATURE_E; + } + } + + if (dCert.extExtKeyUsageSet) { + if (ssl->options.side == CYASSL_CLIENT_END) { + if ((dCert.extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { + CYASSL_MSG("ExtKeyUse Server Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + else { + if ((dCert.extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { + CYASSL_MSG("ExtKeyUse Client Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + } +#endif /* IGNORE_KEY_EXTENSIONS */ + + if (fatal) { + FreeDecodedCert(&dCert); + ssl->error = ret; + return ret; + } + ssl->options.havePeerCert = 1; + + /* store for callback use */ + if (dCert.subjectCNLen < ASN_NAME_MAX) { + XMEMCPY(domain, dCert.subjectCN, dCert.subjectCNLen); + domain[dCert.subjectCNLen] = '\0'; + } + else + domain[0] = '\0'; + + if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) { + if (MatchDomainName(dCert.subjectCN, dCert.subjectCNLen, + (char*)ssl->buffers.domainName.buffer) == 0) { + CYASSL_MSG("DomainName match on common name failed"); + if (CheckAltNames(&dCert, + (char*)ssl->buffers.domainName.buffer) == 0 ) { + CYASSL_MSG("DomainName match on alt names failed too"); + ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */ + } + } + } + + /* decode peer key */ + switch (dCert.keyOID) { + #ifndef NO_RSA + case RSAk: + { + word32 idx = 0; + if (RsaPublicKeyDecode(dCert.publicKey, &idx, + ssl->peerRsaKey, dCert.pubKeySize) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerRsaKeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + ssl->buffers.peerRsaKey.buffer = + XMALLOC(dCert.pubKeySize, + ssl->heap, DYNAMIC_TYPE_RSA); + if (ssl->buffers.peerRsaKey.buffer == NULL) + ret = MEMORY_ERROR; + else { + XMEMCPY(ssl->buffers.peerRsaKey.buffer, + dCert.publicKey, dCert.pubKeySize); + ssl->buffers.peerRsaKey.length = + dCert.pubKeySize; + } + #endif /* NO_RSA */ + #endif /*HAVE_PK_CALLBACKS */ + } + } + break; + #endif /* NO_RSA */ + #ifdef HAVE_NTRU + case NTRUk: + { + if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) { + ret = PEER_KEY_ERROR; + } + else { + XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize); + ssl->peerNtruKeyLen = (word16)dCert.pubKeySize; + ssl->peerNtruKeyPresent = 1; + } + } + break; + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ECDSAk: + { + if (ecc_import_x963(dCert.publicKey, dCert.pubKeySize, + ssl->peerEccDsaKey) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerEccDsaKeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ssl->buffers.peerEccDsaKey.buffer = + XMALLOC(dCert.pubKeySize, + ssl->heap, DYNAMIC_TYPE_ECC); + if (ssl->buffers.peerEccDsaKey.buffer == NULL) + ret = MEMORY_ERROR; + else { + XMEMCPY(ssl->buffers.peerEccDsaKey.buffer, + dCert.publicKey, dCert.pubKeySize); + ssl->buffers.peerEccDsaKey.length = + dCert.pubKeySize; + } + #endif /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + } + } + break; + #endif /* HAVE_ECC */ + default: + break; + } + + FreeDecodedCert(&dCert); + } + + if (anyError != 0 && ret == 0) + ret = anyError; + + if (ret == 0 && ssl->options.side == CYASSL_CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + + if (ret != 0) { + if (!ssl->options.verifyNone) { + int why = bad_certificate; + if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) + why = certificate_expired; + if (ssl->verifyCallback) { + int ok; + CYASSL_X509_STORE_CTX store; + + store.error = ret; + store.error_depth = totalCerts; + store.discardSessionCerts = 0; + store.domain = domain; + store.userCtx = ssl->verifyCbCtx; +#ifdef KEEP_PEER_CERT + store.current_cert = &ssl->peerCert; +#else + store.current_cert = NULL; +#endif +#ifdef FORTRESS + store.ex_data = ssl; +#endif + ok = ssl->verifyCallback(0, &store); + if (ok) { + CYASSL_MSG("Verify callback overriding error!"); + ret = 0; + } + #ifdef SESSION_CERTS + if (store.discardSessionCerts) { + CYASSL_MSG("Verify callback requested discard sess certs"); + ssl->session.chain.count = 0; + } + #endif + } + if (ret != 0) { + SendAlert(ssl, alert_fatal, why); /* try to send */ + ssl->options.isClosed = 1; + } + } + ssl->error = ret; + } +#ifdef CYASSL_ALWAYS_VERIFY_CB + else { + if (ssl->verifyCallback) { + int ok; + CYASSL_X509_STORE_CTX store; + + store.error = ret; + store.error_depth = totalCerts; + store.discardSessionCerts = 0; + store.domain = domain; + store.userCtx = ssl->verifyCbCtx; +#ifdef KEEP_PEER_CERT + store.current_cert = &ssl->peerCert; +#endif + store.ex_data = ssl; + + ok = ssl->verifyCallback(1, &store); + if (!ok) { + CYASSL_MSG("Verify callback overriding valid certificate!"); + ret = -1; + SendAlert(ssl, alert_fatal, bad_certificate); + ssl->options.isClosed = 1; + } + #ifdef SESSION_CERTS + if (store.discardSessionCerts) { + CYASSL_MSG("Verify callback requested discard sess certs"); + ssl->session.chain.count = 0; + } + #endif + } + } +#endif + + return ret; +} + +#endif /* !NO_CERTS */ + + +static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz) +{ + int ret = 0; + + if (size) /* must be 0 */ + return BUFFER_ERROR; + + if (ssl->keys.encryptionOn) { + byte verify[MAX_DIGEST_SIZE]; + int padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - + ssl->specs.hash_size; + + ret = ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ, + HANDSHAKE_HEADER_SZ, handshake, 1); + if (ret != 0) + return ret; + + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + padSz -= ssl->specs.block_size; + + /* access beyond input + size should be checked against totalSz */ + if ((word32) (*inOutIdx + ssl->specs.hash_size + padSz) > totalSz) + return INCOMPLETE_DATA; + + /* verify */ + if (XMEMCMP(input + *inOutIdx, verify, ssl->specs.hash_size) != 0) { + CYASSL_MSG(" hello_request verify mac error"); + return VERIFY_MAC_ERROR; + } + + *inOutIdx += ssl->specs.hash_size + padSz; + } + + if (ssl->options.side == CYASSL_SERVER_END) { + SendAlert(ssl, alert_fatal, unexpected_message); /* try */ + return FATAL_ERROR; + } + else + return SendAlert(ssl, alert_warning, no_renegotiation); +} + + +int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, word32 size, + word32 totalSz, int sniff) +{ + word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ); + + if (finishedSz != size) + return BUFFER_ERROR; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); + #endif + + if (sniff == NO_SNIFF) { + if (XMEMCMP(input + *inOutIdx, &ssl->verifyHashes, size) != 0) { + CYASSL_MSG("Verify finished error on hashes"); + return VERIFY_FINISHED_ERROR; + } + } + + /* increment beyond input + size should be checked against totalSz */ + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return INCOMPLETE_DATA; + + /* force input exhaustion at ProcessReply consuming padSz */ + *inOutIdx += size + ssl->keys.padSz; + + if (ssl->options.side == CYASSL_CLIENT_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + if (!ssl->options.resuming) { + ssl->options.handShakeState = HANDSHAKE_DONE; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + /* Other side has received our Finished, go to next epoch */ + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 1; + } +#endif + } + } + else { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + if (ssl->options.resuming) { + ssl->options.handShakeState = HANDSHAKE_DONE; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + /* Other side has received our Finished, go to next epoch */ + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 1; + } +#endif + } + } + + return 0; +} + + +static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, + byte type, word32 size, word32 totalSz) +{ + int ret = 0; + (void)totalSz; + + CYASSL_ENTER("DoHandShakeMsgType"); + + /* make sure can read the message */ + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + + ret = HashInput(ssl, input + *inOutIdx, size); + if (ret != 0) + return ret; + +#ifdef CYASSL_CALLBACKS + /* add name later, add on record and handshake header part back on */ + if (ssl->toInfoOn) { + int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add, + size + add, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } +#endif + + if (ssl->options.handShakeState == HANDSHAKE_DONE && type != hello_request){ + CYASSL_MSG("HandShake message after handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls == 0 && + ssl->options.serverState == NULL_STATE && type != server_hello) { + CYASSL_MSG("First server message not server hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == CYASSL_CLIENT_END && ssl->options.dtls && + type == server_hello_done && + ssl->options.serverState < SERVER_HELLO_COMPLETE) { + CYASSL_MSG("Server hello done received before server hello in DTLS"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.clientState == NULL_STATE && type != client_hello) { + CYASSL_MSG("First client message not client hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + + switch (type) { + + case hello_request: + CYASSL_MSG("processing hello request"); + ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz); + break; + +#ifndef NO_CYASSL_CLIENT + case hello_verify_request: + CYASSL_MSG("processing hello verify request"); + ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size); + break; + + case server_hello: + CYASSL_MSG("processing server hello"); + ret = DoServerHello(ssl, input, inOutIdx, size); + break; + +#ifndef NO_CERTS + case certificate_request: + CYASSL_MSG("processing certificate request"); + ret = DoCertificateRequest(ssl, input, inOutIdx, size); + break; +#endif + + case server_key_exchange: + CYASSL_MSG("processing server key exchange"); + ret = DoServerKeyExchange(ssl, input, inOutIdx, size); + break; +#endif + +#ifndef NO_CERTS + case certificate: + CYASSL_MSG("processing certificate"); + ret = DoCertificate(ssl, input, inOutIdx, size); + break; +#endif + + case server_hello_done: + CYASSL_MSG("processing server hello done"); + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHelloDone", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ServerHelloDone", &ssl->timeoutInfo); + #endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + break; + + case finished: + CYASSL_MSG("processing finished"); + ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); + break; + +#ifndef NO_CYASSL_SERVER + case client_hello: + CYASSL_MSG("processing client hello"); + ret = DoClientHello(ssl, input, inOutIdx, size); + break; + + case client_key_exchange: + CYASSL_MSG("processing client key exchange"); + ret = DoClientKeyExchange(ssl, input, inOutIdx, size); + break; + +#if !defined(NO_RSA) || defined(HAVE_ECC) + case certificate_verify: + CYASSL_MSG("processing certificate verify"); + ret = DoCertificateVerify(ssl, input, inOutIdx, size); + break; +#endif /* !NO_RSA || HAVE_ECC */ + +#endif /* !NO_CYASSL_SERVER */ + + default: + CYASSL_MSG("Unknown handshake message type"); + ret = UNKNOWN_HANDSHAKE_TYPE; + break; + } + + CYASSL_LEAVE("DoHandShakeMsgType()", ret); + return ret; +} + + +static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + byte type; + word32 size; + int ret = 0; + + CYASSL_ENTER("DoHandShakeMsg()"); + + if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0) + return PARSE_ERROR; + + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + + CYASSL_LEAVE("DoHandShakeMsg()", ret); + return ret; +} + + +#ifdef CYASSL_DTLS + +static INLINE int DtlsCheckWindow(DtlsState* state) +{ + word32 cur; + word32 next; + DtlsSeq window; + + if (state->curEpoch == state->nextEpoch) { + next = state->nextSeq; + window = state->window; + } + else if (state->curEpoch < state->nextEpoch) { + next = state->prevSeq; + window = state->prevWindow; + } + else { + return 0; + } + + cur = state->curSeq; + + if ((next > DTLS_SEQ_BITS) && (cur < next - DTLS_SEQ_BITS)) { + return 0; + } + else if ((cur < next) && (window & (1 << (next - cur - 1)))) { + return 0; + } + + return 1; +} + + +static INLINE int DtlsUpdateWindow(DtlsState* state) +{ + word32 cur; + word32* next; + DtlsSeq* window; + + if (state->curEpoch == state->nextEpoch) { + next = &state->nextSeq; + window = &state->window; + } + else { + next = &state->prevSeq; + window = &state->prevWindow; + } + + cur = state->curSeq; + + if (cur < *next) { + *window |= (1 << (*next - cur - 1)); + } + else { + *window <<= (1 + cur - *next); + *window |= 1; + *next = cur + 1; + } + + return 1; +} + + +static int DtlsMsgDrain(CYASSL* ssl) +{ + DtlsMsg* item = ssl->dtls_msg_list; + int ret = 0; + + /* While there is an item in the store list, and it is the expected + * message, and it is complete, and there hasn't been an error in the + * last messge... */ + while (item != NULL && + ssl->keys.dtls_expected_peer_handshake_number == item->seq && + item->fragSz == item->sz && + ret == 0) { + word32 idx = 0; + ssl->keys.dtls_expected_peer_handshake_number++; + ret = DoHandShakeMsgType(ssl, item->msg, + &idx, item->type, item->sz, item->sz); + ssl->dtls_msg_list = item->next; + DtlsMsgDelete(item, ssl->heap); + item = ssl->dtls_msg_list; + } + + return ret; +} + + +static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + byte type; + word32 size; + word32 fragOffset, fragSz; + int ret = 0; + + CYASSL_ENTER("DoDtlsHandShakeMsg()"); + if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, + &size, &fragOffset, &fragSz) != 0) + return PARSE_ERROR; + + if (*inOutIdx + fragSz > totalSz) + return INCOMPLETE_DATA; + + /* Check the handshake sequence number first. If out of order, + * add the current message to the list. If the message is in order, + * but it is a fragment, add the current message to the list, then + * check the head of the list to see if it is complete, if so, pop + * it out as the current message. If the message is complete and in + * order, process it. Check the head of the list to see if it is in + * order, if so, process it. (Repeat until list exhausted.) If the + * head is out of order, return for more processing. + */ + if (ssl->keys.dtls_peer_handshake_number > + ssl->keys.dtls_expected_peer_handshake_number) { + /* Current message is out of order. It will get stored in the list. + * Storing also takes care of defragmentation. */ + ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, + ssl->keys.dtls_peer_handshake_number, input + *inOutIdx, + size, type, fragOffset, fragSz, ssl->heap); + *inOutIdx += fragSz; + ret = 0; + } + else if (ssl->keys.dtls_peer_handshake_number < + ssl->keys.dtls_expected_peer_handshake_number) { + /* Already saw this message and processed it. It can be ignored. */ + *inOutIdx += fragSz; + ret = 0; + } + else if (fragSz < size) { + /* Since this branch is in order, but fragmented, dtls_msg_list will be + * pointing to the message with this fragment in it. Check it to see + * if it is completed. */ + ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, + ssl->keys.dtls_peer_handshake_number, input + *inOutIdx, + size, type, fragOffset, fragSz, ssl->heap); + *inOutIdx += fragSz; + ret = 0; + if (ssl->dtls_msg_list != NULL && + ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) + ret = DtlsMsgDrain(ssl); + } + else { + /* This branch is in order next, and a complete message. */ + ssl->keys.dtls_expected_peer_handshake_number++; + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + if (ret == 0 && ssl->dtls_msg_list != NULL) + ret = DtlsMsgDrain(ssl); + } + + CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret); + return ret; +} +#endif + + +static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) +{ + if (verify) + return ssl->keys.peer_sequence_number++; + else + return ssl->keys.sequence_number++; +} + + +#ifdef HAVE_AEAD +static INLINE void AeadIncrementExpIV(CYASSL* ssl) +{ + int i; + for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) { + if (++ssl->keys.aead_exp_IV[i]) return; + } +} +#endif + + +static INLINE int Encrypt(CYASSL* ssl, byte* out, const byte* input, word16 sz) +{ + (void)out; + (void)input; + (void)sz; + + if (ssl->encrypt.setup == 0) { + CYASSL_MSG("Encrypt ciphers not setup"); + return ENCRYPT_ERROR; + } + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case cyassl_rc4: + Arc4Process(ssl->encrypt.arc4, out, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case cyassl_triple_des: + return Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz); + #endif + + #ifdef BUILD_AES + case cyassl_aes: + return AesCbcEncrypt(ssl->encrypt.aes, out, input, sz); + #endif + + #ifdef BUILD_AESGCM + case cyassl_aes_gcm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + const byte* additionalSrc = input - 5; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 0), + additional + AEAD_SEQ_OFFSET); + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + additionalSrc -= DTLS_HANDSHAKE_EXTRA; + #endif + XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3); + + /* Store the length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + additional + AEAD_LEN_OFFSET); + XMEMCPY(nonce, + ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ); + XMEMCPY(nonce + AEAD_IMP_IV_SZ, + ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); + AesGcmEncrypt(ssl->encrypt.aes, + out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ, + sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + nonce, AEAD_NONCE_SZ, + out + sz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, additional, + AEAD_AUTH_DATA_SZ); + AeadIncrementExpIV(ssl); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + } + break; + #endif + + #ifdef HAVE_AESCCM + case cyassl_aes_ccm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + const byte* additionalSrc = input - 5; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 0), + additional + AEAD_SEQ_OFFSET); + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + c16toa(ssl->keys.dtls_epoch, additional); + additionalSrc -= DTLS_HANDSHAKE_EXTRA; + } + #endif + XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3); + + /* Store the length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + additional + AEAD_LEN_OFFSET); + XMEMCPY(nonce, + ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ); + XMEMCPY(nonce + AEAD_IMP_IV_SZ, + ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); + AesCcmEncrypt(ssl->encrypt.aes, + out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ, + sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + nonce, AEAD_NONCE_SZ, + out + sz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, + additional, AEAD_AUTH_DATA_SZ); + AeadIncrementExpIV(ssl); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + + break; + } + #endif + + #ifdef HAVE_CAMELLIA + case cyassl_camellia: + CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case cyassl_hc128: + return Hc128_Process(ssl->encrypt.hc128, out, input, sz); + #endif + + #ifdef BUILD_RABBIT + case cyassl_rabbit: + return RabbitProcess(ssl->encrypt.rabbit, out, input, sz); + #endif + + #ifdef HAVE_NULL_CIPHER + case cyassl_cipher_null: + if (input != out) { + XMEMMOVE(out, input, sz); + } + break; + #endif + + default: + CYASSL_MSG("CyaSSL Encrypt programming error"); + return ENCRYPT_ERROR; + } + + return 0; +} + + + +static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, + word16 sz) +{ + (void)plain; + (void)input; + (void)sz; + + if (ssl->decrypt.setup == 0) { + CYASSL_MSG("Decrypt ciphers not setup"); + return DECRYPT_ERROR; + } + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case cyassl_rc4: + Arc4Process(ssl->decrypt.arc4, plain, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case cyassl_triple_des: + return Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz); + #endif + + #ifdef BUILD_AES + case cyassl_aes: + return AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz); + #endif + + #ifdef BUILD_AESGCM + case cyassl_aes_gcm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; + additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; + additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + + c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + additional + AEAD_LEN_OFFSET); + XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ); + XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ); + if (AesGcmDecrypt(ssl->decrypt.aes, + plain + AEAD_EXP_IV_SZ, + input + AEAD_EXP_IV_SZ, + sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + nonce, AEAD_NONCE_SZ, + input + sz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, + additional, AEAD_AUTH_DATA_SZ) < 0) { + SendAlert(ssl, alert_fatal, bad_record_mac); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + return VERIFY_MAC_ERROR; + } + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + break; + } + #endif + + #ifdef HAVE_AESCCM + case cyassl_aes_ccm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + c16toa(ssl->keys.dtls_state.curEpoch, additional); + #endif + + additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; + additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; + additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + + c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + additional + AEAD_LEN_OFFSET); + XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ); + XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ); + if (AesCcmDecrypt(ssl->decrypt.aes, + plain + AEAD_EXP_IV_SZ, + input + AEAD_EXP_IV_SZ, + sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size, + nonce, AEAD_NONCE_SZ, + input + sz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, + additional, AEAD_AUTH_DATA_SZ) < 0) { + SendAlert(ssl, alert_fatal, bad_record_mac); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + return VERIFY_MAC_ERROR; + } + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + break; + } + #endif + + #ifdef HAVE_CAMELLIA + case cyassl_camellia: + CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz); + break; + #endif + + #ifdef HAVE_HC128 + case cyassl_hc128: + return Hc128_Process(ssl->decrypt.hc128, plain, input, sz); + #endif + + #ifdef BUILD_RABBIT + case cyassl_rabbit: + return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); + #endif + + #ifdef HAVE_NULL_CIPHER + case cyassl_cipher_null: + if (input != plain) { + XMEMMOVE(plain, input, sz); + } + break; + #endif + + default: + CYASSL_MSG("CyaSSL Decrypt programming error"); + return DECRYPT_ERROR; + } + return 0; +} + + +/* check cipher text size for sanity */ +static int SanityCheckCipherText(CYASSL* ssl, word32 encryptSz) +{ +#ifdef HAVE_TRUNCATED_HMAC + word32 minLength = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 minLength = ssl->specs.hash_size; /* covers stream */ +#endif + + if (ssl->specs.cipher_type == block) { + if (encryptSz % ssl->specs.block_size) { + CYASSL_MSG("Block ciphertext not block size"); + return SANITY_CIPHER_E; + } + + minLength++; /* pad byte */ + + if (ssl->specs.block_size > minLength) + minLength = ssl->specs.block_size; + + if (ssl->options.tls1_1) + minLength += ssl->specs.block_size; /* explicit IV */ + } + else if (ssl->specs.cipher_type == aead) { + minLength = ssl->specs.aead_mac_size + AEAD_EXP_IV_SZ; + /* explicit IV + authTag size */ + } + + if (encryptSz < minLength) { + CYASSL_MSG("Ciphertext not minimum size"); + return SANITY_CIPHER_E; + } + + return 0; +} + + +#ifndef NO_OLD_TLS + +static INLINE void Md5Rounds(int rounds, const byte* data, int sz) +{ + Md5 md5; + int i; + + InitMd5(&md5); + + for (i = 0; i < rounds; i++) + Md5Update(&md5, data, sz); +} + + + +/* do a dummy sha round */ +static INLINE void ShaRounds(int rounds, const byte* data, int sz) +{ + Sha sha; + int i; + + InitSha(&sha); /* no error check on purpose, dummy round */ + + for (i = 0; i < rounds; i++) + ShaUpdate(&sha, data, sz); +} +#endif + + +#ifndef NO_SHA256 + +static INLINE void Sha256Rounds(int rounds, const byte* data, int sz) +{ + Sha256 sha256; + int i; + + InitSha256(&sha256); /* no error check on purpose, dummy round */ + + for (i = 0; i < rounds; i++) { + Sha256Update(&sha256, data, sz); + /* no error check on purpose, dummy round */ + } + +} + +#endif + + +#ifdef CYASSL_SHA384 + +static INLINE void Sha384Rounds(int rounds, const byte* data, int sz) +{ + Sha384 sha384; + int i; + + InitSha384(&sha384); /* no error check on purpose, dummy round */ + + for (i = 0; i < rounds; i++) { + Sha384Update(&sha384, data, sz); + /* no error check on purpose, dummy round */ + } +} + +#endif + + +#ifdef CYASSL_SHA512 + +static INLINE void Sha512Rounds(int rounds, const byte* data, int sz) +{ + Sha512 sha512; + int i; + + InitSha512(&sha512); /* no error check on purpose, dummy round */ + + for (i = 0; i < rounds; i++) { + Sha512Update(&sha512, data, sz); + /* no error check on purpose, dummy round */ + } +} + +#endif + + +#ifdef CYASSL_RIPEMD + +static INLINE void RmdRounds(int rounds, const byte* data, int sz) +{ + RipeMd ripemd; + int i; + + InitRipeMd(&ripemd); + + for (i = 0; i < rounds; i++) + RipeMdUpdate(&ripemd, data, sz); +} + +#endif + + +/* Do dummy rounds */ +static INLINE void DoRounds(int type, int rounds, const byte* data, int sz) +{ + switch (type) { + + case no_mac : + break; + +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + case md5_mac : + Md5Rounds(rounds, data, sz); + break; +#endif + +#ifndef NO_SHA + case sha_mac : + ShaRounds(rounds, data, sz); + break; +#endif +#endif + +#ifndef NO_SHA256 + case sha256_mac : + Sha256Rounds(rounds, data, sz); + break; +#endif + +#ifdef CYASSL_SHA384 + case sha384_mac : + Sha384Rounds(rounds, data, sz); + break; +#endif + +#ifdef CYASSL_SHA512 + case sha512_mac : + Sha512Rounds(rounds, data, sz); + break; +#endif + +#ifdef CYASSL_RIPEMD + case rmd_mac : + RmdRounds(rounds, data, sz); + break; +#endif + + default: + CYASSL_MSG("Bad round type"); + break; + } +} + + +/* do number of compression rounds on dummy data */ +static INLINE void CompressRounds(CYASSL* ssl, int rounds, const byte* dummy) +{ + if (rounds) + DoRounds(ssl->specs.mac_algorithm, rounds, dummy, COMPRESS_LOWER); +} + + +/* check all length bytes for equality, return 0 on success */ +static int ConstantCompare(const byte* a, const byte* b, int length) +{ + int i; + int good = 0; + int bad = 0; + + for (i = 0; i < length; i++) { + if (a[i] == b[i]) + good++; + else + bad++; + } + + if (good == length) + return 0; + else + return 0 - bad; /* compare failed */ +} + + +/* check all length bytes for the pad value, return 0 on success */ +static int PadCheck(const byte* input, byte pad, int length) +{ + int i; + int good = 0; + int bad = 0; + + for (i = 0; i < length; i++) { + if (input[i] == pad) + good++; + else + bad++; + } + + if (good == length) + return 0; + else + return 0 - bad; /* pad check failed */ +} + + +/* get compression extra rounds */ +static INLINE int GetRounds(int pLen, int padLen, int t) +{ + int roundL1 = 1; /* round up flags */ + int roundL2 = 1; + + int L1 = COMPRESS_CONSTANT + pLen - t; + int L2 = COMPRESS_CONSTANT + pLen - padLen - 1 - t; + + L1 -= COMPRESS_UPPER; + L2 -= COMPRESS_UPPER; + + if ( (L1 % COMPRESS_LOWER) == 0) + roundL1 = 0; + if ( (L2 % COMPRESS_LOWER) == 0) + roundL2 = 0; + + L1 /= COMPRESS_LOWER; + L2 /= COMPRESS_LOWER; + + L1 += roundL1; + L2 += roundL2; + + return L1 - L2; +} + + +/* timing resistant pad/verify check, return 0 on success */ +static int TimingPadVerify(CYASSL* ssl, const byte* input, int padLen, int t, + int pLen, int content) +{ + byte verify[MAX_DIGEST_SIZE]; + byte dummy[MAX_PAD_SIZE]; + int ret = 0; + + XMEMSET(dummy, 1, sizeof(dummy)); + + if ( (t + padLen + 1) > pLen) { + CYASSL_MSG("Plain Len not long enough for pad/mac"); + PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE); + ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */ + ConstantCompare(verify, input + pLen - t, t); + + return VERIFY_MAC_ERROR; + } + + if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) { + CYASSL_MSG("PadCheck failed"); + PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); + ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */ + ConstantCompare(verify, input + pLen - t, t); + + return VERIFY_MAC_ERROR; + } + + PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); + ret = ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, content, 1); + + CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy); + + if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) { + CYASSL_MSG("Verify MAC compare failed"); + return VERIFY_MAC_ERROR; + } + + if (ret != 0) + return VERIFY_MAC_ERROR; + return 0; +} + + +int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) +{ + word32 msgSz = ssl->keys.encryptSz; + word32 idx = *inOutIdx; + int dataSz; + int ivExtra = 0; + byte* rawData = input + idx; /* keep current for hmac */ +#ifdef HAVE_LIBZ + byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + CYASSL_MSG("Received App data before handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->specs.cipher_type == block) { + if (ssl->options.tls1_1) + ivExtra = ssl->specs.block_size; + } + else if (ssl->specs.cipher_type == aead) { + ivExtra = AEAD_EXP_IV_SZ; + } + + dataSz = msgSz - ivExtra - ssl->keys.padSz; + if (dataSz < 0) { + CYASSL_MSG("App data buffer error, malicious input?"); + return BUFFER_ERROR; + } + + /* read data */ + if (dataSz) { + int rawSz = dataSz; /* keep raw size for idx adjustment */ + +#ifdef HAVE_LIBZ + if (ssl->options.usingCompression) { + dataSz = myDeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp)); + if (dataSz < 0) return dataSz; + } +#endif + idx += rawSz; + + ssl->buffers.clearOutputBuffer.buffer = rawData; + ssl->buffers.clearOutputBuffer.length = dataSz; + } + + idx += ssl->keys.padSz; + +#ifdef HAVE_LIBZ + /* decompress could be bigger, overwrite after verify */ + if (ssl->options.usingCompression) + XMEMMOVE(rawData, decomp, dataSz); +#endif + + *inOutIdx = idx; + return 0; +} + + +/* process alert, return level */ +static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type, + word32 totalSz) +{ + byte level; + byte code; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("Alert", &ssl->handShakeInfo); + if (ssl->toInfoOn) + /* add record header back on to info + 2 byte level, data */ + AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx - + RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap); + #endif + + /* make sure can read the message */ + if (*inOutIdx + ALERT_SIZE > totalSz) + return BUFFER_E; + + level = input[(*inOutIdx)++]; + code = input[(*inOutIdx)++]; + ssl->alert_history.last_rx.code = code; + ssl->alert_history.last_rx.level = level; + *type = code; + if (level == alert_fatal) { + ssl->options.isClosed = 1; /* Don't send close_notify */ + } + + CYASSL_MSG("Got alert"); + if (*type == close_notify) { + CYASSL_MSG(" close notify"); + ssl->options.closeNotify = 1; + } + CYASSL_ERROR(*type); + + if (ssl->keys.encryptionOn) { + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz; + } + + return level; +} + +static int GetInputData(CYASSL *ssl, word32 size) +{ + int in; + int inSz; + int maxLength; + int usedLength; + int dtlsExtra = 0; + + + /* check max input length */ + usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx; + maxLength = ssl->buffers.inputBuffer.bufferSize - usedLength; + inSz = (int)(size - usedLength); /* from last partial read */ + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if (size < ssl->dtls_expected_rx) + dtlsExtra = (int)(ssl->dtls_expected_rx - size); + inSz = ssl->dtls_expected_rx; + } +#endif + + if (inSz > maxLength) { + if (GrowInputBuffer(ssl, size + dtlsExtra, usedLength) < 0) + return MEMORY_E; + } + + if (inSz <= 0) + return BUFFER_ERROR; + + /* Put buffer data at start if not there */ + if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0) + XMEMMOVE(ssl->buffers.inputBuffer.buffer, + ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + usedLength); + + /* remove processed data */ + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + + /* read data from network */ + do { + in = Receive(ssl, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.length, + inSz); + if (in == -1) + return SOCKET_ERROR_E; + + if (in == WANT_READ) + return WANT_READ; + + if (in > inSz) + return RECV_OVERFLOW_E; + + ssl->buffers.inputBuffer.length += in; + inSz -= in; + + } while (ssl->buffers.inputBuffer.length < size); + + return 0; +} + + +static INLINE int VerifyMac(CYASSL* ssl, const byte* input, word32 msgSz, + int content, word32* padSz) +{ + int ivExtra = 0; + int ret; + word32 pad = 0; + word32 padByte = 0; +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 digestSz = ssl->specs.hash_size; +#endif + byte verify[MAX_DIGEST_SIZE]; + + if (ssl->specs.cipher_type == block) { + if (ssl->options.tls1_1) + ivExtra = ssl->specs.block_size; + pad = *(input + msgSz - ivExtra - 1); + padByte = 1; + + if (ssl->options.tls) { + ret = TimingPadVerify(ssl, input, pad, digestSz, msgSz - ivExtra, + content); + if (ret != 0) + return ret; + } + else { /* sslv3, some implementations have bad padding, but don't + * allow bad read */ + int badPadLen = 0; + byte dummy[MAX_PAD_SIZE]; + + XMEMSET(dummy, 1, sizeof(dummy)); + + if (pad > (msgSz - digestSz - 1)) { + CYASSL_MSG("Plain Len not long enough for pad/mac"); + pad = 0; /* no bad read */ + badPadLen = 1; + } + PadCheck(dummy, (byte)pad, MAX_PAD_SIZE); /* timing only */ + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, + content, 1); + if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1, + digestSz) != 0) + return VERIFY_MAC_ERROR; + if (ret != 0 || badPadLen) + return VERIFY_MAC_ERROR; + } + } + else if (ssl->specs.cipher_type == stream) { + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1); + if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){ + return VERIFY_MAC_ERROR; + } + if (ret != 0) + return VERIFY_MAC_ERROR; + } + + if (ssl->specs.cipher_type == aead) { + *padSz = ssl->specs.aead_mac_size; + } + else { + *padSz = digestSz + pad + padByte; + } + + return 0; +} + + +/* process input requests, return 0 is done, 1 is call again to complete, and + negative number is error */ +int ProcessReply(CYASSL* ssl) +{ + int ret = 0, type, readSz; + int atomicUser = 0; + word32 startIdx = 0; +#ifndef NO_CYASSL_SERVER + byte b0, b1; +#endif +#ifdef CYASSL_DTLS + int used; +#endif + +#ifdef ATOMIC_USER + if (ssl->ctx->DecryptVerifyCb) + atomicUser = 1; +#endif + + if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE){ + CYASSL_MSG("ProcessReply retry in error state, not allowed"); + return ssl->error; + } + + for (;;) { + switch (ssl->options.processReply) { + + /* in the CYASSL_SERVER case, get the first byte for detecting + * old client hello */ + case doProcessInit: + + readSz = RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + readSz = DTLS_RECORD_HEADER_SZ; + #endif + + /* get header or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, readSz)) < 0) + return ret; + } else { + #ifdef CYASSL_DTLS + /* read ahead may already have header */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < readSz) + if ((ret = GetInputData(ssl, readSz)) < 0) + return ret; + #endif + } + +#ifndef NO_CYASSL_SERVER + + /* see if sending SSLv2 client hello */ + if ( ssl->options.side == CYASSL_SERVER_END && + ssl->options.clientState == NULL_STATE && + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx] + != handshake) { + ssl->options.processReply = runProcessOldClientHello; + + /* how many bytes need ProcessOldClientHello */ + b0 = + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; + b1 = + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; + ssl->curSize = (word16)(((b0 & 0x7f) << 8) | b1); + } + else { + ssl->options.processReply = getRecordLayerHeader; + continue; + } + + /* in the CYASSL_SERVER case, run the old client hello */ + case runProcessOldClientHello: + + /* get sz bytes or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + } else { + #ifdef CYASSL_DTLS + /* read ahead may already have */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < ssl->curSize) + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + #endif /* CYASSL_DTLS */ + } + + ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx, + ssl->curSize); + if (ret < 0) + return ret; + + else if (ssl->buffers.inputBuffer.idx == + ssl->buffers.inputBuffer.length) { + ssl->options.processReply = doProcessInit; + return 0; + } + +#endif /* NO_CYASSL_SERVER */ + + /* get the record layer header */ + case getRecordLayerHeader: + + ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + &ssl->curRL, &ssl->curSize); +#ifdef CYASSL_DTLS + if (ssl->options.dtls && ret == SEQUENCE_ERROR) { + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.length = 0; + ssl->buffers.inputBuffer.idx = 0; + continue; + } +#endif + if (ret != 0) + return ret; + + ssl->options.processReply = getData; + + /* retrieve record layer data */ + case getData: + + /* get sz bytes or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + } else { +#ifdef CYASSL_DTLS + /* read ahead may already have */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < ssl->curSize) + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; +#endif + } + + ssl->options.processReply = runProcessingOneMessage; + startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */ + + /* the record layer is here */ + case runProcessingOneMessage: + + #ifdef CYASSL_DTLS + if (ssl->options.dtls && + ssl->keys.dtls_state.curEpoch < ssl->keys.dtls_state.nextEpoch) + ssl->keys.decryptedCur = 1; + #endif + + if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0) + { + ret = SanityCheckCipherText(ssl, ssl->curSize); + if (ret < 0) + return ret; + + if (atomicUser) { + #ifdef ATOMIC_USER + ret = ssl->ctx->DecryptVerifyCb(ssl, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize, ssl->curRL.type, 1, + &ssl->keys.padSz, ssl->DecryptVerifyCtx); + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + ssl->buffers.inputBuffer.idx += ssl->specs.block_size; + /* go past TLSv1.1 IV */ + if (ssl->specs.cipher_type == aead) + ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ; + #endif /* ATOMIC_USER */ + } + else { + ret = Decrypt(ssl, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize); + if (ret < 0) { + CYASSL_ERROR(ret); + return DECRYPT_ERROR; + } + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + ssl->buffers.inputBuffer.idx += ssl->specs.block_size; + /* go past TLSv1.1 IV */ + if (ssl->specs.cipher_type == aead) + ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ; + + ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize, ssl->curRL.type, + &ssl->keys.padSz); + } + if (ret < 0) { + CYASSL_ERROR(ret); + return DECRYPT_ERROR; + } + ssl->keys.encryptSz = ssl->curSize; + ssl->keys.decryptedCur = 1; + } + + if (ssl->options.dtls) { + #ifdef CYASSL_DTLS + DtlsUpdateWindow(&ssl->keys.dtls_state); + #endif /* CYASSL_DTLS */ + } + + CYASSL_MSG("received record layer msg"); + + switch (ssl->curRL.type) { + case handshake : + /* debugging in DoHandShakeMsg */ + if (!ssl->options.dtls) { + ret = DoHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); + } + else { +#ifdef CYASSL_DTLS + ret = DoDtlsHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); +#endif + } + if (ret != 0) + return ret; + break; + + case change_cipher_spec: + CYASSL_MSG("got CHANGE CIPHER SPEC"); + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ChangeCipher", &ssl->handShakeInfo); + /* add record header back on info */ + if (ssl->toInfoOn) { + AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ, + 1 + RECORD_HEADER_SZ, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } + #endif + + if (ssl->curSize != 1) { + CYASSL_MSG("Malicious or corrupted ChangeCipher msg"); + return LENGTH_ERROR; + } + #ifndef NO_CERTS + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.verifyPeer && + ssl->options.havePeerCert) + if (!ssl->options.havePeerVerify) { + CYASSL_MSG("client didn't send cert verify"); + return NO_PEER_VERIFY; + } + #endif + + + ssl->buffers.inputBuffer.idx++; + ssl->keys.encryptionOn = 1; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolReset(ssl); + ssl->keys.dtls_state.nextEpoch++; + ssl->keys.dtls_state.nextSeq = 0; + } + #endif + + #ifdef HAVE_LIBZ + if (ssl->options.usingCompression) + if ( (ret = InitStreams(ssl)) != 0) + return ret; + #endif + if (ssl->options.resuming && ssl->options.side == + CYASSL_CLIENT_END) + ret = BuildFinished(ssl, &ssl->verifyHashes, server); + else if (!ssl->options.resuming && ssl->options.side == + CYASSL_SERVER_END) + ret = BuildFinished(ssl, &ssl->verifyHashes, client); + if (ret != 0) + return ret; + break; + + case application_data: + CYASSL_MSG("got app DATA"); + if ((ret = DoApplicationData(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx)) + != 0) { + CYASSL_ERROR(ret); + return ret; + } + break; + + case alert: + CYASSL_MSG("got ALERT!"); + ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, &type, + ssl->buffers.inputBuffer.length); + if (ret == alert_fatal) + return FATAL_ERROR; + else if (ret < 0) + return ret; + + /* catch warnings that are handled as errors */ + if (type == close_notify) + return ssl->error = ZERO_RETURN; + + if (type == decrypt_error) + return FATAL_ERROR; + break; + + default: + CYASSL_ERROR(UNKNOWN_RECORD_TYPE); + return UNKNOWN_RECORD_TYPE; + } + + ssl->options.processReply = doProcessInit; + + /* input exhausted? */ + if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length) + return 0; + /* more messages per record */ + else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) { + CYASSL_MSG("More messages in record"); + #ifdef CYASSL_DTLS + /* read-ahead but dtls doesn't bundle messages per record */ + if (ssl->options.dtls) { + ssl->options.processReply = doProcessInit; + continue; + } + #endif + ssl->options.processReply = runProcessingOneMessage; + continue; + } + /* more records */ + else { + CYASSL_MSG("More records in input"); + ssl->options.processReply = doProcessInit; + continue; + } + + default: + CYASSL_MSG("Bad process input state, programming error"); + return INPUT_CASE_ERROR; + } + } +} + + +int SendChangeCipher(CYASSL* ssl) +{ + byte *output; + int sendSz = RECORD_HEADER_SZ + ENUM_LEN; + int idx = RECORD_HEADER_SZ; + int ret; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + } + #endif + + /* check for avalaible size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddRecordHeader(output, 1, change_cipher_spec, ssl); + + output[idx] = 1; /* turn it on */ + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + + if (ssl->options.groupMessages) + return 0; + #ifdef CYASSL_DTLS + else if (ssl->options.dtls) { + /* If using DTLS, force the ChangeCipherSpec message to be in the + * same datagram as the finished message. */ + return 0; + } + #endif + else + return SendBuffered(ssl); +} + + +#ifndef NO_OLD_TLS +static int SSL_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz, + int content, int verify) +{ + byte result[MAX_DIGEST_SIZE]; + word32 digestSz = ssl->specs.hash_size; /* actual sizes */ + word32 padSz = ssl->specs.pad_size; + int ret = 0; + + Md5 md5; + Sha sha; + + /* data */ + byte seq[SEQ_SZ]; + byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */ + const byte* macSecret = CyaSSL_GetMacSecret(ssl, verify); + + XMEMSET(seq, 0, SEQ_SZ); + conLen[0] = (byte)content; + c16toa((word16)sz, &conLen[ENUM_LEN]); + c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]); + + if (ssl->specs.mac_algorithm == md5_mac) { + InitMd5(&md5); + /* inner */ + Md5Update(&md5, macSecret, digestSz); + Md5Update(&md5, PAD1, padSz); + Md5Update(&md5, seq, SEQ_SZ); + Md5Update(&md5, conLen, sizeof(conLen)); + /* in buffer */ + Md5Update(&md5, in, sz); + Md5Final(&md5, result); + /* outer */ + Md5Update(&md5, macSecret, digestSz); + Md5Update(&md5, PAD2, padSz); + Md5Update(&md5, result, digestSz); + Md5Final(&md5, digest); + } + else { + ret = InitSha(&sha); + if (ret != 0) + return ret; + /* inner */ + ShaUpdate(&sha, macSecret, digestSz); + ShaUpdate(&sha, PAD1, padSz); + ShaUpdate(&sha, seq, SEQ_SZ); + ShaUpdate(&sha, conLen, sizeof(conLen)); + /* in buffer */ + ShaUpdate(&sha, in, sz); + ShaFinal(&sha, result); + /* outer */ + ShaUpdate(&sha, macSecret, digestSz); + ShaUpdate(&sha, PAD2, padSz); + ShaUpdate(&sha, result, digestSz); + ShaFinal(&sha, digest); + } + return 0; +} + +#ifndef NO_CERTS +static void BuildMD5_CertVerify(CYASSL* ssl, byte* digest) +{ + byte md5_result[MD5_DIGEST_SIZE]; + + /* make md5 inner */ + Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD1, PAD_MD5); + Md5Final(&ssl->hashMd5, md5_result); + + /* make md5 outer */ + Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD2, PAD_MD5); + Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE); + + Md5Final(&ssl->hashMd5, digest); +} + + +static void BuildSHA_CertVerify(CYASSL* ssl, byte* digest) +{ + byte sha_result[SHA_DIGEST_SIZE]; + + /* make sha inner */ + ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA); + ShaFinal(&ssl->hashSha, sha_result); + + /* make sha outer */ + ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA); + ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE); + + ShaFinal(&ssl->hashSha, digest); +} +#endif /* NO_CERTS */ +#endif /* NO_OLD_TLS */ + + +#ifndef NO_CERTS + +static int BuildCertHashes(CYASSL* ssl, Hashes* hashes) +{ + /* store current states, building requires get_digest which resets state */ + #ifndef NO_OLD_TLS + Md5 md5 = ssl->hashMd5; + Sha sha = ssl->hashSha; + #endif + #ifndef NO_SHA256 + Sha256 sha256 = ssl->hashSha256; + #endif + #ifdef CYASSL_SHA384 + Sha384 sha384 = ssl->hashSha384; + #endif + + if (ssl->options.tls) { +#if ! defined( NO_OLD_TLS ) + Md5Final(&ssl->hashMd5, hashes->md5); + ShaFinal(&ssl->hashSha, hashes->sha); +#endif + if (IsAtLeastTLSv1_2(ssl)) { + int ret; + + #ifndef NO_SHA256 + ret = Sha256Final(&ssl->hashSha256, hashes->sha256); + if (ret != 0) + return ret; + #endif + #ifdef CYASSL_SHA384 + ret = Sha384Final(&ssl->hashSha384, hashes->sha384); + if (ret != 0) + return ret; + #endif + } + } +#if ! defined( NO_OLD_TLS ) + else { + BuildMD5_CertVerify(ssl, hashes->md5); + BuildSHA_CertVerify(ssl, hashes->sha); + } + + /* restore */ + ssl->hashMd5 = md5; + ssl->hashSha = sha; +#endif + if (IsAtLeastTLSv1_2(ssl)) { + #ifndef NO_SHA256 + ssl->hashSha256 = sha256; + #endif + #ifdef CYASSL_SHA384 + ssl->hashSha384 = sha384; + #endif + } + + return 0; +} + +#endif /* CYASSL_LEANPSK */ + +/* Build SSL Message, encrypted */ +static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz, + int type) +{ +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = min(ssl->specs.hash_size, + ssl->truncated_hmac ? TRUNCATED_HMAC_SZ : ssl->specs.hash_size); +#else + word32 digestSz = ssl->specs.hash_size; +#endif + word32 sz = RECORD_HEADER_SZ + inSz + digestSz; + word32 pad = 0, i; + word32 idx = RECORD_HEADER_SZ; + word32 ivSz = 0; /* TLSv1.1 IV */ + word32 headerSz = RECORD_HEADER_SZ; + word16 size; + byte iv[AES_BLOCK_SIZE]; /* max size */ + int ret = 0; + int atomicUser = 0; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sz += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + headerSz += DTLS_RECORD_EXTRA; + } +#endif + +#ifdef ATOMIC_USER + if (ssl->ctx->MacEncryptCb) + atomicUser = 1; +#endif + + if (ssl->specs.cipher_type == block) { + word32 blockSz = ssl->specs.block_size; + if (ssl->options.tls1_1) { + ivSz = blockSz; + sz += ivSz; + + ret = RNG_GenerateBlock(ssl->rng, iv, ivSz); + if (ret != 0) + return ret; + + } + sz += 1; /* pad byte */ + pad = (sz - headerSz) % blockSz; + pad = blockSz - pad; + sz += pad; + } + +#ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + ivSz = AEAD_EXP_IV_SZ; + sz += (ivSz + ssl->specs.aead_mac_size - digestSz); + XMEMCPY(iv, ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); + } +#endif + size = (word16)(sz - headerSz); /* include mac and digest */ + AddRecordHeader(output, size, (byte)type, ssl); + + /* write to output */ + if (ivSz) { + XMEMCPY(output + idx, iv, min(ivSz, sizeof(iv))); + idx += ivSz; + } + XMEMCPY(output + idx, input, inSz); + idx += inSz; + + if (type == handshake) { + ret = HashOutput(ssl, output, headerSz + inSz, ivSz); + if (ret != 0) + return ret; + } + + if (ssl->specs.cipher_type == block) { + word32 tmpIdx = idx + digestSz; + + for (i = 0; i <= pad; i++) + output[tmpIdx++] = (byte)pad; /* pad byte gets pad value too */ + } + + if (atomicUser) { /* User Record Layer Callback handling */ +#ifdef ATOMIC_USER + if ( (ret = ssl->ctx->MacEncryptCb(ssl, output + idx, + output + headerSz + ivSz, inSz, type, 0, + output + headerSz, output + headerSz, size, + ssl->MacEncryptCtx)) != 0) + return ret; +#endif + } + else { + if (ssl->specs.cipher_type != aead) { +#ifdef HAVE_TRUNCATED_HMAC + if (ssl->truncated_hmac && ssl->specs.hash_size > digestSz) { + byte hmac[MAX_DIGEST_SIZE]; + + ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz, + type, 0); + XMEMCPY(output + idx, hmac, digestSz); + } else +#endif + ret = ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, + type, 0); + } + if (ret != 0) + return ret; + + if ( (ret = Encrypt(ssl, output + headerSz, output+headerSz,size)) != 0) + return ret; + } + + return sz; +} + + +int SendFinished(CYASSL* ssl) +{ + int sendSz, + finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : + FINISHED_SZ; + byte input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ]; /* max */ + byte *output; + Hashes* hashes; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + + #ifdef CYASSL_DTLS + word32 sequence_number = ssl->keys.dtls_sequence_number; + word16 epoch = ssl->keys.dtls_epoch; + #endif + + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0) + return ret; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + /* Send Finished message with the next epoch, but don't commit that + * change until the other end confirms its reception. */ + headerSz += DTLS_HANDSHAKE_EXTRA; + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */ + } + #endif + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHandShakeHeader(input, finishedSz, finished, ssl); + + /* make finished hashes */ + hashes = (Hashes*)&input[headerSz]; + ret = BuildFinished(ssl, hashes, + ssl->options.side == CYASSL_CLIENT_END ? client : server); + if (ret != 0) return ret; + + sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake); + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + ssl->keys.dtls_epoch = epoch; + ssl->keys.dtls_sequence_number = sequence_number; + } + #endif + + if (sendSz < 0) + return BUILD_MSG_ERROR; + + if (!ssl->options.resuming) { +#ifndef NO_SESSION_CACHE + AddSession(ssl); /* just try */ +#endif + if (ssl->options.side == CYASSL_CLIENT_END) { + ret = BuildFinished(ssl, &ssl->verifyHashes, server); + if (ret != 0) return ret; + } + else { + ssl->options.handShakeState = HANDSHAKE_DONE; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + /* Other side will soon receive our Finished, go to next + * epoch. */ + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 1; + } + #endif + } + } + else { + if (ssl->options.side == CYASSL_CLIENT_END) { + ssl->options.handShakeState = HANDSHAKE_DONE; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + /* Other side will soon receive our Finished, go to next + * epoch. */ + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 1; + } + #endif + } + else { + ret = BuildFinished(ssl, &ssl->verifyHashes, client); + if (ret != 0) return ret; + } + } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); +} + +#ifndef NO_CERTS +int SendCertificate(CYASSL* ssl) +{ + int sendSz, length, ret = 0; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 certSz, listSz; + byte* output = 0; + + if (ssl->options.usingPSK_cipher) return 0; /* not needed */ + + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + certSz = 0; + length = CERT_HEADER_SZ; + listSz = 0; + } + else { + certSz = ssl->buffers.certificate.length; + /* list + cert size */ + length = certSz + 2 * CERT_HEADER_SZ; + listSz = certSz + CERT_HEADER_SZ; + + /* may need to send rest of chain, already has leading size(s) */ + if (ssl->buffers.certChain.buffer) { + length += ssl->buffers.certChain.length; + listSz += ssl->buffers.certChain.length; + } + } + sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, certificate, ssl); + + /* list total */ + c32to24(listSz, output + i); + i += CERT_HEADER_SZ; + + /* member */ + if (certSz) { + c32to24(certSz, output + i); + i += CERT_HEADER_SZ; + XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz); + i += certSz; + + /* send rest of chain? */ + if (ssl->buffers.certChain.buffer) { + XMEMCPY(output + i, ssl->buffers.certChain.buffer, + ssl->buffers.certChain.length); + /* if add more to output adjust i + i += ssl->buffers.certChain.length; */ + } + } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + if (ssl->options.side == CYASSL_SERVER_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); +} + + +int SendCertificateRequest(CYASSL* ssl) +{ + byte *output; + int ret; + int sendSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + int typeTotal = 1; /* only rsa for now */ + int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + + if (IsAtLeastTLSv1_2(ssl)) + reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; + + if (ssl->options.usingPSK_cipher) return 0; /* not needed */ + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, reqSz, certificate_request, ssl); + + /* write to output */ + output[i++] = (byte)typeTotal; /* # of types */ + output[i++] = rsa_sign; + + /* supported hash/sig */ + if (IsAtLeastTLSv1_2(ssl)) { + c16toa(ssl->suites->hashSigAlgoSz, &output[i]); + i += LENGTH_SZ; + + XMEMCPY(&output[i], + ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz); + i += ssl->suites->hashSigAlgoSz; + } + + c16toa(0, &output[i]); /* auth's */ + /* if add more to output, adjust i + i += REQ_HEADER_SZ; */ + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output, + sendSz, ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); +} +#endif /* !NO_CERTS */ + + +int SendData(CYASSL* ssl, const void* data, int sz) +{ + int sent = 0, /* plainText size */ + sendSz, + ret; + + if (ssl->error == WANT_WRITE) + ssl->error = 0; + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + CYASSL_MSG("handshake not complete, trying to finish"); + if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) + return err; + } + + /* last time system socket output buffer was full, try again to send */ + if (ssl->buffers.outputBuffer.length > 0) { + CYASSL_MSG("output buffer was full, trying to send again"); + if ( (ssl->error = SendBuffered(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset) + return 0; /* peer reset */ + return ssl->error; + } + else { + /* advance sent to previous sent + plain size just sent */ + sent = ssl->buffers.prevSent + ssl->buffers.plainSz; + CYASSL_MSG("sent write buffered data"); + } + } + + for (;;) { +#ifdef HAVE_MAX_FRAGMENT + int len = min(sz - sent, min(ssl->max_fragment, OUTPUT_RECORD_SIZE)); +#else + int len = min(sz - sent, OUTPUT_RECORD_SIZE); +#endif + byte* out; + byte* sendBuffer = (byte*)data + sent; /* may switch on comp */ + int buffSz = len; /* may switch on comp */ +#ifdef HAVE_LIBZ + byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + + if (sent == sz) break; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + len = min(len, MAX_UDP_SIZE); + buffSz = len; + } +#endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, len + COMP_EXTRA + + MAX_MSG_EXTRA)) != 0) + return ssl->error = ret; + + /* get ouput buffer */ + out = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + +#ifdef HAVE_LIBZ + if (ssl->options.usingCompression) { + buffSz = myCompress(ssl, sendBuffer, buffSz, comp, sizeof(comp)); + if (buffSz < 0) { + return buffSz; + } + sendBuffer = comp; + } +#endif + sendSz = BuildMessage(ssl, out, sendBuffer, buffSz, + application_data); + + ssl->buffers.outputBuffer.length += sendSz; + + if ( (ret = SendBuffered(ssl)) < 0) { + CYASSL_ERROR(ret); + /* store for next call if WANT_WRITE or user embedSend() that + doesn't present like WANT_WRITE */ + ssl->buffers.plainSz = len; + ssl->buffers.prevSent = sent; + if (ret == SOCKET_ERROR_E && ssl->options.connReset) + return 0; /* peer reset */ + return ssl->error = ret; + } + + sent += len; + + /* only one message per attempt */ + if (ssl->options.partialWrite == 1) { + CYASSL_MSG("Paritial Write on, only sending one record"); + break; + } + } + + return sent; +} + +/* process input data */ +int ReceiveData(CYASSL* ssl, byte* output, int sz, int peek) +{ + int size; + + CYASSL_ENTER("ReceiveData()"); + + if (ssl->error == WANT_READ) + ssl->error = 0; + + if (ssl->error != 0 && ssl->error != WANT_WRITE) { + CYASSL_MSG("User calling CyaSSL_read in error state, not allowed"); + return ssl->error; + } + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + CYASSL_MSG("Handshake not complete, trying to finish"); + if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) + return err; + } + + while (ssl->buffers.clearOutputBuffer.length == 0) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + if (ssl->error == ZERO_RETURN) { + CYASSL_MSG("Zero return, no more data coming"); + return 0; /* no more data coming */ + } + if (ssl->error == SOCKET_ERROR_E) { + if (ssl->options.connReset || ssl->options.isClosed) { + CYASSL_MSG("Peer reset or closed, connection done"); + return 0; /* peer reset or closed */ + } + } + return ssl->error; + } + + if (sz < (int)ssl->buffers.clearOutputBuffer.length) + size = sz; + else + size = ssl->buffers.clearOutputBuffer.length; + + XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size); + + if (peek == 0) { + ssl->buffers.clearOutputBuffer.length -= size; + ssl->buffers.clearOutputBuffer.buffer += size; + } + + if (ssl->buffers.clearOutputBuffer.length == 0 && + ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + + CYASSL_LEAVE("ReceiveData()", size); + return size; +} + + +/* send alert message */ +int SendAlert(CYASSL* ssl, int severity, int type) +{ + byte input[ALERT_SIZE]; + byte *output; + int sendSz; + int ret; + int dtlsExtra = 0; + + /* if sendalert is called again for nonbloking */ + if (ssl->options.sendAlertState != 0) { + ret = SendBuffered(ssl); + if (ret == 0) + ssl->options.sendAlertState = 0; + return ret; + } + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + dtlsExtra = DTLS_RECORD_EXTRA; + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, + ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + input[0] = (byte)severity; + input[1] = (byte)type; + ssl->alert_history.last_tx.code = type; + ssl->alert_history.last_tx.level = severity; + if (severity == alert_fatal) { + ssl->options.isClosed = 1; /* Don't send close_notify */ + } + + /* only send encrypted alert if handshake actually complete, otherwise + other side may not be able to handle it */ + if (ssl->keys.encryptionOn && ssl->options.handShakeState == HANDSHAKE_DONE) + sendSz = BuildMessage(ssl, output, input, ALERT_SIZE, alert); + else { + + AddRecordHeader(output, ALERT_SIZE, alert, ssl); + output += RECORD_HEADER_SZ; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + output += DTLS_RECORD_EXTRA; + #endif + XMEMCPY(output, input, ALERT_SIZE); + + sendSz = RECORD_HEADER_SZ + ALERT_SIZE; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA; + #endif + } + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("Alert", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + ssl->options.sendAlertState = 1; + + return SendBuffered(ssl); +} + + + +void SetErrorString(int error, char* str) +{ + const int max = CYASSL_MAX_ERROR_SZ; /* shorthand */ + +#ifdef NO_ERROR_STRINGS + + (void)error; + XSTRNCPY(str, "no support for error strings built in", max); + +#else + + /* pass to CTaoCrypt */ + if (error < MAX_CODE_E && error > MIN_CODE_E) { + CTaoCryptErrorString(error, str); + return; + } + + switch (error) { + + case UNSUPPORTED_SUITE : + XSTRNCPY(str, "unsupported cipher suite", max); + break; + + case INPUT_CASE_ERROR : + XSTRNCPY(str, "input state error", max); + break; + + case PREFIX_ERROR : + XSTRNCPY(str, "bad index to key rounds", max); + break; + + case MEMORY_ERROR : + XSTRNCPY(str, "out of memory", max); + break; + + case VERIFY_FINISHED_ERROR : + XSTRNCPY(str, "verify problem on finished", max); + break; + + case VERIFY_MAC_ERROR : + XSTRNCPY(str, "verify mac problem", max); + break; + + case PARSE_ERROR : + XSTRNCPY(str, "parse error on header", max); + break; + + case SIDE_ERROR : + XSTRNCPY(str, "wrong client/server type", max); + break; + + case NO_PEER_CERT : + XSTRNCPY(str, "peer didn't send cert", max); + break; + + case UNKNOWN_HANDSHAKE_TYPE : + XSTRNCPY(str, "weird handshake type", max); + break; + + case SOCKET_ERROR_E : + XSTRNCPY(str, "error state on socket", max); + break; + + case SOCKET_NODATA : + XSTRNCPY(str, "expected data, not there", max); + break; + + case INCOMPLETE_DATA : + XSTRNCPY(str, "don't have enough data to complete task", max); + break; + + case UNKNOWN_RECORD_TYPE : + XSTRNCPY(str, "unknown type in record hdr", max); + break; + + case DECRYPT_ERROR : + XSTRNCPY(str, "error during decryption", max); + break; + + case FATAL_ERROR : + XSTRNCPY(str, "revcd alert fatal error", max); + break; + + case ENCRYPT_ERROR : + XSTRNCPY(str, "error during encryption", max); + break; + + case FREAD_ERROR : + XSTRNCPY(str, "fread problem", max); + break; + + case NO_PEER_KEY : + XSTRNCPY(str, "need peer's key", max); + break; + + case NO_PRIVATE_KEY : + XSTRNCPY(str, "need the private key", max); + break; + + case NO_DH_PARAMS : + XSTRNCPY(str, "server missing DH params", max); + break; + + case RSA_PRIVATE_ERROR : + XSTRNCPY(str, "error during rsa priv op", max); + break; + + case MATCH_SUITE_ERROR : + XSTRNCPY(str, "can't match cipher suite", max); + break; + + case BUILD_MSG_ERROR : + XSTRNCPY(str, "build message failure", max); + break; + + case BAD_HELLO : + XSTRNCPY(str, "client hello malformed", max); + break; + + case DOMAIN_NAME_MISMATCH : + XSTRNCPY(str, "peer subject name mismatch", max); + break; + + case WANT_READ : + case SSL_ERROR_WANT_READ : + XSTRNCPY(str, "non-blocking socket wants data to be read", max); + break; + + case NOT_READY_ERROR : + XSTRNCPY(str, "handshake layer not ready yet, complete first", max); + break; + + case PMS_VERSION_ERROR : + XSTRNCPY(str, "premaster secret version mismatch error", max); + break; + + case VERSION_ERROR : + XSTRNCPY(str, "record layer version error", max); + break; + + case WANT_WRITE : + case SSL_ERROR_WANT_WRITE : + XSTRNCPY(str, "non-blocking socket write buffer full", max); + break; + + case BUFFER_ERROR : + XSTRNCPY(str, "malformed buffer input error", max); + break; + + case VERIFY_CERT_ERROR : + XSTRNCPY(str, "verify problem on certificate", max); + break; + + case VERIFY_SIGN_ERROR : + XSTRNCPY(str, "verify problem based on signature", max); + break; + + case CLIENT_ID_ERROR : + XSTRNCPY(str, "psk client identity error", max); + break; + + case SERVER_HINT_ERROR: + XSTRNCPY(str, "psk server hint error", max); + break; + + case PSK_KEY_ERROR: + XSTRNCPY(str, "psk key callback error", max); + break; + + case NTRU_KEY_ERROR: + XSTRNCPY(str, "NTRU key error", max); + break; + + case NTRU_DRBG_ERROR: + XSTRNCPY(str, "NTRU drbg error", max); + break; + + case NTRU_ENCRYPT_ERROR: + XSTRNCPY(str, "NTRU encrypt error", max); + break; + + case NTRU_DECRYPT_ERROR: + XSTRNCPY(str, "NTRU decrypt error", max); + break; + + case ZLIB_INIT_ERROR: + XSTRNCPY(str, "zlib init error", max); + break; + + case ZLIB_COMPRESS_ERROR: + XSTRNCPY(str, "zlib compress error", max); + break; + + case ZLIB_DECOMPRESS_ERROR: + XSTRNCPY(str, "zlib decompress error", max); + break; + + case GETTIME_ERROR: + XSTRNCPY(str, "gettimeofday() error", max); + break; + + case GETITIMER_ERROR: + XSTRNCPY(str, "getitimer() error", max); + break; + + case SIGACT_ERROR: + XSTRNCPY(str, "sigaction() error", max); + break; + + case SETITIMER_ERROR: + XSTRNCPY(str, "setitimer() error", max); + break; + + case LENGTH_ERROR: + XSTRNCPY(str, "record layer length error", max); + break; + + case PEER_KEY_ERROR: + XSTRNCPY(str, "cant decode peer key", max); + break; + + case ZERO_RETURN: + case SSL_ERROR_ZERO_RETURN: + XSTRNCPY(str, "peer sent close notify alert", max); + break; + + case ECC_CURVETYPE_ERROR: + XSTRNCPY(str, "Bad ECC Curve Type or unsupported", max); + break; + + case ECC_CURVE_ERROR: + XSTRNCPY(str, "Bad ECC Curve or unsupported", max); + break; + + case ECC_PEERKEY_ERROR: + XSTRNCPY(str, "Bad ECC Peer Key", max); + break; + + case ECC_MAKEKEY_ERROR: + XSTRNCPY(str, "ECC Make Key failure", max); + break; + + case ECC_EXPORT_ERROR: + XSTRNCPY(str, "ECC Export Key failure", max); + break; + + case ECC_SHARED_ERROR: + XSTRNCPY(str, "ECC DHE shared failure", max); + break; + + case NOT_CA_ERROR: + XSTRNCPY(str, "Not a CA by basic constraint error", max); + break; + + case BAD_PATH_ERROR: + XSTRNCPY(str, "Bad path for opendir error", max); + break; + + case BAD_CERT_MANAGER_ERROR: + XSTRNCPY(str, "Bad Cert Manager error", max); + break; + + case OCSP_CERT_REVOKED: + XSTRNCPY(str, "OCSP Cert revoked", max); + break; + + case CRL_CERT_REVOKED: + XSTRNCPY(str, "CRL Cert revoked", max); + break; + + case CRL_MISSING: + XSTRNCPY(str, "CRL missing, not loaded", max); + break; + + case MONITOR_RUNNING_E: + XSTRNCPY(str, "CRL monitor already running", max); + break; + + case THREAD_CREATE_E: + XSTRNCPY(str, "Thread creation problem", max); + break; + + case OCSP_NEED_URL: + XSTRNCPY(str, "OCSP need URL", max); + break; + + case OCSP_CERT_UNKNOWN: + XSTRNCPY(str, "OCSP Cert unknown", max); + break; + + case OCSP_LOOKUP_FAIL: + XSTRNCPY(str, "OCSP Responder lookup fail", max); + break; + + case MAX_CHAIN_ERROR: + XSTRNCPY(str, "Maximum Chain Depth Exceeded", max); + break; + + case COOKIE_ERROR: + XSTRNCPY(str, "DTLS Cookie Error", max); + break; + + case SEQUENCE_ERROR: + XSTRNCPY(str, "DTLS Sequence Error", max); + break; + + case SUITES_ERROR: + XSTRNCPY(str, "Suites Pointer Error", max); + break; + + case SSL_NO_PEM_HEADER: + XSTRNCPY(str, "No PEM Header Error", max); + break; + + case OUT_OF_ORDER_E: + XSTRNCPY(str, "Out of order message, fatal", max); + break; + + case BAD_KEA_TYPE_E: + XSTRNCPY(str, "Bad KEA type found", max); + break; + + case SANITY_CIPHER_E: + XSTRNCPY(str, "Sanity check on ciphertext failed", max); + break; + + case RECV_OVERFLOW_E: + XSTRNCPY(str, "Receive callback returned more than requested", max); + break; + + case GEN_COOKIE_E: + XSTRNCPY(str, "Generate Cookie Error", max); + break; + + case NO_PEER_VERIFY: + XSTRNCPY(str, "Need peer certificate verify Error", max); + break; + + case FWRITE_ERROR: + XSTRNCPY(str, "fwrite Error", max); + break; + + case CACHE_MATCH_ERROR: + XSTRNCPY(str, "Cache restore header match Error", max); + break; + + case UNKNOWN_SNI_HOST_NAME_E: + XSTRNCPY(str, "Unrecognized host name Error", max); + break; + + case KEYUSE_SIGNATURE_E: + XSTRNCPY(str, "Key Use digitalSignature not set Error", max); + break; + + case KEYUSE_ENCIPHER_E: + XSTRNCPY(str, "Key Use keyEncipherment not set Error", max); + break; + + case EXTKEYUSE_AUTH_E: + XSTRNCPY(str, "Ext Key Use server/client auth not set Error", max); + break; + + default : + XSTRNCPY(str, "unknown error number", max); + } + +#endif /* NO_ERROR_STRINGS */ +} + + + +/* be sure to add to cipher_name_idx too !!!! */ +static const char* const cipher_names[] = +{ +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + "RC4-SHA", +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + "RC4-MD5", +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + "DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + "AES128-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + "AES256-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + "NULL-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 + "NULL-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + "DHE-RSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + "DHE-RSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 + "PSK-AES128-CBC-SHA256", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + "PSK-AES128-CBC-SHA", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + "PSK-AES256-CBC-SHA", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + "PSK-AES128-CCM-8", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + "PSK-AES256-CCM-8", +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 + "PSK-NULL-SHA256", +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + "PSK-NULL-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + "HC128-MD5", +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + "HC128-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 + "HC128-B2B256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 + "AES128-B2B256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 + "AES256-B2B256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + "RABBIT-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + "NTRU-RC4-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + "NTRU-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + "NTRU-AES128-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + "NTRU-AES256-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + "AES128-CCM-8", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + "AES256-CCM-8", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + "ECDHE-ECDSA-AES128-CCM-8", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + "ECDHE-ECDSA-AES256-CCM-8", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + "ECDHE-RSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + "ECDHE-RSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + "ECDHE-ECDSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + "ECDHE-ECDSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + "ECDHE-RSA-RC4-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + "ECDHE-RSA-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + "ECDHE-ECDSA-RC4-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + "ECDHE-ECDSA-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 + "AES128-SHA256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 + "AES256-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + "DHE-RSA-AES128-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + "DHE-RSA-AES256-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + "ECDH-RSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + "ECDH-RSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + "ECDH-ECDSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + "ECDH-ECDSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + "ECDH-RSA-RC4-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + "ECDH-RSA-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + "ECDH-ECDSA-RC4-SHA", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + "ECDH-ECDSA-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + "AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + "AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + "DHE-RSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + "DHE-RSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + "ECDHE-RSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + "ECDHE-RSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + "ECDHE-ECDSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + "ECDHE-ECDSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + "ECDH-RSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + "ECDH-RSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + "ECDH-ECDSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + "ECDH-ECDSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + "CAMELLIA128-SHA", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + "DHE-RSA-CAMELLIA128-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + "CAMELLIA256-SHA", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + "DHE-RSA-CAMELLIA256-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + "CAMELLIA128-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + "DHE-RSA-CAMELLIA128-SHA256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + "CAMELLIA256-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + "DHE-RSA-CAMELLIA256-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + "ECDHE-RSA-AES128-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + "ECDHE-ECDSA-AES128-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + "ECDH-RSA-AES128-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + "ECDH-ECDSA-AES128-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + "ECDHE-RSA-AES256-SHA384", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + "ECDHE-ECDSA-AES256-SHA384", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + "ECDH-RSA-AES256-SHA384", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + "ECDH-ECDSA-AES256-SHA384", +#endif + +}; + + + +/* cipher suite number that matches above name table */ +static int cipher_name_idx[] = +{ + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + SSL_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + SSL_RSA_WITH_RC4_128_MD5, +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + SSL_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + TLS_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + TLS_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + TLS_RSA_WITH_NULL_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 + TLS_RSA_WITH_NULL_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 + TLS_PSK_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + TLS_PSK_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + TLS_PSK_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + TLS_PSK_WITH_AES_128_CCM_8, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + TLS_PSK_WITH_AES_256_CCM_8, +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 + TLS_PSK_WITH_NULL_SHA256, +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + TLS_PSK_WITH_NULL_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + TLS_RSA_WITH_HC_128_MD5, +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + TLS_RSA_WITH_HC_128_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 + TLS_RSA_WITH_HC_128_B2B256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 + TLS_RSA_WITH_AES_128_CBC_B2B256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 + TLS_RSA_WITH_AES_256_CBC_B2B256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + TLS_RSA_WITH_RABBIT_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + TLS_NTRU_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + TLS_NTRU_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + TLS_NTRU_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + TLS_RSA_WITH_AES_128_CCM_8, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + TLS_RSA_WITH_AES_256_CCM_8, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + TLS_ECDHE_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 + TLS_RSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 + TLS_RSA_WITH_AES_256_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + TLS_ECDH_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + TLS_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + TLS_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 +#endif +}; + + +/* return true if set, else false */ +/* only supports full name from cipher_name[] delimited by : */ +int SetCipherList(Suites* s, const char* list) +{ + int ret = 0, i; + char name[MAX_SUITE_NAME]; + + char needle[] = ":"; + char* haystack = (char*)list; + char* prev; + + const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); + int idx = 0; + int haveRSA = 0, haveECDSA = 0; + + if (s == NULL) { + CYASSL_MSG("SetCipherList suite pointer error"); + return 0; + } + + if (!list) + return 0; + + if (*list == 0) return 1; /* CyaSSL default */ + + if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1; /* CyaSSL defualt */ + + for(;;) { + word32 len; + prev = haystack; + haystack = XSTRSTR(haystack, needle); + + if (!haystack) /* last cipher */ + len = min(sizeof(name), (word32)XSTRLEN(prev)); + else + len = min(sizeof(name), (word32)(haystack - prev)); + + XSTRNCPY(name, prev, len); + name[(len == sizeof(name)) ? len - 1 : len] = 0; + + for (i = 0; i < suiteSz; i++) + if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { + if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM")) + s->suites[idx++] = ECC_BYTE; /* ECC suite */ + else + s->suites[idx++] = 0x00; /* normal */ + s->suites[idx++] = (byte)cipher_name_idx[i]; + + /* The suites are either ECDSA, RSA, or PSK. The RSA suites + * don't necessarily have RSA in the name. */ + if ((haveECDSA == 0) && XSTRSTR(name, "ECDSA")) { + haveECDSA = 1; + } + else if ((haveRSA == 0) && (XSTRSTR(name, "PSK") == NULL)) { + haveRSA = 1; + } + + if (!ret) ret = 1; /* found at least one */ + break; + } + if (!haystack) break; + haystack++; + } + + if (ret) { + s->setSuites = 1; + s->suiteSz = (word16)idx; + + idx = 0; + + if (haveECDSA) { + #ifdef CYASSL_SHA384 + s->hashSigAlgo[idx++] = sha384_mac; + s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + #ifndef NO_SHA256 + s->hashSigAlgo[idx++] = sha256_mac; + s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + #endif + s->hashSigAlgo[idx++] = sha_mac; + s->hashSigAlgo[idx++] = ecc_dsa_sa_algo; + } + + if (haveRSA) { + #ifdef CYASSL_SHA384 + s->hashSigAlgo[idx++] = sha384_mac; + s->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + #ifndef NO_SHA256 + s->hashSigAlgo[idx++] = sha256_mac; + s->hashSigAlgo[idx++] = rsa_sa_algo; + #endif + s->hashSigAlgo[idx++] = sha_mac; + s->hashSigAlgo[idx++] = rsa_sa_algo; + } + + s->hashSigAlgoSz = (word16)idx; + } + + return ret; +} + + +static void PickHashSigAlgo(CYASSL* ssl, + const byte* hashSigAlgo, word32 hashSigAlgoSz) +{ + word32 i; + + ssl->suites->sigAlgo = ssl->specs.sig_algo; + ssl->suites->hashAlgo = sha_mac; + + for (i = 0; i < hashSigAlgoSz; i += 2) { + if (hashSigAlgo[i+1] == ssl->specs.sig_algo) { + if (hashSigAlgo[i] == sha_mac) { + break; + } + #ifndef NO_SHA256 + else if (hashSigAlgo[i] == sha256_mac) { + ssl->suites->hashAlgo = sha256_mac; + break; + } + #endif + #ifdef CYASSL_SHA384 + else if (hashSigAlgo[i] == sha384_mac) { + ssl->suites->hashAlgo = sha384_mac; + break; + } + #endif + } + } +} + + +#ifdef CYASSL_CALLBACKS + + /* Initialisze HandShakeInfo */ + void InitHandShakeInfo(HandShakeInfo* info) + { + int i; + + info->cipherName[0] = 0; + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) + info->packetNames[i][0] = 0; + info->numberPackets = 0; + info->negotiationError = 0; + } + + /* Set Final HandShakeInfo parameters */ + void FinishHandShakeInfo(HandShakeInfo* info, const CYASSL* ssl) + { + int i; + int sz = sizeof(cipher_name_idx)/sizeof(int); + + for (i = 0; i < sz; i++) + if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) { + if (ssl->options.cipherSuite0 == ECC_BYTE) + continue; /* ECC suites at end */ + XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ); + break; + } + + /* error max and min are negative numbers */ + if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR) + info->negotiationError = ssl->error; + } + + + /* Add name to info packet names, increase packet name count */ + void AddPacketName(const char* name, HandShakeInfo* info) + { + if (info->numberPackets < MAX_PACKETS_HANDSHAKE) { + XSTRNCPY(info->packetNames[info->numberPackets++], name, + MAX_PACKETNAME_SZ); + } + } + + + /* Initialisze TimeoutInfo */ + void InitTimeoutInfo(TimeoutInfo* info) + { + int i; + + info->timeoutName[0] = 0; + info->flags = 0; + + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) { + info->packets[i].packetName[0] = 0; + info->packets[i].timestamp.tv_sec = 0; + info->packets[i].timestamp.tv_usec = 0; + info->packets[i].bufferValue = 0; + info->packets[i].valueSz = 0; + } + info->numberPackets = 0; + info->timeoutValue.tv_sec = 0; + info->timeoutValue.tv_usec = 0; + } + + + /* Free TimeoutInfo */ + void FreeTimeoutInfo(TimeoutInfo* info, void* heap) + { + int i; + (void)heap; + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) + if (info->packets[i].bufferValue) { + XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO); + info->packets[i].bufferValue = 0; + } + + } + + + /* Add PacketInfo to TimeoutInfo */ + void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data, + int sz, void* heap) + { + if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) { + Timeval currTime; + + /* may add name after */ + if (name) + XSTRNCPY(info->packets[info->numberPackets].packetName, name, + MAX_PACKETNAME_SZ); + + /* add data, put in buffer if bigger than static buffer */ + info->packets[info->numberPackets].valueSz = sz; + if (sz < MAX_VALUE_SZ) + XMEMCPY(info->packets[info->numberPackets].value, data, sz); + else { + info->packets[info->numberPackets].bufferValue = + XMALLOC(sz, heap, DYNAMIC_TYPE_INFO); + if (!info->packets[info->numberPackets].bufferValue) + /* let next alloc catch, just don't fill, not fatal here */ + info->packets[info->numberPackets].valueSz = 0; + else + XMEMCPY(info->packets[info->numberPackets].bufferValue, + data, sz); + } + gettimeofday(&currTime, 0); + info->packets[info->numberPackets].timestamp.tv_sec = + currTime.tv_sec; + info->packets[info->numberPackets].timestamp.tv_usec = + currTime.tv_usec; + info->numberPackets++; + } + } + + + /* Add packet name to previsouly added packet info */ + void AddLateName(const char* name, TimeoutInfo* info) + { + /* make sure we have a valid previous one */ + if (info->numberPackets > 0 && info->numberPackets < + MAX_PACKETS_HANDSHAKE) { + XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name, + MAX_PACKETNAME_SZ); + } + } + + /* Add record header to previsouly added packet info */ + void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info) + { + /* make sure we have a valid previous one */ + if (info->numberPackets > 0 && info->numberPackets < + MAX_PACKETS_HANDSHAKE) { + if (info->packets[info->numberPackets - 1].bufferValue) + XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl, + RECORD_HEADER_SZ); + else + XMEMCPY(info->packets[info->numberPackets - 1].value, rl, + RECORD_HEADER_SZ); + } + } + +#endif /* CYASSL_CALLBACKS */ + + + +/* client only parts */ +#ifndef NO_CYASSL_CLIENT + + int SendClientHello(CYASSL* ssl) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int idSz = ssl->options.resuming ? ID_LEN : 0; + int ret; + + if (ssl->suites == NULL) { + CYASSL_MSG("Bad suites pointer in SendClientHello"); + return SUITES_ERROR; + } + + length = VERSION_SZ + RAN_LEN + + idSz + ENUM_LEN + + ssl->suites->suiteSz + SUITE_LEN + + COMP_LEN + ENUM_LEN; + +#ifdef HAVE_TLS_EXTENSIONS + length += TLSX_GetRequestSize(ssl); +#else + if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { + length += ssl->suites->hashSigAlgoSz + HELLO_EXT_SZ; + } +#endif + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + length += ENUM_LEN; /* cookie */ + if (ssl->arrays->cookieSz != 0) length += ssl->arrays->cookieSz; + sendSz = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ; + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + } +#endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, client_hello, ssl); + + /* client hello, first version */ + output[idx++] = ssl->version.major; + output[idx++] = ssl->version.minor; + ssl->chVersion = ssl->version; /* store in case changed */ + + /* then random */ + if (ssl->options.connectState == CONNECT_BEGIN) { + ret = RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + if (ret != 0) + return ret; + + /* store random */ + XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN); + } else { +#ifdef CYASSL_DTLS + /* send same random on hello again */ + XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); +#endif + } + idx += RAN_LEN; + + /* then session id */ + output[idx++] = (byte)idSz; + if (idSz) { + XMEMCPY(output + idx, ssl->session.sessionID, ID_LEN); + idx += ID_LEN; + } + + /* then DTLS cookie */ +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + byte cookieSz = ssl->arrays->cookieSz; + + output[idx++] = cookieSz; + if (cookieSz) { + XMEMCPY(&output[idx], ssl->arrays->cookie, cookieSz); + idx += cookieSz; + } + } +#endif + /* then cipher suites */ + c16toa(ssl->suites->suiteSz, output + idx); + idx += 2; + XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); + idx += ssl->suites->suiteSz; + + /* last, compression */ + output[idx++] = COMP_LEN; + if (ssl->options.usingCompression) + output[idx++] = ZLIB_COMPRESSION; + else + output[idx++] = NO_COMPRESSION; + +#ifdef HAVE_TLS_EXTENSIONS + idx += TLSX_WriteRequest(ssl, output + idx); + + (void)idx; /* suppress analyzer warning, keep idx current */ +#else + if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) + { + int i; + /* add in the extensions length */ + c16toa(HELLO_EXT_LEN + ssl->suites->hashSigAlgoSz, output + idx); + idx += 2; + + c16toa(HELLO_EXT_SIG_ALGO, output + idx); + idx += 2; + c16toa(HELLO_EXT_SIGALGO_SZ+ssl->suites->hashSigAlgoSz, output+idx); + idx += 2; + c16toa(ssl->suites->hashSigAlgoSz, output + idx); + idx += 2; + for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, idx++) { + output[idx] = ssl->suites->hashSigAlgo[i]; + } + } +#endif + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz, + ssl->heap); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } + + + static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, + word32* inOutIdx, word32 size) + { + ProtocolVersion pv; + byte cookieSz; + word32 begin = *inOutIdx; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest", + &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); +#endif + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolReset(ssl); + } +#endif + + if ((*inOutIdx - begin) + OPAQUE16_LEN + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + XMEMCPY(&pv, input + *inOutIdx, OPAQUE16_LEN); + *inOutIdx += OPAQUE16_LEN; + + cookieSz = input[(*inOutIdx)++]; + + if (cookieSz) { + if ((*inOutIdx - begin) + cookieSz > size) + return BUFFER_ERROR; + +#ifdef CYASSL_DTLS + if (cookieSz <= MAX_COOKIE_LEN) { + XMEMCPY(ssl->arrays->cookie, input + *inOutIdx, cookieSz); + ssl->arrays->cookieSz = cookieSz; + } +#endif + *inOutIdx += cookieSz; + } + + ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + return 0; + } + + + static int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte b; + ProtocolVersion pv; + byte compression; + word32 i = *inOutIdx; + word32 begin = i; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + + if (pv.minor > ssl->version.minor) { + CYASSL_MSG("Server using higher version, fatal error"); + return VERSION_ERROR; + } + else if (pv.minor < ssl->version.minor) { + CYASSL_MSG("server using lower version"); + + if (!ssl->options.downgrade) { + CYASSL_MSG(" no downgrade allowed, fatal error"); + return VERSION_ERROR; + } + + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + CYASSL_MSG(" downgrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + /* turn off tls 1.1+ */ + CYASSL_MSG(" downgrading to TLSv1"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + CYASSL_MSG(" downgrading to TLSv1.1"); + ssl->version.minor = TLSv1_1_MINOR; + } + } + + /* random */ + XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); + i += RAN_LEN; + + /* session id */ + b = input[i++]; + + if (b == ID_LEN) { + if ((i - begin) + ID_LEN > helloSz) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN)); + i += ID_LEN; + ssl->options.haveSessionId = 1; + } + else if (b) { + CYASSL_MSG("Invalid session ID size"); + return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } + + /* suite and compression */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + compression = input[i++]; + + if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) { + CYASSL_MSG("Server refused compression, turning off"); + ssl->options.usingCompression = 0; /* turn off if server refused */ + } + + *inOutIdx = i; + + /* tls extensions */ + if ( (i - begin) < helloSz) { +#ifdef HAVE_TLS_EXTENSIONS + if (IsTLS(ssl)) { + int ret = 0; + word16 totalExtSz; + Suites clSuites; /* just for compatibility right now */ + + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + if ((ret = TLSX_Parse(ssl, (byte *) input + i, + totalExtSz, 0, &clSuites))) + return ret; + + i += totalExtSz; + *inOutIdx = i; + } + else +#endif + *inOutIdx = begin + helloSz; /* skip extensions */ + } + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + if (ssl->options.resuming) { + if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, + ssl->session.sessionID, ID_LEN) == 0) { + if (SetCipherSpecs(ssl) == 0) { + int ret = -1; + + XMEMCPY(ssl->arrays->masterSecret, + ssl->session.masterSecret, SECRET_LEN); + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + + return ret; + } + else { + CYASSL_MSG("Unsupported cipher suite, DoServerHello"); + return UNSUPPORTED_SUITE; + } + } + else { + CYASSL_MSG("Server denied resumption attempt"); + ssl->options.resuming = 0; /* server denied resumption try */ + } + } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolReset(ssl); + } + #endif + + return SetCipherSpecs(ssl); + } + + +#ifndef NO_CERTS + /* just read in and ignore for now TODO: */ + static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32* + inOutIdx, word32 size) + { + word16 len; + word32 begin = *inOutIdx; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("CertificateRequest", &ssl->timeoutInfo); + #endif + + if ((*inOutIdx - begin) + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + len = input[(*inOutIdx)++]; + + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + /* types, read in here */ + *inOutIdx += len; + + /* signature and hash signature algorithm */ + if (IsAtLeastTLSv1_2(ssl)) { + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + PickHashSigAlgo(ssl, input + *inOutIdx, len); + *inOutIdx += len; + } + + /* authorities */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + while (len) { + word16 dnSz; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &dnSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + dnSz > size) + return BUFFER_ERROR; + + *inOutIdx += dnSz; + len -= OPAQUE16_LEN + dnSz; + } + + /* don't send client cert or cert verify if user hasn't provided + cert and private key */ + if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer) + ssl->options.sendVerify = SEND_CERT; + else if (IsTLS(ssl)) + ssl->options.sendVerify = SEND_BLANK_CERT; + + return 0; + } +#endif /* !NO_CERTS */ + + + static int DoServerKeyExchange(CYASSL* ssl, const byte* input, + word32* inOutIdx, word32 size) + { + word16 length = 0; + word32 begin = *inOutIdx; + int ret = 0; + + (void)length; /* shut up compiler warnings */ + (void)begin; + (void)ssl; + (void)input; + (void)size; + (void)ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ServerKeyExchange", &ssl->timeoutInfo); + #endif + + #ifndef NO_PSK + if (ssl->specs.kea == psk_kea) { + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx, + min(length, MAX_PSK_ID_LEN)); + + ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0; + *inOutIdx += length; + + return 0; + } + #endif + #ifdef OPENSSL_EXTRA + if (ssl->specs.kea == diffie_hellman_kea) + { + /* p */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_DH); + + if (ssl->buffers.serverDH_P.buffer) + ssl->buffers.serverDH_P.length = length; + else + return MEMORY_ERROR; + + XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length); + *inOutIdx += length; + + /* g */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_DH); + + if (ssl->buffers.serverDH_G.buffer) + ssl->buffers.serverDH_G.length = length; + else + return MEMORY_ERROR; + + XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length); + *inOutIdx += length; + + /* pub */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_DH); + + if (ssl->buffers.serverDH_Pub.buffer) + ssl->buffers.serverDH_Pub.length = length; + else + return MEMORY_ERROR; + + XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length); + *inOutIdx += length; + } /* dh_kea */ + #endif /* OPENSSL_EXTRA */ + + #ifdef HAVE_ECC + if (ssl->specs.kea == ecc_diffie_hellman_kea) + { + byte b; + + if ((*inOutIdx - begin) + ENUM_LEN + OPAQUE16_LEN + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + b = input[(*inOutIdx)++]; + + if (b != named_curve) + return ECC_CURVETYPE_ERROR; + + *inOutIdx += 1; /* curve type, eat leading 0 */ + b = input[(*inOutIdx)++]; + + if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b != + secp160r1 && b != secp192r1 && b != secp224r1) + return ECC_CURVE_ERROR; + + length = input[(*inOutIdx)++]; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0) + return ECC_PEERKEY_ERROR; + + *inOutIdx += length; + ssl->peerEccKeyPresent = 1; + } + #endif /* HAVE_ECC */ + + #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) + { +#ifndef NO_OLD_TLS + Md5 md5; + Sha sha; +#endif +#ifndef NO_SHA256 + Sha256 sha256; + byte hash256[SHA256_DIGEST_SIZE]; +#endif +#ifdef CYASSL_SHA384 + Sha384 sha384; + byte hash384[SHA384_DIGEST_SIZE]; +#endif + byte hash[FINISHED_SZ]; + byte messageVerify[MAX_DH_SZ]; + byte hashAlgo = sha_mac; + byte sigAlgo = ssl->specs.sig_algo; + word16 verifySz = (word16) (*inOutIdx - begin); + + /* save message for hash verify */ + if (verifySz > sizeof(messageVerify)) + return BUFFER_ERROR; + + XMEMCPY(messageVerify, input + begin, verifySz); + + if (IsAtLeastTLSv1_2(ssl)) { + if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size) + return BUFFER_ERROR; + + hashAlgo = input[(*inOutIdx)++]; + sigAlgo = input[(*inOutIdx)++]; + } + + /* signature */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &length); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + /* inOutIdx updated at the end of the function */ + + /* verify signature */ +#ifndef NO_OLD_TLS + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); + Md5Update(&md5, messageVerify, verifySz); + Md5Final(&md5, hash); + + /* sha */ + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); + ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); + ShaUpdate(&sha, messageVerify, verifySz); + ShaFinal(&sha, hash + MD5_DIGEST_SIZE); +#endif + +#ifndef NO_SHA256 + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, messageVerify, verifySz); + if (ret != 0) + return ret; + ret = Sha256Final(&sha256, hash256); + if (ret != 0) + return ret; +#endif + +#ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, messageVerify, verifySz); + if (ret != 0) + return ret; + ret = Sha384Final(&sha384, hash384); + if (ret != 0) + return ret; +#endif + +#ifndef NO_RSA + /* rsa */ + if (sigAlgo == rsa_sa_algo) + { + byte* out = NULL; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaVerifyCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + if (!ssl->peerRsaKeyPresent) + return NO_PEER_KEY; + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + ret = ssl->ctx->RsaVerifyCb(ssl, (byte *) input + *inOutIdx, + length, &out, + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaVerifyCtx); + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaSSL_VerifyInline((byte *) input + *inOutIdx, length, + &out, ssl->peerRsaKey); + } + + if (IsAtLeastTLSv1_2(ssl)) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 encSigSz; +#ifndef NO_OLD_TLS + byte* digest = &hash[MD5_DIGEST_SIZE]; + int typeH = SHAh; + int digestSz = SHA_DIGEST_SIZE; +#else + byte* digest = hash256; + int typeH = SHA256h; + int digestSz = SHA256_DIGEST_SIZE; +#endif + + if (hashAlgo == sha_mac) { + #ifndef NO_SHA + digest = &hash[MD5_DIGEST_SIZE]; + typeH = SHAh; + digestSz = SHA_DIGEST_SIZE; + #endif + } + else if (hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = hash256; + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = hash384; + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + + encSigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); + + if (encSigSz != (word32)ret || !out || XMEMCMP(out, encodedSig, + min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) + return VERIFY_SIGN_ERROR; + } + else { + if (ret != sizeof(hash) || !out || XMEMCMP(out, + hash, sizeof(hash)) != 0) + return VERIFY_SIGN_ERROR; + } + } else +#endif +#ifdef HAVE_ECC + /* ecdsa */ + if (sigAlgo == ecc_dsa_sa_algo) { + int verify = 0; +#ifndef NO_OLD_TLS + byte* digest = &hash[MD5_DIGEST_SIZE]; + word32 digestSz = SHA_DIGEST_SIZE; +#else + byte* digest = hash256; + word32 digestSz = SHA256_DIGEST_SIZE; +#endif + byte doUserEcc = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccVerifyCb) + doUserEcc = 1; + #endif + + if (!ssl->peerEccDsaKeyPresent) + return NO_PEER_KEY; + + if (IsAtLeastTLSv1_2(ssl)) { + if (hashAlgo == sha_mac) { + #ifndef NO_SHA + digest = &hash[MD5_DIGEST_SIZE]; + digestSz = SHA_DIGEST_SIZE; + #endif + } + else if (hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = hash256; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = hash384; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + } + if (doUserEcc) { + #ifdef HAVE_PK_CALLBACKS + ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length, + digest, digestSz, + ssl->buffers.peerEccDsaKey.buffer, + ssl->buffers.peerEccDsaKey.length, + &verify, ssl->EccVerifyCtx); + #endif + } + else { + ret = ecc_verify_hash(input + *inOutIdx, length, + digest, digestSz, &verify, ssl->peerEccDsaKey); + } + if (ret != 0 || verify == 0) + return VERIFY_SIGN_ERROR; + } + else +#endif /* HAVE_ECC */ + return ALGO_ID_E; + + /* signature length */ + *inOutIdx += length; + + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + + return 0; + } +#else /* HAVE_OPENSSL or HAVE_ECC */ + return NOT_COMPILED_IN; /* not supported by build */ +#endif /* HAVE_OPENSSL or HAVE_ECC */ + } + + + int SendClientKeyExchange(CYASSL* ssl) + { + byte encSecret[MAX_ENCRYPT_SZ]; + word32 encSz = 0; + word32 idx = 0; + int ret = 0; + byte doUserRsa = 0; + + (void)doUserRsa; + + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + if (ssl->ctx->RsaEncCb) + doUserRsa = 1; + #endif /* NO_RSA */ + #endif /*HAVE_PK_CALLBACKS */ + + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, + SECRET_LEN); + if (ret != 0) + return ret; + + ssl->arrays->preMasterSecret[0] = ssl->chVersion.major; + ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor; + ssl->arrays->preMasterSz = SECRET_LEN; + + if (ssl->peerRsaKeyPresent == 0) + return NO_PEER_KEY; + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + encSz = sizeof(encSecret); + ret = ssl->ctx->RsaEncCb(ssl, + ssl->arrays->preMasterSecret, + SECRET_LEN, + encSecret, &encSz, + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaEncCtx); + #endif /* NO_RSA */ + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaPublicEncrypt(ssl->arrays->preMasterSecret, + SECRET_LEN, encSecret, sizeof(encSecret), + ssl->peerRsaKey, ssl->rng); + if (ret > 0) { + encSz = ret; + ret = 0; /* set success to 0 */ + } + } + break; + #endif + #ifdef OPENSSL_EXTRA + case diffie_hellman_kea: + { + buffer serverP = ssl->buffers.serverDH_P; + buffer serverG = ssl->buffers.serverDH_G; + buffer serverPub = ssl->buffers.serverDH_Pub; + byte priv[ENCRYPT_LEN]; + word32 privSz = 0; + DhKey key; + + if (serverP.buffer == 0 || serverG.buffer == 0 || + serverPub.buffer == 0) + return NO_PEER_KEY; + + InitDhKey(&key); + ret = DhSetKey(&key, serverP.buffer, serverP.length, + serverG.buffer, serverG.length); + if (ret == 0) + /* for DH, encSecret is Yc, agree is pre-master */ + ret = DhGenerateKeyPair(&key, ssl->rng, priv, &privSz, + encSecret, &encSz); + if (ret == 0) + ret = DhAgree(&key, ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, priv, privSz, + serverPub.buffer, serverPub.length); + FreeDhKey(&key); + } + break; + #endif /* OPENSSL_EXTRA */ + #ifndef NO_PSK + case psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays->server_hint, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) + return PSK_KEY_ERROR; + encSz = (word32)XSTRLEN(ssl->arrays->client_identity); + if (encSz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR; + XMEMCPY(encSecret, ssl->arrays->client_identity, encSz); + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16)ssl->arrays->psk_keySz, pms); + pms += 2; + XMEMSET(pms, 0, ssl->arrays->psk_keySz); + pms += ssl->arrays->psk_keySz; + c16toa((word16)ssl->arrays->psk_keySz, pms); + pms += 2; + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; + XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); + ssl->arrays->psk_keySz = 0; /* No further need */ + } + break; + #endif /* NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + word32 rc; + word16 cipherLen = sizeof(encSecret); + DRBG_HANDLE drbg; + static uint8_t const cyasslStr[] = { + 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' + }; + + ret = RNG_GenerateBlock(ssl->rng, + ssl->arrays->preMasterSecret, SECRET_LEN); + if (ret != 0) + return ret; + + ssl->arrays->preMasterSz = SECRET_LEN; + + if (ssl->peerNtruKeyPresent == 0) + return NO_PEER_KEY; + + rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr, + sizeof(cyasslStr), GetEntropy, + &drbg); + if (rc != DRBG_OK) + return NTRU_DRBG_ERROR; + + rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen, + ssl->peerNtruKey, + ssl->arrays->preMasterSz, + ssl->arrays->preMasterSecret, + &cipherLen, encSecret); + crypto_drbg_uninstantiate(drbg); + if (rc != NTRU_OK) + return NTRU_ENCRYPT_ERROR; + + encSz = cipherLen; + ret = 0; + } + break; + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + ecc_key myKey; + ecc_key* peerKey = NULL; + word32 size = sizeof(encSecret); + + if (ssl->specs.static_ecdh) { + /* TODO: EccDsa is really fixed Ecc change naming */ + if (!ssl->peerEccDsaKeyPresent || !ssl->peerEccDsaKey->dp) + return NO_PEER_KEY; + peerKey = ssl->peerEccDsaKey; + } + else { + if (!ssl->peerEccKeyPresent || !ssl->peerEccKey->dp) + return NO_PEER_KEY; + peerKey = ssl->peerEccKey; + } + + if (peerKey == NULL) + return NO_PEER_KEY; + + ecc_init(&myKey); + ret = ecc_make_key(ssl->rng, peerKey->dp->size, &myKey); + if (ret != 0) + return ECC_MAKEKEY_ERROR; + + /* precede export with 1 byte length */ + ret = ecc_export_x963(&myKey, encSecret + 1, &size); + encSecret[0] = (byte)size; + encSz = size + 1; + + if (ret != 0) + ret = ECC_EXPORT_ERROR; + else { + size = sizeof(ssl->arrays->preMasterSecret); + ret = ecc_shared_secret(&myKey, peerKey, + ssl->arrays->preMasterSecret, &size); + if (ret != 0) + ret = ECC_SHARED_ERROR; + } + + ssl->arrays->preMasterSz = size; + ecc_free(&myKey); + } + break; + #endif /* HAVE_ECC */ + default: + return ALGO_ID_E; /* unsupported kea */ + } + + if (ret == 0) { + byte *output; + int sendSz; + word32 tlsSz = 0; + + if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea) + tlsSz = 2; + + if (ssl->specs.kea == ecc_diffie_hellman_kea) /* always off */ + tlsSz = 0; + + sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + } + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl); + + if (tlsSz) { + c16toa((word16)encSz, &output[idx]); + idx += 2; + } + XMEMCPY(output + idx, encSecret, encSz); + /* if add more to output, adjust idx + idx += encSz; */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + if (ssl->options.groupMessages) + ret = 0; + else + ret = SendBuffered(ssl); + } + + if (ret == 0 || ret == WANT_WRITE) { + int tmpRet = MakeMasterSecret(ssl); + if (tmpRet != 0) + ret = tmpRet; /* save WANT_WRITE unless more serious */ + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + } + /* No further need for PMS */ + XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz); + ssl->arrays->preMasterSz = 0; + + return ret; + } + +#ifndef NO_CERTS + int SendCertificateVerify(CYASSL* ssl) + { + byte *output; + int sendSz = 0, length, ret; + word32 idx = 0; + word32 sigOutSz = 0; +#ifndef NO_RSA + RsaKey key; + int initRsaKey = 0; +#endif + int usingEcc = 0; +#ifdef HAVE_ECC + ecc_key eccKey; +#endif + + (void)idx; + + if (ssl->options.sendVerify == SEND_BLANK_CERT) + return 0; /* sent blank cert, can't verify */ + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, MAX_CERT_VERIFY_SZ)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + ret = BuildCertHashes(ssl, &ssl->certHashes); + if (ret != 0) + return ret; + +#ifdef HAVE_ECC + ecc_init(&eccKey); +#endif +#ifndef NO_RSA + ret = InitRsaKey(&key, ssl->heap); + if (ret == 0) initRsaKey = 1; + if (ret == 0) + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key, + ssl->buffers.key.length); + if (ret == 0) + sigOutSz = RsaEncryptSize(&key); + else +#endif + { + #ifdef HAVE_ECC + CYASSL_MSG("Trying ECC client cert, RSA didn't work"); + + idx = 0; + ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &eccKey, + ssl->buffers.key.length); + if (ret == 0) { + CYASSL_MSG("Using ECC client cert"); + usingEcc = 1; + sigOutSz = MAX_ENCODED_SIG_SZ; + } + else { + CYASSL_MSG("Bad client cert type"); + } + #endif + } + if (ret == 0) { + byte* verify = (byte*)&output[RECORD_HEADER_SZ + + HANDSHAKE_HEADER_SZ]; +#ifndef NO_OLD_TLS + byte* signBuffer = ssl->certHashes.md5; +#else + byte* signBuffer = NULL; +#endif + word32 signSz = FINISHED_SZ; + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 extraSz = 0; /* tls 1.2 hash/sig */ + + (void)encodedSig; + (void)signSz; + (void)signBuffer; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + length = sigOutSz; + if (IsAtLeastTLSv1_2(ssl)) { + verify[0] = ssl->suites->hashAlgo; + verify[1] = usingEcc ? ecc_dsa_sa_algo : rsa_sa_algo; + extraSz = HASH_SIG_SIZE; + } + + if (usingEcc) { +#ifdef HAVE_ECC + word32 localSz = MAX_ENCODED_SIG_SZ; + word32 digestSz; + byte* digest; + byte doUserEcc = 0; +#ifndef NO_OLD_TLS + /* old tls default */ + digestSz = SHA_DIGEST_SIZE; + digest = ssl->certHashes.sha; +#else + /* new tls default */ + digestSz = SHA256_DIGEST_SIZE; + digest = ssl->certHashes.sha256; +#endif + + #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + if (ssl->ctx->EccSignCb) + doUserEcc = 1; + #endif /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + + if (IsAtLeastTLSv1_2(ssl)) { + if (ssl->suites->hashAlgo == sha_mac) { + #ifndef NO_SHA + digest = ssl->certHashes.sha; + digestSz = SHA_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = ssl->certHashes.sha256; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = ssl->certHashes.sha384; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + } + + if (doUserEcc) { + #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ret = ssl->ctx->EccSignCb(ssl, digest, digestSz, + encodedSig, &localSz, + ssl->buffers.key.buffer, + ssl->buffers.key.length, + ssl->EccSignCtx); + #endif /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = ecc_sign_hash(digest, digestSz, encodedSig, + &localSz, ssl->rng, &eccKey); + } + if (ret == 0) { + length = localSz; + c16toa((word16)length, verify + extraSz); /* prepend hdr */ + XMEMCPY(verify + extraSz + VERIFY_HEADER,encodedSig,length); + } +#endif + } +#ifndef NO_RSA + else { + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaSignCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + if (IsAtLeastTLSv1_2(ssl)) { +#ifndef NO_OLD_TLS + byte* digest = ssl->certHashes.sha; + int digestSz = SHA_DIGEST_SIZE; + int typeH = SHAh; +#else + byte* digest = ssl->certHashes.sha256; + int digestSz = SHA256_DIGEST_SIZE; + int typeH = SHA256h; +#endif + + if (ssl->suites->hashAlgo == sha_mac) { + #ifndef NO_SHA + digest = ssl->certHashes.sha; + typeH = SHAh; + digestSz = SHA_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = ssl->certHashes.sha256; + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = ssl->certHashes.sha384; + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + + signSz = EncodeSignature(encodedSig, digest,digestSz,typeH); + signBuffer = encodedSig; + } + + c16toa((word16)length, verify + extraSz); /* prepend hdr */ + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + word32 ioLen = ENCRYPT_LEN; + ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, + verify + extraSz + VERIFY_HEADER, + &ioLen, + ssl->buffers.key.buffer, + ssl->buffers.key.length, + ssl->RsaSignCtx); + #endif /* NO_RSA */ + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz + + VERIFY_HEADER, ENCRYPT_LEN, &key, ssl->rng); + } + + if (ret > 0) + ret = 0; /* RSA reset */ + } +#endif + if (ret == 0) { + AddHeaders(output, length + extraSz + VERIFY_HEADER, + certificate_verify, ssl); + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + + extraSz + VERIFY_HEADER; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + } + } +#ifndef NO_RSA + if (initRsaKey) + FreeRsaKey(&key); +#endif +#ifdef HAVE_ECC + ecc_free(&eccKey); +#endif + + if (ret == 0) { + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateVerify", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("CertificateVerify", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); + } + else + return ret; + } +#endif /* NO_CERTS */ + + +#endif /* NO_CYASSL_CLIENT */ + + +#ifndef NO_CYASSL_SERVER + + int SendServerHello(CYASSL* ssl) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int ret; + + length = VERSION_SZ + RAN_LEN + + ID_LEN + ENUM_LEN + + SUITE_LEN + + ENUM_LEN; + +#ifdef HAVE_TLS_EXTENSIONS + length += TLSX_GetResponseSize(ssl); +#endif + + /* check for avalaible size */ + if ((ret = CheckAvailableSize(ssl, MAX_HELLO_SZ)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + AddHeaders(output, length, server_hello, ssl); + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* now write to output */ + /* first version */ + output[idx++] = ssl->version.major; + output[idx++] = ssl->version.minor; + + /* then random */ + if (!ssl->options.resuming) { + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, + RAN_LEN); + if (ret != 0) + return ret; + } + + XMEMCPY(output + idx, ssl->arrays->serverRandom, RAN_LEN); + idx += RAN_LEN; + +#ifdef SHOW_SECRETS + { + int j; + printf("server random: "); + for (j = 0; j < RAN_LEN; j++) + printf("%02x", ssl->arrays->serverRandom[j]); + printf("\n"); + } +#endif + /* then session id */ + output[idx++] = ID_LEN; + + if (!ssl->options.resuming) { + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, ID_LEN); + if (ret != 0) + return ret; + } + + XMEMCPY(output + idx, ssl->arrays->sessionID, ID_LEN); + idx += ID_LEN; + + /* then cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + + /* then compression */ + if (ssl->options.usingCompression) + output[idx++] = ZLIB_COMPRESSION; + else + output[idx++] = NO_COMPRESSION; + + /* last, extensions */ +#ifdef HAVE_TLS_EXTENSIONS + if (IsTLS(ssl)) + TLSX_WriteResponse(ssl, output + idx); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); + } + + +#ifdef HAVE_ECC + + static byte SetCurveId(int size) + { + switch(size) { + case 20: + return secp160r1; + case 24: + return secp192r1; + case 28: + return secp224r1; + case 32: + return secp256r1; + case 48: + return secp384r1; + case 66: + return secp521r1; + default: + return 0; + } + } + +#endif /* HAVE_ECC */ + + + int SendServerKeyExchange(CYASSL* ssl) + { + int ret = 0; + (void)ssl; + + #ifndef NO_PSK + if (ssl->specs.kea == psk_kea) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + if (ssl->arrays->server_hint[0] == 0) return 0; /* don't send */ + + /* include size part */ + length = (word32)XSTRLEN(ssl->arrays->server_hint); + if (length > MAX_PSK_ID_LEN) return SERVER_HINT_ERROR; + length += HINT_LEN_SZ; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* key data */ + c16toa((word16)(length - HINT_LEN_SZ), output + idx); + idx += HINT_LEN_SZ; + XMEMCPY(output + idx, ssl->arrays->server_hint,length -HINT_LEN_SZ); + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + ret = 0; + else + ret = SendBuffered(ssl); + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + } + #endif /*NO_PSK */ + + #ifdef HAVE_ECC + if (ssl->specs.kea == ecc_diffie_hellman_kea) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + byte exportBuf[MAX_EXPORT_ECC_SZ]; + word32 expSz = sizeof(exportBuf); + word32 sigSz; + word32 preSigSz, preSigIdx; +#ifndef NO_RSA + RsaKey rsaKey; +#endif + ecc_key dsaKey; + + if (ssl->specs.static_ecdh) { + CYASSL_MSG("Using Static ECDH, not sending ServerKeyExchagne"); + return 0; + } + + /* curve type, named curve, length(1) */ + length = ENUM_LEN + CURVE_LEN + ENUM_LEN; + /* pub key size */ + CYASSL_MSG("Using ephemeral ECDH"); + if (ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0) + return ECC_EXPORT_ERROR; + length += expSz; + + preSigSz = length; + preSigIdx = idx; + +#ifndef NO_RSA + ret = InitRsaKey(&rsaKey, ssl->heap); + if (ret != 0) return ret; +#endif + ecc_init(&dsaKey); + + /* sig length */ + length += LENGTH_SZ; + + if (!ssl->buffers.key.buffer) { +#ifndef NO_RSA + FreeRsaKey(&rsaKey); +#endif + ecc_free(&dsaKey); + return NO_PRIVATE_KEY; + } + +#ifndef NO_RSA + if (ssl->specs.sig_algo == rsa_sa_algo) { + /* rsa sig size */ + word32 i = 0; + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, + &rsaKey, ssl->buffers.key.length); + if (ret != 0) return ret; + sigSz = RsaEncryptSize(&rsaKey); + } else +#endif + if (ssl->specs.sig_algo == ecc_dsa_sa_algo) { + /* ecdsa sig size */ + word32 i = 0; + ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, + &dsaKey, ssl->buffers.key.length); + if (ret != 0) return ret; + sigSz = ecc_sig_size(&dsaKey); /* worst case estimate */ + } + else { +#ifndef NO_RSA + FreeRsaKey(&rsaKey); +#endif + ecc_free(&dsaKey); + return ALGO_ID_E; /* unsupported type */ + } + length += sigSz; + + if (IsAtLeastTLSv1_2(ssl)) + length += HASH_SIG_SIZE; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + preSigIdx = idx; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { +#ifndef NO_RSA + FreeRsaKey(&rsaKey); +#endif + ecc_free(&dsaKey); + return ret; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* record and message headers will be added below, when we're sure + of the sig length */ + + /* key exchange data */ + output[idx++] = named_curve; + output[idx++] = 0x00; /* leading zero */ + output[idx++] = SetCurveId(ecc_size(ssl->eccTempKey)); + output[idx++] = (byte)expSz; + XMEMCPY(output + idx, exportBuf, expSz); + idx += expSz; + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = ssl->suites->hashAlgo; + output[idx++] = ssl->suites->sigAlgo; + } + + /* Signtaure length will be written later, when we're sure what it + is */ + + /* do signature */ + { +#ifndef NO_OLD_TLS + Md5 md5; + Sha sha; +#endif + byte hash[FINISHED_SZ]; + #ifndef NO_SHA256 + Sha256 sha256; + byte hash256[SHA256_DIGEST_SIZE]; + #endif + #ifdef CYASSL_SHA384 + Sha384 sha384; + byte hash384[SHA384_DIGEST_SIZE]; + #endif + +#ifndef NO_OLD_TLS + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); + Md5Update(&md5, output + preSigIdx, preSigSz); + Md5Final(&md5, hash); + + /* sha */ + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); + ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); + ShaUpdate(&sha, output + preSigIdx, preSigSz); + ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); +#endif + + #ifndef NO_SHA256 + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha256Final(&sha256, hash256); + if (ret != 0) + return ret; + #endif + + #ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha384Final(&sha384, hash384); + if (ret != 0) + return ret; + #endif +#ifndef NO_RSA + if (ssl->suites->sigAlgo == rsa_sa_algo) { + byte* signBuffer = hash; + word32 signSz = sizeof(hash); + byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaSignCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + if (IsAtLeastTLSv1_2(ssl)) { + byte* digest = &hash[MD5_DIGEST_SIZE]; + int typeH = SHAh; + int digestSz = SHA_DIGEST_SIZE; + + if (ssl->suites->hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = hash256; + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = hash384; + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + + signSz = EncodeSignature(encodedSig, digest, digestSz, + typeH); + signBuffer = encodedSig; + } + /* write sig size here */ + c16toa((word16)sigSz, output + idx); + idx += LENGTH_SZ; + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + word32 ioLen = sigSz; + ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, + output + idx, + &ioLen, + ssl->buffers.key.buffer, + ssl->buffers.key.length, + ssl->RsaSignCtx); + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaSSL_Sign(signBuffer, signSz, output + idx, + sigSz, &rsaKey, ssl->rng); + if (ret > 0) + ret = 0; /* reset on success */ + } + FreeRsaKey(&rsaKey); + ecc_free(&dsaKey); + if (ret < 0) + return ret; + } else +#endif + if (ssl->suites->sigAlgo == ecc_dsa_sa_algo) { +#ifndef NO_OLD_TLS + byte* digest = &hash[MD5_DIGEST_SIZE]; + word32 digestSz = SHA_DIGEST_SIZE; +#else + byte* digest = hash256; + word32 digestSz = SHA256_DIGEST_SIZE; +#endif + word32 sz = sigSz; + byte doUserEcc = 0; + + #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + if (ssl->ctx->EccSignCb) + doUserEcc = 1; + #endif /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + + if (IsAtLeastTLSv1_2(ssl)) { + if (ssl->suites->hashAlgo == sha_mac) { + #ifndef NO_SHA + digest = &hash[MD5_DIGEST_SIZE]; + digestSz = SHA_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = hash256; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = hash384; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + } + + if (doUserEcc) { + #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ret = ssl->ctx->EccSignCb(ssl, digest, digestSz, + output + LENGTH_SZ + idx, &sz, + ssl->buffers.key.buffer, + ssl->buffers.key.length, + ssl->EccSignCtx); + #endif /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = ecc_sign_hash(digest, digestSz, + output + LENGTH_SZ + idx, &sz, ssl->rng, &dsaKey); + } +#ifndef NO_RSA + FreeRsaKey(&rsaKey); +#endif + ecc_free(&dsaKey); + if (ret < 0) return ret; + + /* Now that we know the real sig size, write it. */ + c16toa((word16)sz, output + idx); + + /* And adjust length and sendSz from estimates */ + length += sz - sigSz; + sendSz += sz - sigSz; + } + } + + AddHeaders(output, length, server_key_exchange, ssl); + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + ret = 0; + else + ret = SendBuffered(ssl); + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + } + #endif /* HAVE_ECC */ + + #ifdef OPENSSL_EXTRA + if (ssl->specs.kea == diffie_hellman_kea) { + byte *output; + word32 length = 0, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + word32 sigSz = 0, i = 0; + word32 preSigSz = 0, preSigIdx = 0; + RsaKey rsaKey; + DhKey dhKey; + + if (ssl->buffers.serverDH_P.buffer == NULL || + ssl->buffers.serverDH_G.buffer == NULL) + return NO_DH_PARAMS; + + if (ssl->buffers.serverDH_Pub.buffer == NULL) { + ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Pub.buffer == NULL) + return MEMORY_E; + } + + if (ssl->buffers.serverDH_Priv.buffer == NULL) { + ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Priv.buffer == NULL) + return MEMORY_E; + } + + InitDhKey(&dhKey); + ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret == 0) + ret = DhGenerateKeyPair(&dhKey, ssl->rng, + ssl->buffers.serverDH_Priv.buffer, + &ssl->buffers.serverDH_Priv.length, + ssl->buffers.serverDH_Pub.buffer, + &ssl->buffers.serverDH_Pub.length); + FreeDhKey(&dhKey); + + if (ret == 0) { + ret = InitRsaKey(&rsaKey, ssl->heap); + if (ret != 0) return ret; + } + if (ret == 0) { + length = LENGTH_SZ * 3; /* p, g, pub */ + length += ssl->buffers.serverDH_P.length + + ssl->buffers.serverDH_G.length + + ssl->buffers.serverDH_Pub.length; + + preSigIdx = idx; + preSigSz = length; + + /* sig length */ + length += LENGTH_SZ; + + if (!ssl->buffers.key.buffer) + return NO_PRIVATE_KEY; + + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, &rsaKey, + ssl->buffers.key.length); + if (ret == 0) { + sigSz = RsaEncryptSize(&rsaKey); + length += sigSz; + } + } + if (ret != 0) { + FreeRsaKey(&rsaKey); + return ret; + } + + if (IsAtLeastTLSv1_2(ssl)) + length += HASH_SIG_SIZE; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + preSigIdx = idx; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + FreeRsaKey(&rsaKey); + return ret; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* add p, g, pub */ + c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length); + idx += ssl->buffers.serverDH_P.length; + + /* g */ + c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + idx += ssl->buffers.serverDH_G.length; + + /* pub */ + c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length); + idx += ssl->buffers.serverDH_Pub.length; + + /* Add signature */ + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = ssl->suites->hashAlgo; + output[idx++] = ssl->suites->sigAlgo; + } + /* size */ + c16toa((word16)sigSz, output + idx); + idx += LENGTH_SZ; + + /* do signature */ + { +#ifndef NO_OLD_TLS + Md5 md5; + Sha sha; +#endif + byte hash[FINISHED_SZ]; + #ifndef NO_SHA256 + Sha256 sha256; + byte hash256[SHA256_DIGEST_SIZE]; + #endif + #ifdef CYASSL_SHA384 + Sha384 sha384; + byte hash384[SHA384_DIGEST_SIZE]; + #endif + +#ifndef NO_OLD_TLS + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN); + Md5Update(&md5, output + preSigIdx, preSigSz); + Md5Final(&md5, hash); + + /* sha */ + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); + ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); + ShaUpdate(&sha, output + preSigIdx, preSigSz); + ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); +#endif + + #ifndef NO_SHA256 + ret = InitSha256(&sha256); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha256Update(&sha256, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha256Final(&sha256, hash256); + if (ret != 0) + return ret; + #endif + + #ifdef CYASSL_SHA384 + ret = InitSha384(&sha384); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN); + if (ret != 0) + return ret; + ret = Sha384Update(&sha384, output + preSigIdx, preSigSz); + if (ret != 0) + return ret; + ret = Sha384Final(&sha384, hash384); + if (ret != 0) + return ret; + #endif +#ifndef NO_RSA + if (ssl->suites->sigAlgo == rsa_sa_algo) { + byte* signBuffer = hash; + word32 signSz = sizeof(hash); + byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaSignCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + if (IsAtLeastTLSv1_2(ssl)) { + byte* digest = &hash[MD5_DIGEST_SIZE]; + int typeH = SHAh; + int digestSz = SHA_DIGEST_SIZE; + + if (ssl->suites->hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = hash256; + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (ssl->suites->hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = hash384; + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + + signSz = EncodeSignature(encodedSig, digest, digestSz, + typeH); + signBuffer = encodedSig; + } + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + word32 ioLen = sigSz; + ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, + output + idx, + &ioLen, + ssl->buffers.key.buffer, + ssl->buffers.key.length, + ssl->RsaSignCtx); + #endif /*HAVE_PK_CALLBACKS */ + } + else { + ret = RsaSSL_Sign(signBuffer, signSz, output + idx, + sigSz, &rsaKey, ssl->rng); + } + FreeRsaKey(&rsaKey); + if (ret < 0) + return ret; + } +#endif + } + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (ssl->options.groupMessages) + ret = 0; + else + ret = SendBuffered(ssl); + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + } + #endif /* OPENSSL_EXTRA */ + + return ret; + } + + + /* cipher requirements */ + enum { + REQUIRES_RSA, + REQUIRES_DHE, + REQUIRES_ECC_DSA, + REQUIRES_ECC_STATIC, + REQUIRES_PSK, + REQUIRES_NTRU, + REQUIRES_RSA_SIG + }; + + + + /* Does this cipher suite (first, second) have the requirement + an ephemeral key exchange will still require the key for signing + the key exchange so ECHDE_RSA requires an rsa key thus rsa_kea */ + static int CipherRequires(byte first, byte second, int requirement) + { + /* ECC extensions */ + if (first == ECC_BYTE) { + + switch (second) { + +#ifndef NO_RSA + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + +#ifndef NO_DES3 + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; +#endif + +#ifndef NO_RC4 + case TLS_ECDHE_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; +#endif +#endif /* NO_RSA */ + +#ifndef NO_DES3 + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; +#endif +#ifndef NO_RC4 + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; +#endif +#ifndef NO_RSA + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; +#endif + + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + +#ifndef NO_RSA + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_ECC_STATIC) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + + case TLS_RSA_WITH_AES_128_CCM_8 : + case TLS_RSA_WITH_AES_256_CCM_8 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; +#endif + + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 : + case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + if (requirement == REQUIRES_ECC_STATIC) + return 1; + break; + + case TLS_PSK_WITH_AES_128_CCM: + case TLS_PSK_WITH_AES_256_CCM: + case TLS_PSK_WITH_AES_128_CCM_8: + case TLS_PSK_WITH_AES_256_CCM_8: + if (requirement == REQUIRES_PSK) + return 1; + break; + + default: + CYASSL_MSG("Unsupported cipher suite, CipherRequires ECC"); + return 0; + } /* switch */ + } /* if */ + if (first != ECC_BYTE) { /* normal suites */ + switch (second) { + +#ifndef NO_RSA + case SSL_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_NTRU_RSA_WITH_RC4_128_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + + case SSL_RSA_WITH_RC4_128_MD5 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case SSL_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + + case TLS_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; + + case TLS_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_AES_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_NULL_SHA : + case TLS_RSA_WITH_NULL_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_NTRU) + return 1; + break; +#endif + + case TLS_PSK_WITH_AES_128_CBC_SHA256 : + case TLS_PSK_WITH_AES_128_CBC_SHA : + case TLS_PSK_WITH_AES_256_CBC_SHA : + case TLS_PSK_WITH_NULL_SHA256 : + case TLS_PSK_WITH_NULL_SHA : + if (requirement == REQUIRES_PSK) + return 1; + break; + +#ifndef NO_RSA + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_RSA_WITH_HC_128_MD5 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_HC_128_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_HC_128_B2B256: + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_AES_128_CBC_B2B256: + case TLS_RSA_WITH_AES_256_CBC_B2B256: + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_RABBIT_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA : + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA : + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA : + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA : + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_RSA_SIG) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; +#endif + + default: + CYASSL_MSG("Unsupported cipher suite, CipherRequires"); + return 0; + } /* switch */ + } /* if ECC / Normal suites else */ + + return 0; + } + + + /* Make sure client setup is valid for this suite, true on success */ + int VerifyClientSuite(CYASSL* ssl) + { + int havePSK = 0; + byte first = ssl->options.cipherSuite0; + byte second = ssl->options.cipherSuite; + + CYASSL_ENTER("VerifyClientSuite"); + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + + if (CipherRequires(first, second, REQUIRES_PSK)) { + CYASSL_MSG("Requires PSK"); + if (havePSK == 0) { + CYASSL_MSG("Don't have PSK"); + return 0; + } + } + + return 1; /* success */ + } + + + /* Make sure server cert/key are valid for this suite, true on success */ + static int VerifyServerSuite(CYASSL* ssl, word16 idx) + { + int haveRSA = !ssl->options.haveStaticECC; + int havePSK = 0; + byte first; + byte second; + + CYASSL_ENTER("VerifyServerSuite"); + + if (ssl->suites == NULL) { + CYASSL_MSG("Suites pointer error"); + return 0; + } + + first = ssl->suites->suites[idx]; + second = ssl->suites->suites[idx+1]; + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + + if (ssl->options.haveNTRU) + haveRSA = 0; + + if (CipherRequires(first, second, REQUIRES_RSA)) { + CYASSL_MSG("Requires RSA"); + if (haveRSA == 0) { + CYASSL_MSG("Don't have RSA"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_DHE)) { + CYASSL_MSG("Requires DHE"); + if (ssl->options.haveDH == 0) { + CYASSL_MSG("Don't have DHE"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_ECC_DSA)) { + CYASSL_MSG("Requires ECCDSA"); + if (ssl->options.haveECDSAsig == 0) { + CYASSL_MSG("Don't have ECCDSA"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) { + CYASSL_MSG("Requires static ECC"); + if (ssl->options.haveStaticECC == 0) { + CYASSL_MSG("Don't have static ECC"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_PSK)) { + CYASSL_MSG("Requires PSK"); + if (havePSK == 0) { + CYASSL_MSG("Don't have PSK"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_NTRU)) { + CYASSL_MSG("Requires NTRU"); + if (ssl->options.haveNTRU == 0) { + CYASSL_MSG("Don't have NTRU"); + return 0; + } + } + + if (CipherRequires(first, second, REQUIRES_RSA_SIG)) { + CYASSL_MSG("Requires RSA Signature"); + if (ssl->options.side == CYASSL_SERVER_END && + ssl->options.haveECDSAsig == 1) { + CYASSL_MSG("Don't have RSA Signature"); + return 0; + } + } + +#ifdef HAVE_SUPPORTED_CURVES + if (!TLSX_ValidateEllipticCurves(ssl, first, second)) { + CYASSL_MSG("Don't have matching curves"); + return 0; + } +#endif + + /* ECCDHE is always supported if ECC on */ + + return 1; + } + + + static int MatchSuite(CYASSL* ssl, Suites* peerSuites) + { + word16 i, j; + + CYASSL_ENTER("MatchSuite"); + + /* & 0x1 equivalent % 2 */ + if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1) + return MATCH_SUITE_ERROR; + + if (ssl->suites == NULL) + return SUITES_ERROR; + /* start with best, if a match we are good */ + for (i = 0; i < ssl->suites->suiteSz; i += 2) + for (j = 0; j < peerSuites->suiteSz; j += 2) + if (ssl->suites->suites[i] == peerSuites->suites[j] && + ssl->suites->suites[i+1] == peerSuites->suites[j+1] ) { + + if (VerifyServerSuite(ssl, i)) { + int result; + CYASSL_MSG("Verified suite validity"); + ssl->options.cipherSuite0 = ssl->suites->suites[i]; + ssl->options.cipherSuite = ssl->suites->suites[i+1]; + result = SetCipherSpecs(ssl); + if (result == 0) + PickHashSigAlgo(ssl, peerSuites->hashSigAlgo, + peerSuites->hashSigAlgoSz); + return result; + } + else { + CYASSL_MSG("Could not verify suite validity, continue"); + } + } + + return MATCH_SUITE_ERROR; + } + + + /* process old style client hello, deprecate? */ + int ProcessOldClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 inSz, word16 sz) + { + word32 idx = *inOutIdx; + word16 sessionSz; + word16 randomSz; + word16 i, j; + ProtocolVersion pv; + Suites clSuites; + + (void)inSz; + CYASSL_MSG("Got old format client hello"); +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* manually hash input since different format */ +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + Md5Update(&ssl->hashMd5, input + idx, sz); +#endif +#ifndef NO_SHA + ShaUpdate(&ssl->hashSha, input + idx, sz); +#endif +#endif +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) { + int shaRet = Sha256Update(&ssl->hashSha256, input + idx, sz); + + if (shaRet != 0) + return shaRet; + } +#endif + + /* does this value mean client_hello? */ + idx++; + + /* version */ + pv.major = input[idx++]; + pv.minor = input[idx++]; + ssl->chVersion = pv; /* store */ + + if (ssl->version.minor > pv.minor) { + byte haveRSA = 0; + byte havePSK = 0; + if (!ssl->options.downgrade) { + CYASSL_MSG("Client trying to connect with lesser version"); + return VERSION_ERROR; + } + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + CYASSL_MSG(" downgrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + CYASSL_MSG(" downgrading to TLSv1"); + /* turn off tls 1.1+ */ + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + CYASSL_MSG(" downgrading to TLSv1.1"); + ssl->version.minor = TLSv1_1_MINOR; + } +#ifndef NO_RSA + haveRSA = 1; +#endif +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif + + InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveStaticECC, + ssl->options.side); + } + + /* suite size */ + ato16(&input[idx], &clSuites.suiteSz); + idx += 2; + + if (clSuites.suiteSz > MAX_SUITE_SZ) + return BUFFER_ERROR; + clSuites.hashSigAlgoSz = 0; + + /* session size */ + ato16(&input[idx], &sessionSz); + idx += 2; + + if (sessionSz > ID_LEN) + return BUFFER_ERROR; + + /* random size */ + ato16(&input[idx], &randomSz); + idx += 2; + + if (randomSz > RAN_LEN) + return BUFFER_ERROR; + + /* suites */ + for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) { + byte first = input[idx++]; + if (!first) { /* implicit: skip sslv2 type */ + XMEMCPY(&clSuites.suites[j], &input[idx], 2); + j += 2; + } + idx += 2; + } + clSuites.suiteSz = j; + + /* session id */ + if (sessionSz) { + XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz); + idx += sessionSz; + ssl->options.resuming = 1; + } + + /* random */ + if (randomSz < RAN_LEN) + XMEMSET(ssl->arrays->clientRandom, 0, RAN_LEN - randomSz); + XMEMCPY(&ssl->arrays->clientRandom[RAN_LEN - randomSz], input + idx, + randomSz); + idx += randomSz; + + if (ssl->options.usingCompression) + ssl->options.usingCompression = 0; /* turn off */ + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + *inOutIdx = idx; + + ssl->options.haveSessionId = 1; + /* DoClientHello uses same resume code */ + if (ssl->options.resuming) { /* let's try */ + int ret = -1; + CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); + if (!session) { + CYASSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } else { + if (MatchSuite(ssl, &clSuites) < 0) { + CYASSL_MSG("Unsupported cipher suite, OldClientHello"); + return UNSUPPORTED_SUITE; + } + #ifdef SESSION_CERTS + ssl->session = *session; /* restore session certs. */ + #endif + + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, + RAN_LEN); + if (ret != 0) + return ret; + + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + + return ret; + } + } + + return MatchSuite(ssl, &clSuites); + } + + + static int DoClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte b; + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + ssl->chVersion = pv; /* store */ + i += OPAQUE16_LEN; + + if (ssl->version.minor > pv.minor) { + byte haveRSA = 0; + byte havePSK = 0; + + if (!ssl->options.downgrade) { + CYASSL_MSG("Client trying to connect with lesser version"); + return VERSION_ERROR; + } + + if (pv.minor == SSLv3_MINOR) { + /* turn off tls */ + CYASSL_MSG(" downgrading to SSLv3"); + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = SSLv3_MINOR; + } + else if (pv.minor == TLSv1_MINOR) { + /* turn off tls 1.1+ */ + CYASSL_MSG(" downgrading to TLSv1"); + ssl->options.tls1_1 = 0; + ssl->version.minor = TLSv1_MINOR; + } + else if (pv.minor == TLSv1_1_MINOR) { + CYASSL_MSG(" downgrading to TLSv1.1"); + ssl->version.minor = TLSv1_1_MINOR; + } +#ifndef NO_RSA + haveRSA = 1; +#endif +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif + InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveStaticECC, + ssl->options.side); + } + + /* random */ + XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); + i += RAN_LEN; + +#ifdef SHOW_SECRETS + { + int j; + printf("client random: "); + for (j = 0; j < RAN_LEN; j++) + printf("%02x", ssl->arrays->clientRandom[j]); + printf("\n"); + } +#endif + + /* session id */ + b = input[i++]; + + if (b == ID_LEN) { + if ((i - begin) + ID_LEN > helloSz) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN); + i += ID_LEN; + ssl->options.resuming = 1; /* client wants to resume */ + CYASSL_MSG("Client wants to resume session"); + } + else if (b) { + CYASSL_MSG("Invalid session ID size"); + return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } + + #ifdef CYASSL_DTLS + /* cookie */ + if (ssl->options.dtls) { + + if ((i - begin) + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + b = input[i++]; + + if (b) { + byte cookie[MAX_COOKIE_LEN]; + + if (b > MAX_COOKIE_LEN) + return BUFFER_ERROR; + + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + + if (ssl->ctx->CBIOCookie == NULL) { + CYASSL_MSG("Your Cookie callback is null, please set"); + return COOKIE_ERROR; + } + + if ((ssl->ctx->CBIOCookie(ssl, cookie, COOKIE_SZ, + ssl->IOCB_CookieCtx) != COOKIE_SZ) + || (b != COOKIE_SZ) + || (XMEMCMP(cookie, input + i, b) != 0)) { + return COOKIE_ERROR; + } + + i += b; + } + } + #endif + + /* suites */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &clSuites.suiteSz); + i += OPAQUE16_LEN; + + /* suites and compression length check */ + if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + if (clSuites.suiteSz > MAX_SUITE_SZ) + return BUFFER_ERROR; + + XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); + i += clSuites.suiteSz; + clSuites.hashSigAlgoSz = 0; + + /* compression length */ + b = input[i++]; + + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + + if (ssl->options.usingCompression) { + int match = 0; + + while (b--) { + byte comp = input[i++]; + + if (comp == ZLIB_COMPRESSION) + match = 1; + } + + if (!match) { + CYASSL_MSG("Not matching compression, turning off"); + ssl->options.usingCompression = 0; /* turn off */ + } + } + else + i += b; /* ignore, since we're not on */ + + *inOutIdx = i; + + /* tls extensions */ + if ((i - begin) < helloSz) { +#ifdef HAVE_TLS_EXTENSIONS + if (IsTLS(ssl)) { + int ret = 0; +#else + if (IsAtLeastTLSv1_2(ssl)) { +#endif + /* Process the hello extension. Skip unsupported. */ + word16 totalExtSz; + + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + +#ifdef HAVE_TLS_EXTENSIONS + if ((ret = TLSX_Parse(ssl, (byte *) input + i, + totalExtSz, 1, &clSuites))) + return ret; + + i += totalExtSz; +#else + while (totalExtSz) { + word16 extId, extSz; + + if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz) + return BUFFER_ERROR; + + ato16(&input[i], &extId); + i += OPAQUE16_LEN; + ato16(&input[i], &extSz); + i += OPAQUE16_LEN; + + if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz) + return BUFFER_ERROR; + + if (extId == HELLO_EXT_SIG_ALGO) { + ato16(&input[i], &clSuites.hashSigAlgoSz); + i += OPAQUE16_LEN; + + if (OPAQUE16_LEN + clSuites.hashSigAlgoSz > extSz) + return BUFFER_ERROR; + + XMEMCPY(clSuites.hashSigAlgo, &input[i], + min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX)); + i += clSuites.hashSigAlgoSz; + } + else + i += extSz; + + totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz; + } +#endif + *inOutIdx = i; + } + else + *inOutIdx = begin + helloSz; /* skip extensions */ + } + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.haveSessionId = 1; + + /* ProcessOld uses same resume code */ + if (ssl->options.resuming && (!ssl->options.dtls || + ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */ + int ret = -1; + CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); + + if (!session) { + CYASSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } + else { + if (MatchSuite(ssl, &clSuites) < 0) { + CYASSL_MSG("Unsupported cipher suite, ClientHello"); + return UNSUPPORTED_SUITE; + } + #ifdef SESSION_CERTS + ssl->session = *session; /* restore session certs. */ + #endif + + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, + RAN_LEN); + if (ret != 0) + return ret; + + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + + return ret; + } + } + return MatchSuite(ssl, &clSuites); + } + +#if !defined(NO_RSA) || defined(HAVE_ECC) + static int DoCertificateVerify(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 size) + { + word16 sz = 0; + int ret = VERIFY_CERT_ERROR; /* start in error state */ + byte hashAlgo = sha_mac; + byte sigAlgo = anonymous_sa_algo; + word32 begin = *inOutIdx; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateVerify", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("CertificateVerify", &ssl->timeoutInfo); + #endif + + + if (IsAtLeastTLSv1_2(ssl)) { + if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size) + return BUFFER_ERROR; + + hashAlgo = input[(*inOutIdx)++]; + sigAlgo = input[(*inOutIdx)++]; + } + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &sz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + sz > size || sz > ENCRYPT_LEN) + return BUFFER_ERROR; + + /* RSA */ +#ifndef NO_RSA + if (ssl->peerRsaKeyPresent != 0) { + byte* out = NULL; + int outLen = 0; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaVerifyCb) + doUserRsa = 1; + #endif /*HAVE_PK_CALLBACKS */ + + CYASSL_MSG("Doing RSA peer cert verify"); + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + outLen = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, sz, + &out, + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaVerifyCtx); + #endif /*HAVE_PK_CALLBACKS */ + } + else { + outLen = RsaSSL_VerifyInline(input + *inOutIdx, sz, &out, + ssl->peerRsaKey); + } + + if (IsAtLeastTLSv1_2(ssl)) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 sigSz; + byte* digest = ssl->certHashes.sha; + int typeH = SHAh; + int digestSz = SHA_DIGEST_SIZE; + + if (sigAlgo != rsa_sa_algo) { + CYASSL_MSG("Oops, peer sent RSA key but not in verify"); + } + + if (hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = ssl->certHashes.sha256; + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = ssl->certHashes.sha384; + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + + sigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); + + if (outLen == (int)sigSz && out && XMEMCMP(out, encodedSig, + min(sigSz, MAX_ENCODED_SIG_SZ)) == 0) + ret = 0; /* verified */ + } + else { + if (outLen == FINISHED_SZ && out && XMEMCMP(out, + &ssl->certHashes, FINISHED_SZ) == 0) + ret = 0; /* verified */ + } + } +#endif +#ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + int verify = 0; + int err = -1; + byte* digest = ssl->certHashes.sha; + word32 digestSz = SHA_DIGEST_SIZE; + byte doUserEcc = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccVerifyCb) + doUserEcc = 1; + #endif + + CYASSL_MSG("Doing ECC peer cert verify"); + + if (IsAtLeastTLSv1_2(ssl)) { + if (sigAlgo != ecc_dsa_sa_algo) { + CYASSL_MSG("Oops, peer sent ECC key but not in verify"); + } + + if (hashAlgo == sha256_mac) { + #ifndef NO_SHA256 + digest = ssl->certHashes.sha256; + digestSz = SHA256_DIGEST_SIZE; + #endif + } + else if (hashAlgo == sha384_mac) { + #ifdef CYASSL_SHA384 + digest = ssl->certHashes.sha384; + digestSz = SHA384_DIGEST_SIZE; + #endif + } + } + + if (doUserEcc) { + #ifdef HAVE_PK_CALLBACKS + ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, sz, digest, + digestSz, + ssl->buffers.peerEccDsaKey.buffer, + ssl->buffers.peerEccDsaKey.length, + &verify, ssl->EccVerifyCtx); + #endif + } + else { + err = ecc_verify_hash(input + *inOutIdx, sz, digest, digestSz, + &verify, ssl->peerEccDsaKey); + } + + if (err == 0 && verify == 1) + ret = 0; /* verified */ + } +#endif + *inOutIdx += sz; + + if (ret == 0) + ssl->options.havePeerVerify = 1; + + return ret; + } +#endif /* !NO_RSA || HAVE_ECC */ + + int SendServerHelloDone(CYASSL* ssl) + { + byte *output; + int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int ret; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, 0, server_hello_done, ssl); + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return 0; + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHelloDone", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz, + ssl->heap); +#endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } + +#ifdef CYASSL_DTLS + int SendHelloVerifyRequest(CYASSL* ssl) + { + byte* output; + byte cookieSz = COOKIE_SZ; + int length = VERSION_SZ + ENUM_LEN + cookieSz; + int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; + int sendSz = length + idx; + int ret; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, hello_verify_request, ssl); + + output[idx++] = ssl->chVersion.major; + output[idx++] = ssl->chVersion.minor; + + output[idx++] = cookieSz; + if (ssl->ctx->CBIOCookie == NULL) { + CYASSL_MSG("Your Cookie callback is null, please set"); + return COOKIE_ERROR; + } + if ((ret = ssl->ctx->CBIOCookie(ssl, output + idx, cookieSz, + ssl->IOCB_CookieCtx)) < 0) + return ret; + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output, + sendSz, ssl->heap); +#endif + ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } +#endif + + static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 size) + { + int ret = 0; + word32 length = 0; + byte* out = NULL; + word32 begin = *inOutIdx; + + (void)length; /* shut up compiler warnings */ + (void)out; + (void)input; + (void)size; + + if (ssl->options.side != CYASSL_SERVER_END) { + CYASSL_MSG("Client received client keyexchange, attack?"); + CYASSL_ERROR(ssl->error = SIDE_ERROR); + return SSL_FATAL_ERROR; + } + + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + CYASSL_MSG("Client sending keyexchange at wrong time"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + #ifndef NO_CERTS + if (ssl->options.verifyPeer && ssl->options.failNoCert) + if (!ssl->options.havePeerCert) { + CYASSL_MSG("client didn't present peer cert"); + return NO_PEER_CERT; + } + #endif + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ClientKeyExchange", &ssl->timeoutInfo); + #endif + + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + word32 idx = 0; + RsaKey key; + byte doUserRsa = 0; + + #ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaDecCb) + doUserRsa = 1; + #endif + + ret = InitRsaKey(&key, ssl->heap); + if (ret != 0) return ret; + + if (ssl->buffers.key.buffer) + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, + &key, ssl->buffers.key.length); + else + return NO_PRIVATE_KEY; + + if (ret == 0) { + length = RsaEncryptSize(&key); + ssl->arrays->preMasterSz = SECRET_LEN; + + if (ssl->options.tls) { + word16 check; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &check); + *inOutIdx += OPAQUE16_LEN; + + if ((word32) check != length) { + CYASSL_MSG("RSA explicit size doesn't match"); + FreeRsaKey(&key); + return RSA_PRIVATE_ERROR; + } + } + + if ((*inOutIdx - begin) + length > size) { + CYASSL_MSG("RSA message too big"); + FreeRsaKey(&key); + return BUFFER_ERROR; + } + + if (doUserRsa) { + #ifdef HAVE_PK_CALLBACKS + ret = ssl->ctx->RsaDecCb(ssl, + input + *inOutIdx, length, &out, + ssl->buffers.key.buffer, + ssl->buffers.key.length, + ssl->RsaDecCtx); + #endif + } + else { + ret = RsaPrivateDecryptInline(input + *inOutIdx, length, + &out, &key); + } + + *inOutIdx += length; + + if (ret == SECRET_LEN) { + XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN); + if (ssl->arrays->preMasterSecret[0] != + ssl->chVersion.major + || ssl->arrays->preMasterSecret[1] != + ssl->chVersion.minor) + ret = PMS_VERSION_ERROR; + else + ret = MakeMasterSecret(ssl); + } + else { + ret = RSA_PRIVATE_ERROR; + } + } + + FreeRsaKey(&key); + } + break; + #endif + #ifndef NO_PSK + case psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + word16 ci_sz; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &ci_sz); + *inOutIdx += OPAQUE16_LEN; + + if (ci_sz > MAX_PSK_ID_LEN) + return CLIENT_ID_ERROR; + + if ((*inOutIdx - begin) + ci_sz > size) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz); + *inOutIdx += ci_sz; + + ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0; + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) + return PSK_KEY_ERROR; + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMSET(pms, 0, ssl->arrays->psk_keySz); + pms += ssl->arrays->psk_keySz; + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; + + ret = MakeMasterSecret(ssl); + + /* No further need for PSK */ + XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); + ssl->arrays->psk_keySz = 0; + } + break; + #endif /* NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + word16 cipherLen; + word16 plainLen = sizeof(ssl->arrays->preMasterSecret); + + if (!ssl->buffers.key.buffer) + return NO_PRIVATE_KEY; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &cipherLen); + *inOutIdx += OPAQUE16_LEN; + + if (cipherLen > MAX_NTRU_ENCRYPT_SZ) + return NTRU_KEY_ERROR; + + if ((*inOutIdx - begin) + cipherLen > size) + return BUFFER_ERROR; + + if (NTRU_OK != crypto_ntru_decrypt( + (word16) ssl->buffers.key.length, + ssl->buffers.key.buffer, cipherLen, + input + *inOutIdx, &plainLen, + ssl->arrays->preMasterSecret)) + return NTRU_DECRYPT_ERROR; + + if (plainLen != SECRET_LEN) + return NTRU_DECRYPT_ERROR; + + *inOutIdx += cipherLen; + + ssl->arrays->preMasterSz = plainLen; + ret = MakeMasterSecret(ssl); + } + break; + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + if ((*inOutIdx - begin) + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + length = input[(*inOutIdx)++]; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey)) + return ECC_PEERKEY_ERROR; + + *inOutIdx += length; + ssl->peerEccKeyPresent = 1; + + length = sizeof(ssl->arrays->preMasterSecret); + + if (ssl->specs.static_ecdh) { + ecc_key staticKey; + word32 i = 0; + + ecc_init(&staticKey); + ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, + &staticKey, ssl->buffers.key.length); + + if (ret == 0) + ret = ecc_shared_secret(&staticKey, ssl->peerEccKey, + ssl->arrays->preMasterSecret, &length); + + ecc_free(&staticKey); + } + else + ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey, + ssl->arrays->preMasterSecret, &length); + + if (ret != 0) + return ECC_SHARED_ERROR; + + ssl->arrays->preMasterSz = length; + ret = MakeMasterSecret(ssl); + } + break; + #endif /* HAVE_ECC */ + #ifdef OPENSSL_EXTRA + case diffie_hellman_kea: + { + word16 clientPubSz; + DhKey dhKey; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &clientPubSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + clientPubSz > size) + return BUFFER_ERROR; + + InitDhKey(&dhKey); + ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret == 0) + ret = DhAgree(&dhKey, ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz, + ssl->buffers.serverDH_Priv.buffer, + ssl->buffers.serverDH_Priv.length, + input + *inOutIdx, clientPubSz); + FreeDhKey(&dhKey); + + *inOutIdx += clientPubSz; + + if (ret == 0) + ret = MakeMasterSecret(ssl); + } + break; + #endif /* OPENSSL_EXTRA */ + default: + { + CYASSL_MSG("Bad kea type"); + ret = BAD_KEA_TYPE_E; + } + break; + } + + /* No further need for PMS */ + XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz); + ssl->arrays->preMasterSz = 0; + + if (ret == 0) { + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + #ifndef NO_CERTS + if (ssl->options.verifyPeer) + ret = BuildCertHashes(ssl, &ssl->certHashes); + #endif + } + + return ret; + } + +#endif /* NO_CYASSL_SERVER */ +
diff -r 64d4f7cb83d5 -r e505054279ed src/keys.c --- a/src/keys.c Wed Dec 03 05:24:18 2014 +0000 +++ b/src/keys.c Wed Jan 14 22:07:14 2015 +0000 @@ -1,2013 +1,2014 @@ -/* keys.c - * - * Copyright (C) 2006-2014 wolfSSL Inc. - * - * This file is part of CyaSSL. - * - * CyaSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * CyaSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <cyassl/ctaocrypt/settings.h> - -#include <cyassl/internal.h> -#include <cyassl/error-ssl.h> -#ifdef SHOW_SECRETS - #ifdef FREESCALE_MQX - #include <fio.h> - #else - #include <stdio.h> - #endif -#endif - - -int SetCipherSpecs(CYASSL* ssl) -{ - if (ssl->options.side == CYASSL_CLIENT_END) { - /* server side verified before SetCipherSpecs call */ - if (VerifyClientSuite(ssl) != 1) { - CYASSL_MSG("SetCipherSpecs() client has an unusuable suite"); - return UNSUPPORTED_SUITE; - } - } - /* ECC extensions, or AES-CCM */ - if (ssl->options.cipherSuite0 == ECC_BYTE) { - - switch (ssl->options.cipherSuite) { - -#ifdef HAVE_ECC - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA - case TLS_ECDHE_RSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA - case TLS_ECDH_RSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA - case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 1; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 - case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 - case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = ecc_diffie_hellman_kea; - ssl->specs.sig_algo = ecc_dsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; - - break; -#endif -#endif /* HAVE_ECC */ - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 - case TLS_RSA_WITH_AES_128_CCM_8 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 - case TLS_RSA_WITH_AES_256_CCM_8 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 - case TLS_PSK_WITH_AES_128_CCM_8 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 - case TLS_PSK_WITH_AES_256_CCM_8 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - - default: - CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs ECC"); - return UNSUPPORTED_SUITE; - } /* switch */ - } /* if */ - if (ssl->options.cipherSuite0 != ECC_BYTE) { /* normal suites */ - switch (ssl->options.cipherSuite) { - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA - case SSL_RSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - case TLS_NTRU_RSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 - case SSL_RSA_WITH_RC4_128_MD5 : - ssl->specs.bulk_cipher_algorithm = cyassl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = md5_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = MD5_DIGEST_SIZE; - ssl->specs.pad_size = PAD_MD5; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif - -#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA - case SSL_RSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA - case TLS_RSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 - case TLS_RSA_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA - case TLS_RSA_WITH_NULL_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = 0; - ssl->specs.block_size = 0; - ssl->specs.iv_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 - case TLS_RSA_WITH_NULL_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = 0; - ssl->specs.block_size = 0; - ssl->specs.iv_size = 0; - - break; -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA - case TLS_RSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 - case TLS_RSA_WITH_AES_256_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 - case TLS_PSK_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA - case TLS_PSK_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA - case TLS_PSK_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 - case TLS_PSK_WITH_NULL_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = 0; - ssl->specs.block_size = 0; - ssl->specs.iv_size = 0; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - -#ifdef BUILD_TLS_PSK_WITH_NULL_SHA - case TLS_PSK_WITH_NULL_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = psk_kea; - ssl->specs.sig_algo = anonymous_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = 0; - ssl->specs.block_size = 0; - ssl->specs.iv_size = 0; - - ssl->options.usingPSK_cipher = 1; - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 - case TLS_RSA_WITH_HC_128_MD5 : - ssl->specs.bulk_cipher_algorithm = cyassl_hc128; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = md5_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = MD5_DIGEST_SIZE; - ssl->specs.pad_size = PAD_MD5; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = HC_128_KEY_SIZE; - ssl->specs.block_size = 0; - ssl->specs.iv_size = HC_128_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA - case TLS_RSA_WITH_HC_128_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_hc128; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = HC_128_KEY_SIZE; - ssl->specs.block_size = 0; - ssl->specs.iv_size = HC_128_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 - case TLS_RSA_WITH_HC_128_B2B256: - ssl->specs.bulk_cipher_algorithm = cyassl_hc128; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = blake2b_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = BLAKE2B_256; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = HC_128_KEY_SIZE; - ssl->specs.block_size = 0; - ssl->specs.iv_size = HC_128_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 - case TLS_RSA_WITH_AES_128_CBC_B2B256: - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = blake2b_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = BLAKE2B_256; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 - case TLS_RSA_WITH_AES_256_CBC_B2B256: - ssl->specs.bulk_cipher_algorithm = cyassl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = blake2b_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = BLAKE2B_256; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA - case TLS_RSA_WITH_RABBIT_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_rabbit; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RABBIT_KEY_SIZE; - ssl->specs.block_size = 0; - ssl->specs.iv_size = RABBIT_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 - case TLS_RSA_WITH_AES_128_GCM_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 - case TLS_RSA_WITH_AES_256_GCM_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : - ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; - ssl->specs.cipher_type = aead; - ssl->specs.mac_algorithm = sha384_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA384_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AEAD_IMP_IV_SZ; - ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = rsa_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - -#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 : - ssl->specs.bulk_cipher_algorithm = cyassl_camellia; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha256_mac; - ssl->specs.kea = diffie_hellman_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA256_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; - ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; - ssl->specs.iv_size = CAMELLIA_IV_SIZE; - - break; -#endif - - default: - CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs"); - return UNSUPPORTED_SUITE; - } /* switch */ - } /* if ECC / Normal suites else */ - - /* set TLS if it hasn't been turned off */ - if (ssl->version.major == 3 && ssl->version.minor >= 1) { -#ifndef NO_TLS - ssl->options.tls = 1; - ssl->hmac = TLS_hmac; - if (ssl->version.minor >= 2) - ssl->options.tls1_1 = 1; -#endif - } - -#ifdef CYASSL_DTLS - if (ssl->options.dtls) - ssl->hmac = TLS_hmac; -#endif - - return 0; -} - - -enum KeyStuff { - MASTER_ROUNDS = 3, - PREFIX = 3, /* up to three letters for master prefix */ - KEY_PREFIX = 7 /* up to 7 prefix letters for key rounds */ - - -}; - -#ifndef NO_OLD_TLS -/* true or false, zero for error */ -static int SetPrefix(byte* sha_input, int idx) -{ - switch (idx) { - case 0: - XMEMCPY(sha_input, "A", 1); - break; - case 1: - XMEMCPY(sha_input, "BB", 2); - break; - case 2: - XMEMCPY(sha_input, "CCC", 3); - break; - case 3: - XMEMCPY(sha_input, "DDDD", 4); - break; - case 4: - XMEMCPY(sha_input, "EEEEE", 5); - break; - case 5: - XMEMCPY(sha_input, "FFFFFF", 6); - break; - case 6: - XMEMCPY(sha_input, "GGGGGGG", 7); - break; - default: - CYASSL_MSG("Set Prefix error, bad input"); - return 0; - } - return 1; -} -#endif - - -static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, - byte side, void* heap, int devId) -{ -#ifdef BUILD_ARC4 - word32 sz = specs->key_size; - if (specs->bulk_cipher_algorithm == cyassl_rc4) { - if (enc->arc4 == NULL) - enc->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER); - if (enc->arc4 == NULL) - return MEMORY_E; - if (dec->arc4 == NULL) - dec->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER); - if (dec->arc4 == NULL) - return MEMORY_E; -#ifdef HAVE_CAVIUM - if (devId != NO_CAVIUM_DEVICE) { - if (Arc4InitCavium(enc->arc4, devId) != 0) { - CYASSL_MSG("Arc4InitCavium failed in SetKeys"); - return CAVIUM_INIT_E; - } - if (Arc4InitCavium(dec->arc4, devId) != 0) { - CYASSL_MSG("Arc4InitCavium failed in SetKeys"); - return CAVIUM_INIT_E; - } - } -#endif - if (side == CYASSL_CLIENT_END) { - Arc4SetKey(enc->arc4, keys->client_write_key, sz); - Arc4SetKey(dec->arc4, keys->server_write_key, sz); - } - else { - Arc4SetKey(enc->arc4, keys->server_write_key, sz); - Arc4SetKey(dec->arc4, keys->client_write_key, sz); - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef HAVE_HC128 - if (specs->bulk_cipher_algorithm == cyassl_hc128) { - int hcRet; - if (enc->hc128 == NULL) - enc->hc128 = - (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER); - if (enc->hc128 == NULL) - return MEMORY_E; - if (dec->hc128 == NULL) - dec->hc128 = - (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER); - if (dec->hc128 == NULL) - return MEMORY_E; - if (side == CYASSL_CLIENT_END) { - hcRet = Hc128_SetKey(enc->hc128, keys->client_write_key, - keys->client_write_IV); - if (hcRet != 0) return hcRet; - hcRet = Hc128_SetKey(dec->hc128, keys->server_write_key, - keys->server_write_IV); - if (hcRet != 0) return hcRet; - } - else { - hcRet = Hc128_SetKey(enc->hc128, keys->server_write_key, - keys->server_write_IV); - if (hcRet != 0) return hcRet; - hcRet = Hc128_SetKey(dec->hc128, keys->client_write_key, - keys->client_write_IV); - if (hcRet != 0) return hcRet; - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef BUILD_RABBIT - if (specs->bulk_cipher_algorithm == cyassl_rabbit) { - int rabRet; - if (enc->rabbit == NULL) - enc->rabbit = - (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER); - if (enc->rabbit == NULL) - return MEMORY_E; - if (dec->rabbit == NULL) - dec->rabbit = - (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER); - if (dec->rabbit == NULL) - return MEMORY_E; - if (side == CYASSL_CLIENT_END) { - rabRet = RabbitSetKey(enc->rabbit, keys->client_write_key, - keys->client_write_IV); - if (rabRet != 0) return rabRet; - rabRet = RabbitSetKey(dec->rabbit, keys->server_write_key, - keys->server_write_IV); - if (rabRet != 0) return rabRet; - } - else { - rabRet = RabbitSetKey(enc->rabbit, keys->server_write_key, - keys->server_write_IV); - if (rabRet != 0) return rabRet; - rabRet = RabbitSetKey(dec->rabbit, keys->client_write_key, - keys->client_write_IV); - if (rabRet != 0) return rabRet; - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef BUILD_DES3 - if (specs->bulk_cipher_algorithm == cyassl_triple_des) { - int desRet = 0; - - if (enc->des3 == NULL) - enc->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER); - if (enc->des3 == NULL) - return MEMORY_E; - if (dec->des3 == NULL) - dec->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER); - if (dec->des3 == NULL) - return MEMORY_E; -#ifdef HAVE_CAVIUM - if (devId != NO_CAVIUM_DEVICE) { - if (Des3_InitCavium(enc->des3, devId) != 0) { - CYASSL_MSG("Des3_InitCavium failed in SetKeys"); - return CAVIUM_INIT_E; - } - if (Des3_InitCavium(dec->des3, devId) != 0) { - CYASSL_MSG("Des3_InitCavium failed in SetKeys"); - return CAVIUM_INIT_E; - } - } -#endif - if (side == CYASSL_CLIENT_END) { - desRet = Des3_SetKey(enc->des3, keys->client_write_key, - keys->client_write_IV, DES_ENCRYPTION); - if (desRet != 0) - return desRet; - desRet = Des3_SetKey(dec->des3, keys->server_write_key, - keys->server_write_IV, DES_DECRYPTION); - if (desRet != 0) - return desRet; - } - else { - desRet = Des3_SetKey(enc->des3, keys->server_write_key, - keys->server_write_IV, DES_ENCRYPTION); - if (desRet != 0) - return desRet; - desRet = Des3_SetKey(dec->des3, keys->client_write_key, - keys->client_write_IV, DES_DECRYPTION); - if (desRet != 0) - return desRet; - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef BUILD_AES - if (specs->bulk_cipher_algorithm == cyassl_aes) { - int aesRet = 0; - - if (enc->aes == NULL) - enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); - if (enc->aes == NULL) - return MEMORY_E; - if (dec->aes == NULL) - dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); - if (dec->aes == NULL) - return MEMORY_E; -#ifdef HAVE_CAVIUM - if (devId != NO_CAVIUM_DEVICE) { - if (AesInitCavium(enc->aes, devId) != 0) { - CYASSL_MSG("AesInitCavium failed in SetKeys"); - return CAVIUM_INIT_E; - } - if (AesInitCavium(dec->aes, devId) != 0) { - CYASSL_MSG("AesInitCavium failed in SetKeys"); - return CAVIUM_INIT_E; - } - } -#endif - if (side == CYASSL_CLIENT_END) { - aesRet = AesSetKey(enc->aes, keys->client_write_key, - specs->key_size, keys->client_write_IV, - AES_ENCRYPTION); - if (aesRet != 0) - return aesRet; - aesRet = AesSetKey(dec->aes, keys->server_write_key, - specs->key_size, keys->server_write_IV, - AES_DECRYPTION); - if (aesRet != 0) - return aesRet; - } - else { - aesRet = AesSetKey(enc->aes, keys->server_write_key, - specs->key_size, keys->server_write_IV, - AES_ENCRYPTION); - if (aesRet != 0) - return aesRet; - aesRet = AesSetKey(dec->aes, keys->client_write_key, - specs->key_size, keys->client_write_IV, - AES_DECRYPTION); - if (aesRet != 0) - return aesRet; - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef BUILD_AESGCM - if (specs->bulk_cipher_algorithm == cyassl_aes_gcm) { - if (enc->aes == NULL) - enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); - if (enc->aes == NULL) - return MEMORY_E; - if (dec->aes == NULL) - dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); - if (dec->aes == NULL) - return MEMORY_E; - - if (side == CYASSL_CLIENT_END) { - AesGcmSetKey(enc->aes, keys->client_write_key, specs->key_size); - XMEMCPY(keys->aead_enc_imp_IV, - keys->client_write_IV, AEAD_IMP_IV_SZ); - AesGcmSetKey(dec->aes, keys->server_write_key, specs->key_size); - XMEMCPY(keys->aead_dec_imp_IV, - keys->server_write_IV, AEAD_IMP_IV_SZ); - } - else { - AesGcmSetKey(enc->aes, keys->server_write_key, specs->key_size); - XMEMCPY(keys->aead_enc_imp_IV, - keys->server_write_IV, AEAD_IMP_IV_SZ); - AesGcmSetKey(dec->aes, keys->client_write_key, specs->key_size); - XMEMCPY(keys->aead_dec_imp_IV, - keys->client_write_IV, AEAD_IMP_IV_SZ); - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef HAVE_AESCCM - if (specs->bulk_cipher_algorithm == cyassl_aes_ccm) { - if (enc->aes == NULL) - enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); - if (enc->aes == NULL) - return MEMORY_E; - if (dec->aes == NULL) - dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); - if (dec->aes == NULL) - return MEMORY_E; - - if (side == CYASSL_CLIENT_END) { - AesCcmSetKey(enc->aes, keys->client_write_key, specs->key_size); - XMEMCPY(keys->aead_enc_imp_IV, - keys->client_write_IV, AEAD_IMP_IV_SZ); - AesCcmSetKey(dec->aes, keys->server_write_key, specs->key_size); - XMEMCPY(keys->aead_dec_imp_IV, - keys->server_write_IV, AEAD_IMP_IV_SZ); - } - else { - AesCcmSetKey(enc->aes, keys->server_write_key, specs->key_size); - XMEMCPY(keys->aead_enc_imp_IV, - keys->server_write_IV, AEAD_IMP_IV_SZ); - AesCcmSetKey(dec->aes, keys->client_write_key, specs->key_size); - XMEMCPY(keys->aead_dec_imp_IV, - keys->client_write_IV, AEAD_IMP_IV_SZ); - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef HAVE_CAMELLIA - if (specs->bulk_cipher_algorithm == cyassl_camellia) { - int camRet; - - if (enc->cam == NULL) - enc->cam = - (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER); - if (enc->cam == NULL) - return MEMORY_E; - - if (dec->cam == NULL) - dec->cam = - (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER); - if (dec->cam == NULL) - return MEMORY_E; - - if (side == CYASSL_CLIENT_END) { - camRet = CamelliaSetKey(enc->cam, keys->client_write_key, - specs->key_size, keys->client_write_IV); - if (camRet != 0) - return camRet; - - camRet = CamelliaSetKey(dec->cam, keys->server_write_key, - specs->key_size, keys->server_write_IV); - if (camRet != 0) - return camRet; - } - else { - camRet = CamelliaSetKey(enc->cam, keys->server_write_key, - specs->key_size, keys->server_write_IV); - if (camRet != 0) - return camRet; - - camRet = CamelliaSetKey(dec->cam, keys->client_write_key, - specs->key_size, keys->client_write_IV); - if (camRet != 0) - return camRet; - } - enc->setup = 1; - dec->setup = 1; - } -#endif - -#ifdef HAVE_NULL_CIPHER - if (specs->bulk_cipher_algorithm == cyassl_cipher_null) { - enc->setup = 1; - dec->setup = 1; - } -#endif - - keys->sequence_number = 0; - keys->peer_sequence_number = 0; - keys->encryptionOn = 0; - (void)side; - (void)heap; - (void)enc; - (void)dec; - (void)specs; - (void)devId; - - return 0; -} - - -/* TLS can call too */ -int StoreKeys(CYASSL* ssl, const byte* keyData) -{ - int sz, i = 0; - int devId = NO_CAVIUM_DEVICE; - -#ifdef HAVE_CAVIUM - devId = ssl->devId; -#endif - - if (ssl->specs.cipher_type != aead) { - sz = ssl->specs.hash_size; - XMEMCPY(ssl->keys.client_write_MAC_secret,&keyData[i], sz); - i += sz; - XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); - i += sz; - } - sz = ssl->specs.key_size; - XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz); - i += sz; - XMEMCPY(ssl->keys.server_write_key, &keyData[i], sz); - i += sz; - - sz = ssl->specs.iv_size; - XMEMCPY(ssl->keys.client_write_IV, &keyData[i], sz); - i += sz; - XMEMCPY(ssl->keys.server_write_IV, &keyData[i], sz); - -#ifdef HAVE_AEAD - if (ssl->specs.cipher_type == aead) { - /* Initialize the AES-GCM/CCM explicit IV to a zero. */ - XMEMSET(ssl->keys.aead_exp_IV, 0, AEAD_EXP_IV_SZ); - } -#endif - - return SetKeys(&ssl->encrypt, &ssl->decrypt, &ssl->keys, &ssl->specs, - ssl->options.side, ssl->heap, devId); -} - -#ifndef NO_OLD_TLS -int DeriveKeys(CYASSL* ssl) -{ - int length = 2 * ssl->specs.hash_size + - 2 * ssl->specs.key_size + - 2 * ssl->specs.iv_size; - int rounds = (length + MD5_DIGEST_SIZE - 1 ) / MD5_DIGEST_SIZE, i; - int ret = 0; - - byte shaOutput[SHA_DIGEST_SIZE]; - byte md5Input[SECRET_LEN + SHA_DIGEST_SIZE]; - byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; - - Md5 md5; - Sha sha; - - byte keyData[KEY_PREFIX * MD5_DIGEST_SIZE]; /* max size */ - - InitMd5(&md5); - ret = InitSha(&sha); - if (ret != 0) - return ret; - - XMEMCPY(md5Input, ssl->arrays->masterSecret, SECRET_LEN); - - for (i = 0; i < rounds; ++i) { - int j = i + 1; - int idx = j; - - if (!SetPrefix(shaInput, i)) { - return PREFIX_ERROR; - } - - XMEMCPY(shaInput + idx, ssl->arrays->masterSecret, SECRET_LEN); - idx += SECRET_LEN; - XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN); - idx += RAN_LEN; - XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN); - - ShaUpdate(&sha, shaInput, (word32)sizeof(shaInput) - KEY_PREFIX + j); - ShaFinal(&sha, shaOutput); - - XMEMCPY(&md5Input[SECRET_LEN], shaOutput, SHA_DIGEST_SIZE); - Md5Update(&md5, md5Input, sizeof(md5Input)); - Md5Final(&md5, keyData + i * MD5_DIGEST_SIZE); - } - - return StoreKeys(ssl, keyData); -} - - -static int CleanPreMaster(CYASSL* ssl) -{ - int i, ret, sz = ssl->arrays->preMasterSz; - - for (i = 0; i < sz; i++) - ssl->arrays->preMasterSecret[i] = 0; - - ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, sz); - if (ret != 0) - return ret; - - for (i = 0; i < sz; i++) - ssl->arrays->preMasterSecret[i] = 0; - - return 0; -} - - -/* Create and store the master secret see page 32, 6.1 */ -static int MakeSslMasterSecret(CYASSL* ssl) -{ - byte shaOutput[SHA_DIGEST_SIZE]; - byte md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE]; - byte shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN]; - int i, ret; - word32 idx; - word32 pmsSz = ssl->arrays->preMasterSz; - - Md5 md5; - Sha sha; - -#ifdef SHOW_SECRETS - { - word32 j; - printf("pre master secret: "); - for (j = 0; j < pmsSz; j++) - printf("%02x", ssl->arrays->preMasterSecret[j]); - printf("\n"); - } -#endif - - InitMd5(&md5); - ret = InitSha(&sha); - if (ret != 0) - return ret; - - XMEMCPY(md5Input, ssl->arrays->preMasterSecret, pmsSz); - - for (i = 0; i < MASTER_ROUNDS; ++i) { - byte prefix[PREFIX]; - if (!SetPrefix(prefix, i)) { - return PREFIX_ERROR; - } - - idx = 0; - XMEMCPY(shaInput, prefix, i + 1); - idx += i + 1; - - XMEMCPY(shaInput + idx, ssl->arrays->preMasterSecret, pmsSz); - idx += pmsSz; - XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN); - idx += RAN_LEN; - XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN); - idx += RAN_LEN; - ShaUpdate(&sha, shaInput, idx); - ShaFinal(&sha, shaOutput); - - idx = pmsSz; /* preSz */ - XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE); - idx += SHA_DIGEST_SIZE; - Md5Update(&md5, md5Input, idx); - Md5Final(&md5, &ssl->arrays->masterSecret[i * MD5_DIGEST_SIZE]); - } - -#ifdef SHOW_SECRETS - { - word32 j; - printf("master secret: "); - for (j = 0; j < SECRET_LEN; j++) - printf("%02x", ssl->arrays->masterSecret[j]); - printf("\n"); - } -#endif - - ret = DeriveKeys(ssl); - if (ret != 0) { - /* always try to clean PreMaster */ - CleanPreMaster(ssl); - return ret; - } - - return CleanPreMaster(ssl); -} -#endif - - -/* Master wrapper, doesn't use SSL stack space in TLS mode */ -int MakeMasterSecret(CYASSL* ssl) -{ -#ifdef NO_OLD_TLS - return MakeTlsMasterSecret(ssl); -#elif !defined(NO_TLS) - if (ssl->options.tls) return MakeTlsMasterSecret(ssl); -#endif - -#ifndef NO_OLD_TLS - return MakeSslMasterSecret(ssl); -#endif -} - +/* keys.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <cyassl/ctaocrypt/settings.h> + +#include <cyassl/internal.h> +#include <cyassl/error-ssl.h> +#ifdef SHOW_SECRETS + #ifdef FREESCALE_MQX + #include <fio.h> + #else + #include <stdio.h> + #endif +#endif + +int SetCipherSpecs(CYASSL* ssl) +{ +#ifndef NO_CYASSL_SERVER + if (ssl->options.side == CYASSL_CLIENT_END) { + /* server side verified before SetCipherSpecs call */ + if (VerifyClientSuite(ssl) != 1) { + CYASSL_MSG("SetCipherSpecs() client has an unusuable suite"); + return UNSUPPORTED_SUITE; + } + } +#endif /* NO_CYASSL_SERVER */ + /* ECC extensions, or AES-CCM */ + if (ssl->options.cipherSuite0 == ECC_BYTE) { + + switch (ssl->options.cipherSuite) { + +#ifdef HAVE_ECC + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + case TLS_ECDHE_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA + case TLS_ECDH_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif +#endif /* HAVE_ECC */ + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 + case TLS_RSA_WITH_AES_128_CCM_8 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8 + case TLS_RSA_WITH_AES_256_CCM_8 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8 + case TLS_PSK_WITH_AES_128_CCM_8 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8 + case TLS_PSK_WITH_AES_256_CCM_8 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + + default: + CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs ECC"); + return UNSUPPORTED_SUITE; + } /* switch */ + } /* if */ + if (ssl->options.cipherSuite0 != ECC_BYTE) { /* normal suites */ + switch (ssl->options.cipherSuite) { + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + case SSL_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + case TLS_NTRU_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + case SSL_RSA_WITH_RC4_128_MD5 : + ssl->specs.bulk_cipher_algorithm = cyassl_rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + case SSL_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + case TLS_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 + case TLS_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA + case TLS_RSA_WITH_NULL_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256 + case TLS_RSA_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + case TLS_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 + case TLS_RSA_WITH_AES_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256 + case TLS_PSK_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + case TLS_PSK_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + case TLS_PSK_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256 + case TLS_PSK_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_NULL_SHA + case TLS_PSK_WITH_NULL_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = 0; + ssl->specs.block_size = 0; + ssl->specs.iv_size = 0; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5 + case TLS_RSA_WITH_HC_128_MD5 : + ssl->specs.bulk_cipher_algorithm = cyassl_hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA + case TLS_RSA_WITH_HC_128_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256 + case TLS_RSA_WITH_HC_128_B2B256: + ssl->specs.bulk_cipher_algorithm = cyassl_hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = blake2b_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = BLAKE2B_256; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256 + case TLS_RSA_WITH_AES_128_CBC_B2B256: + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = blake2b_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = BLAKE2B_256; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256 + case TLS_RSA_WITH_AES_256_CBC_B2B256: + ssl->specs.bulk_cipher_algorithm = cyassl_aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = blake2b_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = BLAKE2B_256; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA + case TLS_RSA_WITH_RABBIT_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_rabbit; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = RABBIT_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = RABBIT_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = cyassl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AEAD_IMP_IV_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_128_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 : + ssl->specs.bulk_cipher_algorithm = cyassl_camellia; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CAMELLIA_256_KEY_SIZE; + ssl->specs.block_size = CAMELLIA_BLOCK_SIZE; + ssl->specs.iv_size = CAMELLIA_IV_SIZE; + + break; +#endif + + default: + CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs"); + return UNSUPPORTED_SUITE; + } /* switch */ + } /* if ECC / Normal suites else */ + + /* set TLS if it hasn't been turned off */ + if (ssl->version.major == 3 && ssl->version.minor >= 1) { +#ifndef NO_TLS + ssl->options.tls = 1; + ssl->hmac = TLS_hmac; + if (ssl->version.minor >= 2) + ssl->options.tls1_1 = 1; +#endif + } + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) + ssl->hmac = TLS_hmac; +#endif + + return 0; +} + + +enum KeyStuff { + MASTER_ROUNDS = 3, + PREFIX = 3, /* up to three letters for master prefix */ + KEY_PREFIX = 7 /* up to 7 prefix letters for key rounds */ + + +}; + +#ifndef NO_OLD_TLS +/* true or false, zero for error */ +static int SetPrefix(byte* sha_input, int idx) +{ + switch (idx) { + case 0: + XMEMCPY(sha_input, "A", 1); + break; + case 1: + XMEMCPY(sha_input, "BB", 2); + break; + case 2: + XMEMCPY(sha_input, "CCC", 3); + break; + case 3: + XMEMCPY(sha_input, "DDDD", 4); + break; + case 4: + XMEMCPY(sha_input, "EEEEE", 5); + break; + case 5: + XMEMCPY(sha_input, "FFFFFF", 6); + break; + case 6: + XMEMCPY(sha_input, "GGGGGGG", 7); + break; + default: + CYASSL_MSG("Set Prefix error, bad input"); + return 0; + } + return 1; +} +#endif + + +static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, + byte side, void* heap, int devId) +{ +#ifdef BUILD_ARC4 + word32 sz = specs->key_size; + if (specs->bulk_cipher_algorithm == cyassl_rc4) { + if (enc->arc4 == NULL) + enc->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER); + if (enc->arc4 == NULL) + return MEMORY_E; + if (dec->arc4 == NULL) + dec->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER); + if (dec->arc4 == NULL) + return MEMORY_E; +#ifdef HAVE_CAVIUM + if (devId != NO_CAVIUM_DEVICE) { + if (Arc4InitCavium(enc->arc4, devId) != 0) { + CYASSL_MSG("Arc4InitCavium failed in SetKeys"); + return CAVIUM_INIT_E; + } + if (Arc4InitCavium(dec->arc4, devId) != 0) { + CYASSL_MSG("Arc4InitCavium failed in SetKeys"); + return CAVIUM_INIT_E; + } + } +#endif + if (side == CYASSL_CLIENT_END) { + Arc4SetKey(enc->arc4, keys->client_write_key, sz); + Arc4SetKey(dec->arc4, keys->server_write_key, sz); + } + else { + Arc4SetKey(enc->arc4, keys->server_write_key, sz); + Arc4SetKey(dec->arc4, keys->client_write_key, sz); + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef HAVE_HC128 + if (specs->bulk_cipher_algorithm == cyassl_hc128) { + int hcRet; + if (enc->hc128 == NULL) + enc->hc128 = + (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER); + if (enc->hc128 == NULL) + return MEMORY_E; + if (dec->hc128 == NULL) + dec->hc128 = + (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER); + if (dec->hc128 == NULL) + return MEMORY_E; + if (side == CYASSL_CLIENT_END) { + hcRet = Hc128_SetKey(enc->hc128, keys->client_write_key, + keys->client_write_IV); + if (hcRet != 0) return hcRet; + hcRet = Hc128_SetKey(dec->hc128, keys->server_write_key, + keys->server_write_IV); + if (hcRet != 0) return hcRet; + } + else { + hcRet = Hc128_SetKey(enc->hc128, keys->server_write_key, + keys->server_write_IV); + if (hcRet != 0) return hcRet; + hcRet = Hc128_SetKey(dec->hc128, keys->client_write_key, + keys->client_write_IV); + if (hcRet != 0) return hcRet; + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef BUILD_RABBIT + if (specs->bulk_cipher_algorithm == cyassl_rabbit) { + int rabRet; + if (enc->rabbit == NULL) + enc->rabbit = + (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER); + if (enc->rabbit == NULL) + return MEMORY_E; + if (dec->rabbit == NULL) + dec->rabbit = + (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER); + if (dec->rabbit == NULL) + return MEMORY_E; + if (side == CYASSL_CLIENT_END) { + rabRet = RabbitSetKey(enc->rabbit, keys->client_write_key, + keys->client_write_IV); + if (rabRet != 0) return rabRet; + rabRet = RabbitSetKey(dec->rabbit, keys->server_write_key, + keys->server_write_IV); + if (rabRet != 0) return rabRet; + } + else { + rabRet = RabbitSetKey(enc->rabbit, keys->server_write_key, + keys->server_write_IV); + if (rabRet != 0) return rabRet; + rabRet = RabbitSetKey(dec->rabbit, keys->client_write_key, + keys->client_write_IV); + if (rabRet != 0) return rabRet; + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef BUILD_DES3 + if (specs->bulk_cipher_algorithm == cyassl_triple_des) { + int desRet = 0; + + if (enc->des3 == NULL) + enc->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER); + if (enc->des3 == NULL) + return MEMORY_E; + if (dec->des3 == NULL) + dec->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER); + if (dec->des3 == NULL) + return MEMORY_E; +#ifdef HAVE_CAVIUM + if (devId != NO_CAVIUM_DEVICE) { + if (Des3_InitCavium(enc->des3, devId) != 0) { + CYASSL_MSG("Des3_InitCavium failed in SetKeys"); + return CAVIUM_INIT_E; + } + if (Des3_InitCavium(dec->des3, devId) != 0) { + CYASSL_MSG("Des3_InitCavium failed in SetKeys"); + return CAVIUM_INIT_E; + } + } +#endif + if (side == CYASSL_CLIENT_END) { + desRet = Des3_SetKey(enc->des3, keys->client_write_key, + keys->client_write_IV, DES_ENCRYPTION); + if (desRet != 0) + return desRet; + desRet = Des3_SetKey(dec->des3, keys->server_write_key, + keys->server_write_IV, DES_DECRYPTION); + if (desRet != 0) + return desRet; + } + else { + desRet = Des3_SetKey(enc->des3, keys->server_write_key, + keys->server_write_IV, DES_ENCRYPTION); + if (desRet != 0) + return desRet; + desRet = Des3_SetKey(dec->des3, keys->client_write_key, + keys->client_write_IV, DES_DECRYPTION); + if (desRet != 0) + return desRet; + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef BUILD_AES + if (specs->bulk_cipher_algorithm == cyassl_aes) { + int aesRet = 0; + + if (enc->aes == NULL) + enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (enc->aes == NULL) + return MEMORY_E; + if (dec->aes == NULL) + dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (dec->aes == NULL) + return MEMORY_E; +#ifdef HAVE_CAVIUM + if (devId != NO_CAVIUM_DEVICE) { + if (AesInitCavium(enc->aes, devId) != 0) { + CYASSL_MSG("AesInitCavium failed in SetKeys"); + return CAVIUM_INIT_E; + } + if (AesInitCavium(dec->aes, devId) != 0) { + CYASSL_MSG("AesInitCavium failed in SetKeys"); + return CAVIUM_INIT_E; + } + } +#endif + if (side == CYASSL_CLIENT_END) { + aesRet = AesSetKey(enc->aes, keys->client_write_key, + specs->key_size, keys->client_write_IV, + AES_ENCRYPTION); + if (aesRet != 0) + return aesRet; + aesRet = AesSetKey(dec->aes, keys->server_write_key, + specs->key_size, keys->server_write_IV, + AES_DECRYPTION); + if (aesRet != 0) + return aesRet; + } + else { + aesRet = AesSetKey(enc->aes, keys->server_write_key, + specs->key_size, keys->server_write_IV, + AES_ENCRYPTION); + if (aesRet != 0) + return aesRet; + aesRet = AesSetKey(dec->aes, keys->client_write_key, + specs->key_size, keys->client_write_IV, + AES_DECRYPTION); + if (aesRet != 0) + return aesRet; + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef BUILD_AESGCM + if (specs->bulk_cipher_algorithm == cyassl_aes_gcm) { + if (enc->aes == NULL) + enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (enc->aes == NULL) + return MEMORY_E; + if (dec->aes == NULL) + dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (dec->aes == NULL) + return MEMORY_E; + + if (side == CYASSL_CLIENT_END) { + AesGcmSetKey(enc->aes, keys->client_write_key, specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, + keys->client_write_IV, AEAD_IMP_IV_SZ); + AesGcmSetKey(dec->aes, keys->server_write_key, specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, + keys->server_write_IV, AEAD_IMP_IV_SZ); + } + else { + AesGcmSetKey(enc->aes, keys->server_write_key, specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, + keys->server_write_IV, AEAD_IMP_IV_SZ); + AesGcmSetKey(dec->aes, keys->client_write_key, specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, + keys->client_write_IV, AEAD_IMP_IV_SZ); + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef HAVE_AESCCM + if (specs->bulk_cipher_algorithm == cyassl_aes_ccm) { + if (enc->aes == NULL) + enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (enc->aes == NULL) + return MEMORY_E; + if (dec->aes == NULL) + dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER); + if (dec->aes == NULL) + return MEMORY_E; + + if (side == CYASSL_CLIENT_END) { + AesCcmSetKey(enc->aes, keys->client_write_key, specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, + keys->client_write_IV, AEAD_IMP_IV_SZ); + AesCcmSetKey(dec->aes, keys->server_write_key, specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, + keys->server_write_IV, AEAD_IMP_IV_SZ); + } + else { + AesCcmSetKey(enc->aes, keys->server_write_key, specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, + keys->server_write_IV, AEAD_IMP_IV_SZ); + AesCcmSetKey(dec->aes, keys->client_write_key, specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, + keys->client_write_IV, AEAD_IMP_IV_SZ); + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef HAVE_CAMELLIA + if (specs->bulk_cipher_algorithm == cyassl_camellia) { + int camRet; + + if (enc->cam == NULL) + enc->cam = + (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER); + if (enc->cam == NULL) + return MEMORY_E; + + if (dec->cam == NULL) + dec->cam = + (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER); + if (dec->cam == NULL) + return MEMORY_E; + + if (side == CYASSL_CLIENT_END) { + camRet = CamelliaSetKey(enc->cam, keys->client_write_key, + specs->key_size, keys->client_write_IV); + if (camRet != 0) + return camRet; + + camRet = CamelliaSetKey(dec->cam, keys->server_write_key, + specs->key_size, keys->server_write_IV); + if (camRet != 0) + return camRet; + } + else { + camRet = CamelliaSetKey(enc->cam, keys->server_write_key, + specs->key_size, keys->server_write_IV); + if (camRet != 0) + return camRet; + + camRet = CamelliaSetKey(dec->cam, keys->client_write_key, + specs->key_size, keys->client_write_IV); + if (camRet != 0) + return camRet; + } + enc->setup = 1; + dec->setup = 1; + } +#endif + +#ifdef HAVE_NULL_CIPHER + if (specs->bulk_cipher_algorithm == cyassl_cipher_null) { + enc->setup = 1; + dec->setup = 1; + } +#endif + + keys->sequence_number = 0; + keys->peer_sequence_number = 0; + keys->encryptionOn = 0; + (void)side; + (void)heap; + (void)enc; + (void)dec; + (void)specs; + (void)devId; + + return 0; +} + + +/* TLS can call too */ +int StoreKeys(CYASSL* ssl, const byte* keyData) +{ + int sz, i = 0; + int devId = NO_CAVIUM_DEVICE; + +#ifdef HAVE_CAVIUM + devId = ssl->devId; +#endif + + if (ssl->specs.cipher_type != aead) { + sz = ssl->specs.hash_size; + XMEMCPY(ssl->keys.client_write_MAC_secret,&keyData[i], sz); + i += sz; + XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); + i += sz; + } + sz = ssl->specs.key_size; + XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz); + i += sz; + XMEMCPY(ssl->keys.server_write_key, &keyData[i], sz); + i += sz; + + sz = ssl->specs.iv_size; + XMEMCPY(ssl->keys.client_write_IV, &keyData[i], sz); + i += sz; + XMEMCPY(ssl->keys.server_write_IV, &keyData[i], sz); + +#ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + /* Initialize the AES-GCM/CCM explicit IV to a zero. */ + XMEMSET(ssl->keys.aead_exp_IV, 0, AEAD_EXP_IV_SZ); + } +#endif + + return SetKeys(&ssl->encrypt, &ssl->decrypt, &ssl->keys, &ssl->specs, + ssl->options.side, ssl->heap, devId); +} + +#ifndef NO_OLD_TLS +int DeriveKeys(CYASSL* ssl) +{ + int length = 2 * ssl->specs.hash_size + + 2 * ssl->specs.key_size + + 2 * ssl->specs.iv_size; + int rounds = (length + MD5_DIGEST_SIZE - 1 ) / MD5_DIGEST_SIZE, i; + int ret = 0; + + byte shaOutput[SHA_DIGEST_SIZE]; + byte md5Input[SECRET_LEN + SHA_DIGEST_SIZE]; + byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; + + Md5 md5; + Sha sha; + + byte keyData[KEY_PREFIX * MD5_DIGEST_SIZE]; /* max size */ + + InitMd5(&md5); + ret = InitSha(&sha); + if (ret != 0) + return ret; + + XMEMCPY(md5Input, ssl->arrays->masterSecret, SECRET_LEN); + + for (i = 0; i < rounds; ++i) { + int j = i + 1; + int idx = j; + + if (!SetPrefix(shaInput, i)) { + return PREFIX_ERROR; + } + + XMEMCPY(shaInput + idx, ssl->arrays->masterSecret, SECRET_LEN); + idx += SECRET_LEN; + XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN); + idx += RAN_LEN; + XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN); + + ShaUpdate(&sha, shaInput, (word32)sizeof(shaInput) - KEY_PREFIX + j); + ShaFinal(&sha, shaOutput); + + XMEMCPY(&md5Input[SECRET_LEN], shaOutput, SHA_DIGEST_SIZE); + Md5Update(&md5, md5Input, sizeof(md5Input)); + Md5Final(&md5, keyData + i * MD5_DIGEST_SIZE); + } + + return StoreKeys(ssl, keyData); +} + + +static int CleanPreMaster(CYASSL* ssl) +{ + int i, ret, sz = ssl->arrays->preMasterSz; + + for (i = 0; i < sz; i++) + ssl->arrays->preMasterSecret[i] = 0; + + ret = RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, sz); + if (ret != 0) + return ret; + + for (i = 0; i < sz; i++) + ssl->arrays->preMasterSecret[i] = 0; + + return 0; +} + + +/* Create and store the master secret see page 32, 6.1 */ +static int MakeSslMasterSecret(CYASSL* ssl) +{ + byte shaOutput[SHA_DIGEST_SIZE]; + byte md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE]; + byte shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN]; + int i, ret; + word32 idx; + word32 pmsSz = ssl->arrays->preMasterSz; + + Md5 md5; + Sha sha; + +#ifdef SHOW_SECRETS + { + word32 j; + printf("pre master secret: "); + for (j = 0; j < pmsSz; j++) + printf("%02x", ssl->arrays->preMasterSecret[j]); + printf("\n"); + } +#endif + + InitMd5(&md5); + ret = InitSha(&sha); + if (ret != 0) + return ret; + + XMEMCPY(md5Input, ssl->arrays->preMasterSecret, pmsSz); + + for (i = 0; i < MASTER_ROUNDS; ++i) { + byte prefix[PREFIX]; + if (!SetPrefix(prefix, i)) { + return PREFIX_ERROR; + } + + idx = 0; + XMEMCPY(shaInput, prefix, i + 1); + idx += i + 1; + + XMEMCPY(shaInput + idx, ssl->arrays->preMasterSecret, pmsSz); + idx += pmsSz; + XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN); + idx += RAN_LEN; + XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN); + idx += RAN_LEN; + ShaUpdate(&sha, shaInput, idx); + ShaFinal(&sha, shaOutput); + + idx = pmsSz; /* preSz */ + XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE); + idx += SHA_DIGEST_SIZE; + Md5Update(&md5, md5Input, idx); + Md5Final(&md5, &ssl->arrays->masterSecret[i * MD5_DIGEST_SIZE]); + } + +#ifdef SHOW_SECRETS + { + word32 j; + printf("master secret: "); + for (j = 0; j < SECRET_LEN; j++) + printf("%02x", ssl->arrays->masterSecret[j]); + printf("\n"); + } +#endif + + ret = DeriveKeys(ssl); + if (ret != 0) { + /* always try to clean PreMaster */ + CleanPreMaster(ssl); + return ret; + } + + return CleanPreMaster(ssl); +} +#endif + + +/* Master wrapper, doesn't use SSL stack space in TLS mode */ +int MakeMasterSecret(CYASSL* ssl) +{ +#ifdef NO_OLD_TLS + return MakeTlsMasterSecret(ssl); +#elif !defined(NO_TLS) + if (ssl->options.tls) return MakeTlsMasterSecret(ssl); +#endif + +#ifndef NO_OLD_TLS + return MakeSslMasterSecret(ssl); +#endif +} + +