Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 +} + +