From a5529b124db0de6ce3257f66180e93297ed925c5 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 19 Dec 2014 09:56:51 -0700 Subject: [PATCH] moving over more files --- ctaocrypt/benchmark/include.am | 4 +- ctaocrypt/test/include.am | 4 +- cyassl/ssl.h | 3 +- wolfcrypt/src/asn.c | 7693 ++++++++++++++++++++++++++++++++ wolfcrypt/src/coding.c | 399 ++ wolfcrypt/src/ecc.c | 4837 ++++++++++++++++++++ wolfcrypt/src/error.c | 325 ++ wolfcrypt/src/hmac.c | 6 +- wolfcrypt/src/logging.c | 162 + wolfcrypt/src/memory.c | 183 + wolfcrypt/src/random.c | 2 +- wolfcrypt/src/rsa.c | 6 +- wolfcrypt/src/sha.c | 428 ++ wolfcrypt/src/sha256.c | 322 ++ wolfcrypt/src/tfm.c | 2538 +++++++++++ wolfssl/wolfcrypt/ecc.h | 108 +- wolfssl/wolfcrypt/hmac.h | 2 +- 17 files changed, 16957 insertions(+), 65 deletions(-) create mode 100644 wolfcrypt/src/asn.c create mode 100644 wolfcrypt/src/coding.c create mode 100644 wolfcrypt/src/ecc.c create mode 100644 wolfcrypt/src/error.c create mode 100644 wolfcrypt/src/logging.c create mode 100644 wolfcrypt/src/memory.c create mode 100644 wolfcrypt/src/sha.c create mode 100644 wolfcrypt/src/sha256.c create mode 100644 wolfcrypt/src/tfm.c diff --git a/ctaocrypt/benchmark/include.am b/ctaocrypt/benchmark/include.am index 47e7bf0c5..5ed36a5f5 100644 --- a/ctaocrypt/benchmark/include.am +++ b/ctaocrypt/benchmark/include.am @@ -3,8 +3,8 @@ noinst_PROGRAMS += ctaocrypt/benchmark/benchmark ctaocrypt_benchmark_benchmark_SOURCES = ctaocrypt/benchmark/benchmark.c -ctaocrypt_benchmark_benchmark_LDADD = src/libcyassl.la -ctaocrypt_benchmark_benchmark_DEPENDENCIES = src/libcyassl.la +ctaocrypt_benchmark_benchmark_LDADD = src/libwolfssl.la +ctaocrypt_benchmark_benchmark_DEPENDENCIES = src/libwolfssl.la EXTRA_DIST += ctaocrypt/benchmark/benchmark.sln EXTRA_DIST += ctaocrypt/benchmark/benchmark.vcproj DISTCLEANFILES+= ctaocrypt/benchmark/.libs/benchmark diff --git a/ctaocrypt/test/include.am b/ctaocrypt/test/include.am index d5c550bc3..740ba8562 100644 --- a/ctaocrypt/test/include.am +++ b/ctaocrypt/test/include.am @@ -3,8 +3,8 @@ noinst_PROGRAMS+= ctaocrypt/test/testctaocrypt ctaocrypt_test_testctaocrypt_SOURCES = ctaocrypt/test/test.c -ctaocrypt_test_testctaocrypt_LDADD = src/libcyassl.la -ctaocrypt_test_testctaocrypt_DEPENDENCIES = src/libcyassl.la +ctaocrypt_test_testctaocrypt_LDADD = src/libwolfssl.la +ctaocrypt_test_testctaocrypt_DEPENDENCIES = src/libwolfssl.la noinst_HEADERS += ctaocrypt/test/test.h EXTRA_DIST += ctaocrypt/test/test.sln EXTRA_DIST += ctaocrypt/test/test.vcproj diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 3eb128441..92b5401cb 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -361,6 +361,8 @@ #define CYASSL_SMALL_STACK #endif +#define WOLFSSL_ENTER(x) CYASSL_ENTER(x) /* @TODO*/ +#define WOLFSSL_BIT_SIZE CYASSL_BIT_SIZE /* @TODO*/ /* wrapper around macros until they are changed in cyassl code * needs investigation in regards to macros in fips */ @@ -389,7 +391,6 @@ /* for DH reverse compatibility */ #ifndef NO_DH - #define WOLFSSL_BIT_SIZE CYASSL_BIT_SIZE /* @TODO*/ #define InitDhKey wc_InitDhKey #define FreeDhKey wc_FreeDhKey #define DhGenerateKeyPair wc_DhGenerateKeyPair diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c new file mode 100644 index 000000000..437a7f61a --- /dev/null +++ b/wolfcrypt/src/asn.c @@ -0,0 +1,7693 @@ +/* asn.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL 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. + * + * wolfSSL 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 +#endif + + +/* compatability layer temporary */ +#include + + +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#ifndef NO_RC4 + #include +#endif + +#ifdef HAVE_NTRU + #include "ntru_crypto.h" +#endif + +#ifdef HAVE_ECC + #include +#endif + +#ifdef WOLFSSL_DEBUG_ENCODING + #ifdef FREESCALE_MQX + #include + #else + #include + #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 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 + #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) + #define XTIME(t1) mqx_time((t1)) + #define XGMTIME(c) mqx_gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#elif defined(WOLFSSL_MDK_ARM) + #if defined(WOLFSSL_MDK5) + #include "cmsis_os.h" + #else + #include + #endif + #undef RNG + #include "cyassl_MDK_ARM.h" + #undef RNG + #define RNG wolfSSL_RNG /*for avoiding name conflict in "stm32f2xx.h" */ + #define XTIME(tl) (0) + #define XGMTIME(c) wolfssl_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 facility */ + #include + #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 + + +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; +} + +/* CodeWarrior GCC toolchain only has gmtime_r(), no gmtime() */ +struct tm* mqx_gmtime(const time_t* clock) +{ + struct tm tmpTime; + + return gmtime_r(clock, &tmpTime); +} + +#endif /* FREESCALE_MQX */ + +#ifdef WOLFSSL_TIRTOS + +time_t XTIME(time_t * timer) +{ + time_t sec = 0; + + sec = (time_t) MYTIME_gettime(); + + if (timer != NULL) + *timer = sec; + + return sec; +} + +#endif /* WOLFSSL_TIRTOS */ + +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 */ + + +WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx) +{ + int length = 0; + word32 i = *inOutIdx; + byte b; + + *len = 0; /* default length */ + + if ( (i+1) > maxIdx) { /* for first read */ + WOLFSSL_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 */ + WOLFSSL_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 */ + WOLFSSL_MSG("GetLength value exceeds buffer length"); + return BUFFER_E; + } + + *inOutIdx = i; + if (length > 0) + *len = length; + + return length; +} + + +WOLFSSL_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; +} + + +WOLFSSL_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 */ +WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx, int* version) +{ + word32 idx = *inOutIdx; + + WOLFSSL_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; + + WOLFSSL_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; +} + + +WOLFSSL_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; +} + + +WOLFSSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) +{ + int length; + word32 i = *inOutIdx; + byte b; + *oid = 0; + + WOLFSSL_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 == WOLFSSL_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) +{ + int typeH; + int derivedLen; + int decryptionType; + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* key; +#else + byte key[MAX_KEY_SIZE]; +#endif + + 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; + } + +#ifdef WOLFSSL_SMALL_STACK + key = (byte*)XMALLOC(MAX_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (key == NULL) + return MEMORY_E; +#endif + + 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)) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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 { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ALGO_ID_E; + } + + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + ret = Des3_CbcDecrypt(&dec, input, input, length); + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + break; + } +#endif +#ifndef NO_RC4 + case RC4_TYPE: + { + Arc4 dec; + + Arc4SetKey(&dec, key, derivedLen); + Arc4Process(&dec, input, input, length); + break; + } +#endif + + default: +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ALGO_ID_E; + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + 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; +#ifdef WOLFSSL_SMALL_STACK + byte* salt = NULL; + byte* cbcIv = NULL; +#else + byte salt[MAX_SALT_SIZE]; + byte cbcIv[MAX_IV_SIZE]; +#endif + + 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; + +#ifdef WOLFSSL_SMALL_STACK + salt = (byte*)XMALLOC(MAX_SALT_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (salt == NULL) + return MEMORY_E; +#endif + + XMEMCPY(salt, &input[inOutIdx], saltSz); + inOutIdx += saltSz; + + if (GetShortInt(input, &inOutIdx, &iterations) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + +#ifdef WOLFSSL_SMALL_STACK + cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (cbcIv == NULL) { + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + if (version == PKCS5v2) { + /* get encryption algo */ + if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (CheckAlgoV2(oid, &id) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; /* PKCS v2 algo id error */ + } + + if (input[inOutIdx++] != ASN_OCTET_STRING) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (GetLength(input, &inOutIdx, &length, sz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + XMEMCPY(cbcIv, &input[inOutIdx], length); + inOutIdx += length; + } + + if (input[inOutIdx++] != ASN_OCTET_STRING) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (GetLength(input, &inOutIdx, &length, sz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id, + input + inOutIdx, length, version, cbcIv) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_INPUT_E; /* decrypt failure */ + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + 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; +} + +int RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e, word32 eSz, + RsaKey* key) +{ + if (n == NULL || e == NULL || key == NULL) + return BAD_FUNC_ARG; + + key->type = RSA_PUBLIC; + + if (mp_init(&key->n) != MP_OKAY) + return MP_INIT_E; + + if (mp_read_unsigned_bin(&key->n, n, nSz) != 0) { + mp_clear(&key->n); + return ASN_GETINT_E; + } + + if (mp_init(&key->e) != MP_OKAY) { + mp_clear(&key->n); + return MP_INIT_E; + } + + if (mp_read_unsigned_bin(&key->e, e, eSz) != 0) { + mp_clear(&key->n); + mp_clear(&key->e); + return ASN_GETINT_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; +} + + +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 /* 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->subjectCNEnc = CTC_UTF8; + 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 WOLFSSL_CERT_GEN + cert->subjectSN = 0; + cert->subjectSNLen = 0; + cert->subjectSNEnc = CTC_UTF8; + cert->subjectC = 0; + cert->subjectCLen = 0; + cert->subjectCEnc = CTC_PRINTABLE; + cert->subjectL = 0; + cert->subjectLLen = 0; + cert->subjectLEnc = CTC_UTF8; + cert->subjectST = 0; + cert->subjectSTLen = 0; + cert->subjectSTEnc = CTC_UTF8; + cert->subjectO = 0; + cert->subjectOLen = 0; + cert->subjectOEnc = CTC_UTF8; + cert->subjectOU = 0; + cert->subjectOULen = 0; + cert->subjectOUEnc = CTC_UTF8; + cert->subjectEmail = 0; + cert->subjectEmailLen = 0; +#endif /* WOLFSSL_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 WOLFSSL_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 /* WOLFSSL_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 WOLFSSL_SEP + XFREE(cert->deviceType, cert->heap, 0); + XFREE(cert->hwType, cert->heap, 0); + XFREE(cert->hwSerialNum, cert->heap, 0); +#endif /* WOLFSSL_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]; +#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH) + mp_int* mpi = NULL; +#else + mp_int stack_mpi; + mp_int* mpi = &stack_mpi; +#endif + + 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 defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH) + mpi = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (mpi == NULL) + return MEMORY_E; +#endif + + if (GetInt(mpi, cert->source, &cert->srcIdx, cert->maxIdx) < 0) { +#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH) + XFREE(mpi, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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) { + XMEMCPY(cert->serial, serialTmp, len); + cert->serialSz = len; + } + } + mp_clear(mpi); + +#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH) + XFREE(mpi, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + 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; + word32 rc; + word32 remaining = cert->maxIdx - cert->srcIdx; +#ifdef WOLFSSL_SMALL_STACK + byte* keyBlob = NULL; +#else + byte keyBlob[MAX_NTRU_KEY_SZ]; +#endif + rc = ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, + &keyLen, NULL, &next, &remaining); + if (rc != NTRU_OK) + return ASN_NTRU_KEY_E; + if (keyLen > MAX_NTRU_KEY_SZ) + return ASN_NTRU_KEY_E; + +#ifdef WOLFSSL_SMALL_STACK + keyBlob = (byte*)XMALLOC(MAX_NTRU_KEY_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (keyBlob == NULL) + return MEMORY_E; +#endif + + rc = ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, + &keyLen, keyBlob, &next, &remaining); + if (rc != NTRU_OK) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_NTRU_KEY_E; + } + + if ( (next - key) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MEMORY_E; + } + XMEMCPY(cert->publicKey, keyBlob, keyLen); + cert->pubKeyStored = 1; + cert->pubKeySize = keyLen; + +#ifdef WOLFSSL_SMALL_STACK + XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + 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 */ + + WOLFSSL_MSG("Getting Cert Name"); + + if (cert->source[cert->srcIdx] == ASN_OBJECT_ID) { + WOLFSSL_MSG("Trying optional prefix..."); + + if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0) + return ASN_PARSE_E; + + cert->srcIdx += length; + WOLFSSL_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) { + WOLFSSL_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++]; /* encoding */ + + 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=" */ + WOLFSSL_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; + cert->subjectCNEnc = b; + } + + 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 WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectSN = (char*)&cert->source[cert->srcIdx]; + cert->subjectSNLen = strLen; + cert->subjectSNEnc = b; + } + #endif /* WOLFSSL_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 WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectC = (char*)&cert->source[cert->srcIdx]; + cert->subjectCLen = strLen; + cert->subjectCEnc = b; + } + #endif /* WOLFSSL_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 WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectL = (char*)&cert->source[cert->srcIdx]; + cert->subjectLLen = strLen; + cert->subjectLEnc = b; + } + #endif /* WOLFSSL_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 WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectST = (char*)&cert->source[cert->srcIdx]; + cert->subjectSTLen = strLen; + cert->subjectSTEnc = b; + } + #endif /* WOLFSSL_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 WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectO = (char*)&cert->source[cert->srcIdx]; + cert->subjectOLen = strLen; + cert->subjectOEnc = b; + } + #endif /* WOLFSSL_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 WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectOU = (char*)&cert->source[cert->srcIdx]; + cert->subjectOULen = strLen; + cert->subjectOUEnc = b; + } + #endif /* WOLFSSL_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)) { + WOLFSSL_MSG("ASN name too big, skipping"); + tooBig = TRUE; + } + + if (email) { + if ( (14 + adv) > (int)(ASN_NAME_MAX - idx)) { + WOLFSSL_MSG("ASN name too big, skipping"); + tooBig = TRUE; + } + if (!tooBig) { + XMEMCPY(&full[idx], "/emailAddress=", 14); + idx += 14; + } + + #ifdef WOLFSSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectEmail = (char*)&cert->source[cert->srcIdx]; + cert->subjectEmailLen = adv; + } + #endif /* WOLFSSL_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) { + WOLFSSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + emailName->name = (char*)XMALLOC(adv + 1, + cert->heap, DYNAMIC_TYPE_ALTNAME); + if (emailName->name == NULL) { + WOLFSSL_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)) { + WOLFSSL_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(b,a); +} + + +/* 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; + } + + /* adjust tm_year, tm_mon */ + GetTime((int*)&certTime.tm_year, date, &i); certTime.tm_year -= 1900; + GetTime((int*)&certTime.tm_mon, date, &i); certTime.tm_mon -= 1; + GetTime((int*)&certTime.tm_mday, date, &i); + GetTime((int*)&certTime.tm_hour, date, &i); + GetTime((int*)&certTime.tm_min, date, &i); + GetTime((int*)&certTime.tm_sec, date, &i); + + if (date[i] != 'Z') { /* only Zulu supported for this profile */ + WOLFSSL_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; + + WOLFSSL_MSG("Got Cert Header"); + + if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID, + cert->maxIdx)) < 0) + return ret; + + WOLFSSL_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; + + WOLFSSL_MSG("Got Subject Name"); + + if ( (ret = GetKey(cert)) < 0) + return ret; + + WOLFSSL_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) * WOLFSSL_BIT_SIZE)) + break; + + return i; +} + + +WOLFSSL_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) * WOLFSSL_BIT_SIZE)); + i++; + } + } + + return i; +} + + +WOLFSSL_LOCAL word32 SetSequence(word32 len, byte* output) +{ + output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + +WOLFSSL_LOCAL word32 SetOctetString(word32 len, byte* output) +{ + output[0] = ASN_OCTET_STRING; + return SetLength(len, output + 1) + 1; +} + +/* Write a set header to output */ +WOLFSSL_LOCAL word32 SetSet(word32 len, byte* output) +{ + output[0] = ASN_SET | ASN_CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + +WOLFSSL_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; +} + +WOLFSSL_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(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_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 && WOLFSSL_CERT_GEN */ + + +WOLFSSL_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: + WOLFSSL_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: + WOLFSSL_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: + WOLFSSL_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: + WOLFSSL_MSG("Unknown Key Algo"); + return 0; + } + } + else { + WOLFSSL_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; +} + + +int GetCTC_HashOID(int type) +{ + switch (type) { +#ifdef WOLFSSL_MD2 + case MD2: + return MD2h; +#endif +#ifndef NO_MD5 + case MD5: + return MD5h; +#endif +#ifndef NO_SHA + case SHA: + return SHAh; +#endif +#ifndef NO_SHA256 + case SHA256: + return SHA256h; +#endif +#ifdef WOLFSSL_SHA384 + case SHA384: + return SHA384h; +#endif +#ifdef WOLFSSL_SHA512 + case SHA512: + return SHA512h; +#endif + default: + return 0; + }; +} + + +/* return true (1) or false (0) 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) +{ + int typeH = 0, digestSz = 0, ret = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* digest; +#else + byte digest[MAX_DIGEST_SIZE]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + digest = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (digest == NULL) + return 0; /* not confirmed */ +#endif + + (void)key; + (void)keySz; + (void)sig; + (void)sigSz; + (void)heap; + + switch (sigOID) { + #ifndef NO_MD5 + case CTC_MD5wRSA: + if (Md5Hash(buf, bufSz, digest) == 0) { + typeH = MD5h; + digestSz = MD5_DIGEST_SIZE; + } + break; + #endif + #if defined(WOLFSSL_MD2) + case CTC_MD2wRSA: + if (Md2Hash(buf, bufSz, digest) == 0) { + typeH = MD2h; + digestSz = MD2_DIGEST_SIZE; + } + break; + #endif + #ifndef NO_SHA + case CTC_SHAwRSA: + case CTC_SHAwDSA: + case CTC_SHAwECDSA: + if (ShaHash(buf, bufSz, digest) == 0) { + typeH = SHAh; + digestSz = SHA_DIGEST_SIZE; + } + break; + #endif + #ifndef NO_SHA256 + case CTC_SHA256wRSA: + case CTC_SHA256wECDSA: + if (Sha256Hash(buf, bufSz, digest) == 0) { + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + } + break; + #endif + #ifdef WOLFSSL_SHA512 + case CTC_SHA512wRSA: + case CTC_SHA512wECDSA: + if (Sha512Hash(buf, bufSz, digest) == 0) { + typeH = SHA512h; + digestSz = SHA512_DIGEST_SIZE; + } + break; + #endif + #ifdef WOLFSSL_SHA384 + case CTC_SHA384wRSA: + case CTC_SHA384wECDSA: + if (Sha384Hash(buf, bufSz, digest) == 0) { + typeH = SHA384h; + digestSz = SHA384_DIGEST_SIZE; + } + break; + #endif + default: + WOLFSSL_MSG("Verify Signautre has unsupported type"); + } + + if (typeH == 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return 0; /* not confirmed */ + } + + switch (keyOID) { + #ifndef NO_RSA + case RSAk: + { + word32 idx = 0; + int encodedSigSz, verifySz; + byte* out; +#ifdef WOLFSSL_SMALL_STACK + RsaKey* pubKey; + byte* plain; + byte* encodedSig; +#else + RsaKey pubKey[1]; + byte plain[MAX_ENCODED_SIG_SZ]; + byte encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + plain = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (pubKey == NULL || plain == NULL || encodedSig == NULL) { + WOLFSSL_MSG("Failed to allocate memory at ConfirmSignature"); + + if (pubKey) + XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (plain) + XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig) + XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + break; /* not confirmed */ + } +#endif + + if (sigSz > MAX_ENCODED_SIG_SZ) { + WOLFSSL_MSG("Verify Signautre is too big"); + } + else if (InitRsaKey(pubKey, heap) != 0) { + WOLFSSL_MSG("InitRsaKey failed"); + } + else if (RsaPublicKeyDecode(key, &idx, pubKey, keySz) < 0) { + WOLFSSL_MSG("ASN Key decode error RSA"); + } + else { + XMEMCPY(plain, sig, sigSz); + + if ((verifySz = RsaSSL_VerifyInline(plain, sigSz, &out, + pubKey)) < 0) { + WOLFSSL_MSG("Rsa SSL verify error"); + } + else { + /* make sure we're right justified */ + encodedSigSz = + EncodeSignature(encodedSig, digest, digestSz, typeH); + if (encodedSigSz != verifySz || + XMEMCMP(out, encodedSig, encodedSigSz) != 0) { + WOLFSSL_MSG("Rsa SSL verify match encode error"); + } + else + ret = 1; /* match */ + + #ifdef WOLFSSL_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 /* WOLFSSL_DEBUG_ENCODING */ + + } + + } + + FreeRsaKey(pubKey); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + break; + } + + #endif /* NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + { + int verify = 0; +#ifdef WOLFSSL_SMALL_STACK + ecc_key* pubKey; +#else + ecc_key pubKey[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + pubKey = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKey == NULL) { + WOLFSSL_MSG("Failed to allocate pubKey"); + break; /* not confirmed */ + } +#endif + + if (ecc_import_x963(key, keySz, pubKey) < 0) { + WOLFSSL_MSG("ASN Key import error ECC"); + } + else { + if (ecc_verify_hash(sig, sigSz, digest, digestSz, &verify, + pubKey) != 0) { + WOLFSSL_MSG("ECC verify hash error"); + } + else if (1 != verify) { + WOLFSSL_MSG("ECC Verify didn't match"); + } else + ret = 1; /* match */ + + ecc_free(pubKey); + } +#ifdef WOLFSSL_SMALL_STACK + XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + break; + } + #endif /* HAVE_ECC */ + default: + WOLFSSL_MSG("Verify Key type unknown"); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +#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; + + WOLFSSL_ENTER("DecodeAltNames"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_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) { + WOLFSSL_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) { + WOLFSSL_MSG("\tOut of Memory"); + return ASN_PARSE_E; + } + + dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (dnsEntry->name == NULL) { + WOLFSSL_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) { + WOLFSSL_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) { + WOLFSSL_MSG("\tOut of Memory"); + return ASN_PARSE_E; + } + + emailEntry->name = (char*)XMALLOC(strLen + 1, cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (emailEntry->name == NULL) { + WOLFSSL_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 WOLFSSL_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) { + WOLFSSL_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) { + WOLFSSL_MSG("\tbad OID"); + return ASN_PARSE_E; + } + + if (oid != HW_NAME_OID) { + WOLFSSL_MSG("\tincorrect OID"); + return ASN_PARSE_E; + } + + if (input[idx++] != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { + WOLFSSL_MSG("\twrong type"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + WOLFSSL_MSG("\tfail: str len"); + return ASN_PARSE_E; + } + + if (GetSequence(input, &idx, &strLen, sz) < 0) { + WOLFSSL_MSG("\tBad Sequence"); + return ASN_PARSE_E; + } + + if (input[idx++] != ASN_OBJECT_ID) { + WOLFSSL_MSG("\texpected OID"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + WOLFSSL_MSG("\tfailed: str len"); + return ASN_PARSE_E; + } + + cert->hwType = (byte*)XMALLOC(strLen, cert->heap, 0); + if (cert->hwType == NULL) { + WOLFSSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + + XMEMCPY(cert->hwType, &input[idx], strLen); + cert->hwTypeSz = strLen; + idx += strLen; + + if (input[idx++] != ASN_OCTET_STRING) { + WOLFSSL_MSG("\texpected Octet String"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + WOLFSSL_MSG("\tfailed: str len"); + return ASN_PARSE_E; + } + + cert->hwSerialNum = (byte*)XMALLOC(strLen + 1, cert->heap, 0); + if (cert->hwSerialNum == NULL) { + WOLFSSL_MSG("\tOut of Memory"); + return MEMORY_E; + } + + XMEMCPY(cert->hwSerialNum, &input[idx], strLen); + cert->hwSerialNum[strLen] = '\0'; + cert->hwSerialNumSz = strLen; + idx += strLen; + } +#endif /* WOLFSSL_SEP */ + else { + int strLen; + word32 lenStartIdx = idx; + + WOLFSSL_MSG("\tUnsupported name type, skipping"); + + if (GetLength(input, &idx, &strLen, sz) < 0) { + WOLFSSL_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; + + WOLFSSL_ENTER("DecodeBasicCaConstraint"); + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_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) + { + WOLFSSL_MSG("\tfail: constraint not BOOLEAN"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) + { + WOLFSSL_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) { + WOLFSSL_MSG("\tfail: pathlen not INTEGER"); + return ASN_PARSE_E; + } + + if (input[idx++] != 1) { + WOLFSSL_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; + + WOLFSSL_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) + { + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_ENTER("DecodeAuthKeyId"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE\n"); + return ASN_PARSE_E; + } + + if (input[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) { + WOLFSSL_MSG("\tinfo: OPTIONAL item 0, not available\n"); + return 0; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_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; + + WOLFSSL_ENTER("DecodeSubjKeyId"); + + if (input[idx++] != ASN_OCTET_STRING) { + WOLFSSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_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; + WOLFSSL_ENTER("DecodeKeyUsage"); + + if (input[idx++] != ASN_BIT_STRING) { + WOLFSSL_MSG("\tfail: key usage expected bit string"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_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; + + WOLFSSL_ENTER("DecodeExtKeyUsage"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_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) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + nameIdx = idx; + b = input[nameIdx++]; + if (GetLength(input, &nameIdx, &strLength, sz) <= 0) { + WOLFSSL_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) { + WOLFSSL_MSG("allocate error"); + return MEMORY_E; + } + + entry->name = (char*)XMALLOC(strLength, heap, DYNAMIC_TYPE_ALTNAME); + if (entry->name == NULL) { + WOLFSSL_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; + + WOLFSSL_ENTER("DecodeNameConstraints"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_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) { + WOLFSSL_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 { + WOLFSSL_MSG("\tinvalid subtree"); + return ASN_PARSE_E; + } + + DecodeSubtree(input + idx, length, subtree, cert->heap); + + idx += length; + } + + return 0; +} +#endif /* IGNORE_NAME_CONSTRAINTS */ + + +#ifdef WOLFSSL_SEP + static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert) + { + word32 idx = 0; + int length = 0; + + WOLFSSL_ENTER("DecodeCertPolicy"); + + /* Unwrap certificatePolicies */ + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (input[idx++] != ASN_OBJECT_ID) { + WOLFSSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_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) { + WOLFSSL_MSG("\tCouldn't alloc memory for deviceType"); + return MEMORY_E; + } + cert->deviceTypeSz = length; + XMEMCPY(cert->deviceType, input + idx, length); + } + + WOLFSSL_LEAVE("DecodeCertPolicy", 0); + return 0; + } +#endif /* WOLFSSL_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; + + WOLFSSL_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) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + oid = 0; + if (GetObjectId(input, &idx, &oid, sz) < 0) { + WOLFSSL_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) { + WOLFSSL_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) { + WOLFSSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_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: + WOLFSSL_MSG("Certificate Policy extension not supported yet."); + #ifdef WOLFSSL_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: + WOLFSSL_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 + WOLFSSL_LOCAL Signer* GetCA(void* signers, byte* hash); + #ifndef NO_SKID + WOLFSSL_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; + } + + WOLFSSL_MSG("Parsed Past Key"); + + if (cert->srcIdx < cert->sigIndex) { + #ifndef ALLOW_V1_EXTENSIONS + if (cert->version < 2) { + WOLFSSL_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 */ + WOLFSSL_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)) { + WOLFSSL_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)) { + WOLFSSL_MSG("Confirm name constraint failed"); + return ASN_NAME_INVALID_E; + } +#endif /* IGNORE_NAME_CONSTRAINTS */ + } + else { + /* no signer */ + WOLFSSL_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; + } +} + + +WOLFSSL_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; +} + + +WOLFSSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output) +{ + int result = 0; + + WOLFSSL_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(WOLFSSL_KEY_GEN) || defined(WOLFSSL_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) +{ +#ifdef WOLFSSL_SMALL_STACK + char* header = NULL; + char* footer = NULL; +#else + char header[80]; + char footer[80]; +#endif + + int headerLen = 80; + int footerLen = 80; + int i; + int err; + int outLen; /* return length or error */ + + if (der == output) /* no in place conversion */ + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + header = (char*)XMALLOC(headerLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (header == NULL) + return MEMORY_E; + + footer = (char*)XMALLOC(footerLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (footer == NULL) { + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + if (type == CERT_TYPE) { + XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", headerLen); + XSTRNCPY(footer, "-----END CERTIFICATE-----\n", footerLen); + } + else if (type == PRIVATEKEY_TYPE) { + XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", headerLen); + XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n", footerLen); + } + #ifdef HAVE_ECC + else if (type == ECC_PRIVATEKEY_TYPE) { + XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----\n", headerLen); + XSTRNCPY(footer, "-----END EC PRIVATE KEY-----\n", footerLen); + } + #endif + #ifdef WOLFSSL_CERT_REQ + else if (type == CERTREQ_TYPE) + { + XSTRNCPY(header, + "-----BEGIN CERTIFICATE REQUEST-----\n", headerLen); + XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----\n", footerLen); + } + #endif + else { +#ifdef WOLFSSL_SMALL_STACK + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BAD_FUNC_ARG; + } + + headerLen = (int)XSTRLEN(header); + footerLen = (int)XSTRLEN(footer); + + if (!der || !output) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BAD_FUNC_ARG; + } + + /* don't even try if outSz too short */ + if (outSz < headerLen + footerLen + derSz) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BAD_FUNC_ARG; + } + + /* header */ + XMEMCPY(output, header, headerLen); + i = headerLen; + +#ifdef WOLFSSL_SMALL_STACK + XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + /* body */ + outLen = outSz - (headerLen + footerLen); /* input to Base64_Encode */ + if ( (err = Base64_Encode(der, derSz, output + i, (word32*)&outLen)) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return err; + } + i += outLen; + + /* footer */ + if ( (i + footerLen) > (int)outSz) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BAD_FUNC_ARG; + } + XMEMCPY(output + i, footer, footerLen); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return outLen + headerLen + footerLen; +} + + +#endif /* WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN */ + + +#if defined(WOLFSSL_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 /* WOLFSSL_KEY_GEN && !NO_RSA */ + + +#if defined(WOLFSSL_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 WOLFSSL_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.countryEnc = CTC_PRINTABLE; + cert->issuer.state[0] = '\0'; + cert->issuer.stateEnc = CTC_UTF8; + cert->issuer.locality[0] = '\0'; + cert->issuer.localityEnc = CTC_UTF8; + cert->issuer.sur[0] = '\0'; + cert->issuer.surEnc = CTC_UTF8; + cert->issuer.org[0] = '\0'; + cert->issuer.orgEnc = CTC_UTF8; + cert->issuer.unit[0] = '\0'; + cert->issuer.unitEnc = CTC_UTF8; + cert->issuer.commonName[0] = '\0'; + cert->issuer.commonNameEnc = CTC_UTF8; + cert->issuer.email[0] = '\0'; + + cert->subject.country[0] = '\0'; + cert->subject.countryEnc = CTC_PRINTABLE; + cert->subject.state[0] = '\0'; + cert->subject.stateEnc = CTC_UTF8; + cert->subject.locality[0] = '\0'; + cert->subject.localityEnc = CTC_UTF8; + cert->subject.sur[0] = '\0'; + cert->subject.surEnc = CTC_UTF8; + cert->subject.org[0] = '\0'; + cert->subject.orgEnc = CTC_UTF8; + cert->subject.unit[0] = '\0'; + cert->subject.unitEnc = CTC_UTF8; + cert->subject.commonName[0] = '\0'; + cert->subject.commonNameEnc = CTC_UTF8; + cert->subject.email[0] = '\0'; + +#ifdef WOLFSSL_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 WOLFSSL_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 WOLFSSL_CERT_REQ + int attribSz; +#endif +} DerCert; + + +#ifdef WOLFSSL_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 /* WOLFSSL_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 len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ + int algoSz; + int curveSz; + int lenSz; + int idx; + word32 pubSz = ECC_BUFSIZE; +#ifdef WOLFSSL_SMALL_STACK + byte* algo = NULL; + byte* curve = NULL; + byte* pub = NULL; +#else + byte algo[MAX_ALGO_SZ]; + byte curve[MAX_ALGO_SZ]; + byte pub[ECC_BUFSIZE]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + pub = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pub == NULL) + return MEMORY_E; +#endif + + int ret = ecc_export_x963(key, pub, &pubSz); + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + +#ifdef WOLFSSL_SMALL_STACK + curve = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (curve == NULL) { + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + /* headers */ + curveSz = SetCurve(key, curve); + if (curveSz <= 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return curveSz; + } + +#ifdef WOLFSSL_SMALL_STACK + algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (algo == NULL) { + XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + 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; + +#ifdef WOLFSSL_SMALL_STACK + XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return idx; +} + + +#endif /* HAVE_ECC */ + + +/* Write a public RSA key to output */ +static int SetRsaPublicKey(byte* output, RsaKey* key) +{ +#ifdef WOLFSSL_SMALL_STACK + byte* n = NULL; + byte* e = NULL; + byte* algo = NULL; +#else + byte n[MAX_RSA_INT_SZ]; + byte e[MAX_RSA_E_SZ]; + byte algo[MAX_ALGO_SZ]; +#endif + 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 */ +#ifdef WOLFSSL_SMALL_STACK + n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (n == NULL) + return MEMORY_E; +#endif + + 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) < MAX_RSA_INT_SZ) { + if (leadingBit) + n[nSz] = 0; + err = mp_to_unsigned_bin(&key->n, n + nSz + leadingBit); + if (err == MP_OKAY) + nSz += rawLen; + else { +#ifdef WOLFSSL_SMALL_STACK + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MP_TO_E; + } + } + else { +#ifdef WOLFSSL_SMALL_STACK + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BUFFER_E; + } + + /* e */ +#ifdef WOLFSSL_SMALL_STACK + e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (e == NULL) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MEMORY_E; + } +#endif + + 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) < MAX_RSA_E_SZ) { + if (leadingBit) + e[eSz] = 0; + err = mp_to_unsigned_bin(&key->e, e + eSz + leadingBit); + if (err == MP_OKAY) + eSz += rawLen; + else { +#ifdef WOLFSSL_SMALL_STACK + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MP_TO_E; + } + } + else { +#ifdef WOLFSSL_SMALL_STACK + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BUFFER_E; + } + +#ifdef WOLFSSL_SMALL_STACK + algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (algo == NULL) { + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + /* 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; + +#ifdef WOLFSSL_SMALL_STACK + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + 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 WOLFSSL_ALT_NAMES + +/* Copy Dates from cert, return bytes written */ +static int CopyValidity(byte* output, Cert* cert) +{ + int seqSz; + + WOLFSSL_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 Which Name Encoding from index */ +static char GetNameType(CertName* name, int idx) +{ + switch (idx) { + case 0: + return name->countryEnc; + + case 1: + return name->stateEnc; + + case 2: + return name->localityEnc; + + case 3: + return name->surEnc; + + case 4: + return name->orgEnc; + + case 5: + return name->unitEnc; + + case 6: + return name->commonNameEnc; + + 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; +#ifdef WOLFSSL_SMALL_STACK + EncodedName* names = NULL; +#else + EncodedName names[NAME_ENTRIES]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + names = (EncodedName*)XMALLOC(sizeof(EncodedName) * NAME_ENTRIES, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (names == NULL) + return MEMORY_E; +#endif + + 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)) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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 */ + names[i].encoded[idx++] = GetNameType(name, i); + } + /* 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) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + 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; + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + 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 = ntru_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 = ntru_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 WOLFSSL_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 WOLFSSL_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) +{ + int encSigSz, digestSz, typeH = 0, ret = 0; + byte digest[SHA256_DIGEST_SIZE]; /* max size */ +#ifdef WOLFSSL_SMALL_STACK + byte* encSig; +#else + byte encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ]; +#endif + + (void)digest; + (void)digestSz; + (void)encSig; + (void)encSigSz; + (void)typeH; + + (void)buffer; + (void)sz; + (void)sig; + (void)sigSz; + (void)rsaKey; + (void)eccKey; + (void)rng; + + switch (sigAlgoType) { + #ifndef NO_MD5 + case CTC_MD5wRSA: + if ((ret = Md5Hash(buffer, sz, digest)) == 0) { + typeH = MD5h; + digestSz = MD5_DIGEST_SIZE; + } + break; + #endif + #ifndef NO_SHA + case CTC_SHAwRSA: + case CTC_SHAwECDSA: + if ((ret = ShaHash(buffer, sz, digest)) == 0) { + typeH = SHAh; + digestSz = SHA_DIGEST_SIZE; + } + break; + #endif + #ifndef NO_SHA256 + case CTC_SHA256wRSA: + case CTC_SHA256wECDSA: + if ((ret = Sha256Hash(buffer, sz, digest)) == 0) { + typeH = SHA256h; + digestSz = SHA256_DIGEST_SIZE; + } + break; + #endif + default: + WOLFSSL_MSG("MakeSignautre called with unsupported type"); + ret = ALGO_ID_E; + } + + if (ret != 0) + return ret; + +#ifdef WOLFSSL_SMALL_STACK + encSig = (byte*)XMALLOC(MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (encSig == NULL) + return MEMORY_E; +#endif + + ret = ALGO_ID_E; + +#ifndef NO_RSA + if (rsaKey) { + /* signature */ + encSigSz = EncodeSignature(encSig, digest, digestSz, typeH); + ret = RsaSSL_Sign(encSig, encSigSz, sig, sigSz, rsaKey, rng); + } +#endif + +#ifdef HAVE_ECC + if (!rsaKey && eccKey) { + word32 outSz = sigSz; + ret = ecc_sign_hash(digest, digestSz, sig, &outSz, rng, eccKey); + + if (ret == 0) + ret = outSz; + } +#endif + +#ifdef WOLFSSL_SMALL_STACK + XFREE(encSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +/* 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) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + DerCert* der; +#else + DerCert der[1]; +#endif + + cert->keyType = eccKey ? ECC_KEY : (rsaKey ? RSA_KEY : NTRU_KEY); + +#ifdef WOLFSSL_SMALL_STACK + der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) + return MEMORY_E; +#endif + + ret = EncodeCert(cert, der, rsaKey, eccKey, rng, ntruKey, ntruSz); + + if (ret == 0) { + if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) + ret = BUFFER_E; + else + ret = cert->bodySz = WriteCertBody(der, derBuffer); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +/* 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 WOLFSSL_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) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + DerCert* der; +#else + DerCert der[1]; +#endif + + cert->keyType = eccKey ? ECC_KEY : RSA_KEY; + +#ifdef WOLFSSL_SMALL_STACK + der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) + return MEMORY_E; +#endif + + ret = EncodeCertReq(cert, der, rsaKey, eccKey); + + if (ret == 0) { + if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) + ret = BUFFER_E; + else + ret = cert->bodySz = WriteCertReqBody(der, derBuffer); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#endif /* WOLFSSL_CERT_REQ */ + + +int SignCert(int requestSz, int sType, byte* buffer, word32 buffSz, + RsaKey* rsaKey, ecc_key* eccKey, RNG* rng) +{ + int sigSz; +#ifdef WOLFSSL_SMALL_STACK + byte* sig; +#else + byte sig[MAX_ENCODED_SIG_SZ]; +#endif + + if (requestSz < 0) + return requestSz; + +#ifdef WOLFSSL_SMALL_STACK + sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sig == NULL) + return MEMORY_E; +#endif + + sigSz = MakeSignature(buffer, requestSz, sig, MAX_ENCODED_SIG_SZ, rsaKey, + eccKey, rng, sType); + + if (sigSz >= 0) { + if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz) + sigSz = BUFFER_E; + else + sigSz = AddSignature(buffer, requestSz, sig, sigSz, sType); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return sigSz; +} + + +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 WOLFSSL_ALT_NAMES + +/* Set Alt Names from der cert, return 0 on success */ +static int SetAltNamesFromCert(Cert* cert, const byte* der, int derSz) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* decoded; +#else + DecodedCert decoded[1]; +#endif + + if (derSz < 0) + return derSz; + +#ifdef WOLFSSL_SMALL_STACK + decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (decoded == NULL) + return MEMORY_E; +#endif + + InitDecodedCert(decoded, (byte*)der, derSz, 0); + ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) { + WOLFSSL_MSG("ParseCertRelative error"); + } + else if (decoded->extensions) { + byte b; + int length; + word32 maxExtensionsIdx; + + decoded->srcIdx = decoded->extensionsIdx; + b = decoded->source[decoded->srcIdx++]; + + if (b != ASN_EXTENSIONS) { + ret = ASN_PARSE_E; + } + else if (GetLength(decoded->source, &decoded->srcIdx, &length, + decoded->maxIdx) < 0) { + ret = ASN_PARSE_E; + } + else if (GetSequence(decoded->source, &decoded->srcIdx, &length, + decoded->maxIdx) < 0) { + ret = ASN_PARSE_E; + } + else { + 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) { + ret = ASN_PARSE_E; + break; + } + + tmpIdx = decoded->srcIdx; + decoded->srcIdx = startIdx; + + if (GetAlgoId(decoded->source, &decoded->srcIdx, &oid, + decoded->maxIdx) < 0) { + ret = ASN_PARSE_E; + break; + } + + 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; + WOLFSSL_MSG("AltNames extensions too big"); + ret = ALT_NAME_E; + break; + } + } + decoded->srcIdx = tmpIdx + length; + } + } + } + + FreeDecodedCert(decoded); +#ifdef WOLFSSL_SMALL_STACK + XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret < 0 ? ret : 0; +} + + +/* Set Dates from der cert, return 0 on success */ +static int SetDatesFromCert(Cert* cert, const byte* der, int derSz) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* decoded; +#else + DecodedCert decoded[1]; +#endif + + WOLFSSL_ENTER("SetDatesFromCert"); + if (derSz < 0) + return derSz; + +#ifdef WOLFSSL_SMALL_STACK + decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (decoded == NULL) + return MEMORY_E; +#endif + + InitDecodedCert(decoded, (byte*)der, derSz, 0); + ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) { + WOLFSSL_MSG("ParseCertRelative error"); + } + else if (decoded->beforeDate == NULL || decoded->afterDate == NULL) { + WOLFSSL_MSG("Couldn't extract dates"); + ret = -1; + } + else if (decoded->beforeDateLen > MAX_DATE_SIZE || + decoded->afterDateLen > MAX_DATE_SIZE) { + WOLFSSL_MSG("Bad date size"); + ret = -1; + } + else { + XMEMCPY(cert->beforeDate, decoded->beforeDate, decoded->beforeDateLen); + XMEMCPY(cert->afterDate, decoded->afterDate, decoded->afterDateLen); + + cert->beforeDateSz = decoded->beforeDateLen; + cert->afterDateSz = decoded->afterDateLen; + } + + FreeDecodedCert(decoded); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret < 0 ? ret : 0; +} + + +#endif /* WOLFSSL_ALT_NAMES && !NO_RSA */ + + +/* Set cn name from der buffer, return 0 on success */ +static int SetNameFromCert(CertName* cn, const byte* der, int derSz) +{ + int ret, sz; +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* decoded; +#else + DecodedCert decoded[1]; +#endif + + if (derSz < 0) + return derSz; + +#ifdef WOLFSSL_SMALL_STACK + decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (decoded == NULL) + return MEMORY_E; +#endif + + InitDecodedCert(decoded, (byte*)der, derSz, 0); + ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) { + WOLFSSL_MSG("ParseCertRelative error"); + } + else { + 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; + cn->commonNameEnc = decoded->subjectCNEnc; + } + 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; + cn->countryEnc = decoded->subjectCEnc; + } + 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; + cn->stateEnc = decoded->subjectSTEnc; + } + 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; + cn->localityEnc = decoded->subjectLEnc; + } + 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; + cn->orgEnc = decoded->subjectOEnc; + } + 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; + cn->unitEnc = decoded->subjectOUEnc; + } + 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; + cn->surEnc = decoded->subjectSNEnc; + } + 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); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret < 0 ? ret : 0; +} + + +#ifndef NO_FILESYSTEM + +/* 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) { + WOLFSSL_MSG("SetIssuer OOF Problem"); + return MEMORY_E; + } + derSz = wolfSSL_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) { + WOLFSSL_MSG("SetSubject OOF Problem"); + return MEMORY_E; + } + derSz = wolfSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF); + ret = SetNameFromCert(&cert->subject, der, derSz); + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + + return ret; +} + + +#ifdef WOLFSSL_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) { + WOLFSSL_MSG("SetAltNames OOF Problem"); + return MEMORY_E; + } + derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF); + ret = SetAltNamesFromCert(cert, der, derSz); + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + + return ret; +} + +#endif /* WOLFSSL_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 WOLFSSL_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 /* WOLFSSL_ALT_NAMES */ + +#endif /* WOLFSSL_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; + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* priv; + byte* pub; +#else + byte priv[ECC_MAXSIZE]; + byte pub[ECC_MAXSIZE * 2 + 1]; /* public key has two parts plus header */ +#endif + + 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; + + if (length > ECC_MAXSIZE) + return BUFFER_E; + +#ifdef WOLFSSL_SMALL_STACK + priv = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (priv == NULL) + return MEMORY_E; + + pub = (byte*)XMALLOC(ECC_MAXSIZE * 2 + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pub == NULL) { + XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + /* 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) + ret = ASN_PARSE_E; + else { + /* object id */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != ASN_OBJECT_ID) { + ret = ASN_OBJECT_ID_E; + } + else if (GetLength(input, inOutIdx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + else { + while(length--) { + oid += input[*inOutIdx]; + *inOutIdx += 1; + } + if (CheckCurve(oid) < 0) + ret = ECC_CURVE_OID_E; + } + } + } + + if (ret == 0) { + /* prefix 1 */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != ECC_PREFIX_1) { + ret = ASN_ECC_KEY_E; + } + else if (GetLength(input, inOutIdx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + else { + /* key header */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != ASN_BIT_STRING) { + ret = ASN_BITSTR_E; + } + else if (GetLength(input, inOutIdx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + else { + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != 0x00) { + ret = ASN_EXPECT_0_E; + } + else { + /* pub key */ + pubSz = length - 1; /* null prefix */ + if (pubSz < (ECC_MAXSIZE*2 + 1)) { + XMEMCPY(pub, &input[*inOutIdx], pubSz); + *inOutIdx += length; + ret = ecc_import_private_key(priv, privSz, pub, pubSz, + key); + } else + ret = BUFFER_E; + } + } + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +#ifdef WOLFSSL_KEY_GEN + +/* Write a Private ecc key to DER format, length on success else < 0 */ +int EccKeyToDer(ecc_key* key, byte* output, word32 inLen) +{ + byte curve[MAX_ALGO_SZ]; + byte ver[MAX_VERSION_SZ]; + byte seq[MAX_SEQ_SZ]; + int ret; + int curveSz; + int verSz; + int privHdrSz = ASN_ECC_HEADER_SZ; + int pubHdrSz = ASN_ECC_CONTEXT_SZ + ASN_ECC_HEADER_SZ; + int curveHdrSz = ASN_ECC_CONTEXT_SZ; + word32 seqSz; + word32 idx = 0; + word32 pubSz = ECC_BUFSIZE; + word32 privSz; + word32 totalSz; + + if (key == NULL || output == NULL || inLen == 0) + return BAD_FUNC_ARG; + + ret = ecc_export_x963(key, NULL, &pubSz); + if (ret != LENGTH_ONLY_E) { + return ret; + } + curveSz = SetCurve(key, curve); + if (curveSz < 0) { + return curveSz; + } + + privSz = key->dp->size; + + verSz = SetMyVersion(1, ver, FALSE); + if (verSz < 0) { + return verSz; + } + + totalSz = verSz + privSz + privHdrSz + curveSz + curveHdrSz + + pubSz + pubHdrSz + 1; /* plus null byte b4 public */ + seqSz = SetSequence(totalSz, seq); + totalSz += seqSz; + + if (totalSz > inLen) { + return BUFFER_E; + } + + /* write it out */ + /* seq */ + XMEMCPY(output + idx, seq, seqSz); + idx += seqSz; + + /* ver */ + XMEMCPY(output + idx, ver, verSz); + idx += verSz; + + /* private */ + output[idx++] = ASN_OCTET_STRING; + output[idx++] = (byte)privSz; + ret = ecc_export_private_only(key, output + idx, &privSz); + if (ret < 0) { + return ret; + } + idx += privSz; + + /* curve */ + output[idx++] = ECC_PREFIX_0; + output[idx++] = (byte)curveSz; + XMEMCPY(output + idx, curve, curveSz); + idx += curveSz; + + /* public */ + output[idx++] = ECC_PREFIX_1; + output[idx++] = (byte)pubSz + ASN_ECC_CONTEXT_SZ + 1; /* plus null byte */ + output[idx++] = ASN_BIT_STRING; + output[idx++] = (byte)pubSz + 1; /* plus null byte */ + output[idx++] = (byte)0; /* null byte */ + ret = ecc_export_x963(key, output + idx, &pubSz); + if (ret != 0) { + return ret; + } + /* idx += pubSz if do more later */ + + return totalSz; +} + +#endif /* WOLFSSL_KEY_GEN */ + +#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; + + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + oid = 0; + if (GetObjectId(source, &idx, &oid, sz) < 0) { + WOLFSSL_MSG("\tfail: OBJECT ID"); + return ASN_PARSE_E; + } + + /* check for critical flag */ + if (source[idx] == ASN_BOOLEAN) { + WOLFSSL_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) { + WOLFSSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(source, &idx, &length, sz) < 0) { + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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) + { + WOLFSSL_MSG("\tOCSP Confirm signature failed"); + return ASN_OCSP_CONFIRM_E; + } + } + + *ioIndex = idx; + return 0; +} + + +void InitOcspResponse(OcspResponse* resp, CertStatus* status, + byte* source, word32 inSz) +{ + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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) { + WOLFSSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce."); + } else { + if (RNG_GenerateBlock(&rng, req->nonce, MAX_OCSP_NONCE_SZ) != 0) + WOLFSSL_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) +{ + WOLFSSL_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; + + WOLFSSL_ENTER("CompareOcspReqResp"); + + if (req == NULL) + { + WOLFSSL_MSG("\tReq missing"); + return -1; + } + + if (resp == NULL) + { + WOLFSSL_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) + { + WOLFSSL_MSG("\tnonceSz mismatch"); + return cmp; + } + + cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz); + if (cmp != 0) + { + WOLFSSL_MSG("\tnonce mismatch"); + return cmp; + } + } + + cmp = XMEMCMP(req->issuerHash, resp->issuerHash, SHA_DIGEST_SIZE); + if (cmp != 0) + { + WOLFSSL_MSG("\tissuerHash mismatch"); + return cmp; + } + + cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, SHA_DIGEST_SIZE); + if (cmp != 0) + { + WOLFSSL_MSG("\tissuerKeyHash mismatch"); + return cmp; + } + + cmp = req->serialSz - resp->status->serialSz; + if (cmp != 0) + { + WOLFSSL_MSG("\tserialSz mismatch"); + return cmp; + } + + cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz); + if (cmp != 0) + { + WOLFSSL_MSG("\tserial mismatch"); + return cmp; + } + + return 0; +} + +#endif + + +/* store SHA1 hash of NAME */ +WOLFSSL_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; + + WOLFSSL_ENTER("GetNameHash"); + + if (source[*idx] == ASN_OBJECT_ID) { + WOLFSSL_MSG("Trying optional prefix..."); + + if (GetLength(source, idx, &length, maxIdx) < 0) + return ASN_PARSE_E; + + *idx += length; + WOLFSSL_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) +{ + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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) { + WOLFSSL_MSG("Expecting Integer"); + return ASN_PARSE_E; + } + + if (GetLength(buff, idx, &len, maxIdx) < 0) + return ASN_PARSE_E; + + if (len > EXTERNAL_SERIAL_SIZE) { + WOLFSSL_MSG("Serial Size too big"); + return ASN_PARSE_E; + } + + rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), NULL, DYNAMIC_TYPE_CRL); + if (rc == NULL) { + WOLFSSL_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) { + WOLFSSL_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; + + WOLFSSL_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; + + WOLFSSL_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)) { + WOLFSSL_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 */ + WOLFSSL_MSG("About to verify CRL signature"); + + if (ca) { + WOLFSSL_MSG("Found CRL issuer CA"); + /* try to confirm/verify signature */ + #ifndef IGNORE_KEY_EXTENSIONS + if ((ca->keyUsage & KEYUSE_CRL_SIGN) == 0) { + WOLFSSL_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)) { + WOLFSSL_MSG("CRL Confirm signature failed"); + return ASN_CRL_CONFIRM_E; + } + } + else { + WOLFSSL_MSG("Did NOT find CRL issuer CA"); + return ASN_CRL_NO_SIGNER_E; + } + + return 0; +} + +#endif /* HAVE_CRL */ +#endif + +#ifdef WOLFSSL_SEP + + + +#endif /* WOLFSSL_SEP */ + diff --git a/wolfcrypt/src/coding.c b/wolfcrypt/src/coding.c new file mode 100644 index 000000000..cdad0f5ca --- /dev/null +++ b/wolfcrypt/src/coding.c @@ -0,0 +1,399 @@ +/* coding.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 +#endif + +#include + +#ifndef NO_CODING + +#include +#include +#include + + +enum { + BAD = 0xFF, /* invalid encoding */ + PAD = '=', + PEM_LINE_SZ = 64 +}; + + +static +const byte base64Decode[] = { 62, BAD, BAD, BAD, 63, /* + starts at 0x2B */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, + BAD, BAD, BAD, BAD, BAD, BAD, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51 + }; + + +int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + word32 i = 0; + word32 j = 0; + word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ ); + const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1; + + plainSz = (plainSz * 3 + 3) / 4; + if (plainSz > *outLen) return BAD_FUNC_ARG; + + while (inLen > 3) { + byte b1, b2, b3; + byte e1 = in[j++]; + byte e2 = in[j++]; + byte e3 = in[j++]; + byte e4 = in[j++]; + + int pad3 = 0; + int pad4 = 0; + + if (e1 == 0) /* end file 0's */ + break; + if (e3 == PAD) + pad3 = 1; + if (e4 == PAD) + pad4 = 1; + + if (e1 < 0x2B || e2 < 0x2B || e3 < 0x2B || e4 < 0x2B) { + CYASSL_MSG("Bad Base64 Decode data, too small"); + return ASN_INPUT_E; + } + + if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) { + CYASSL_MSG("Bad Base64 Decode data, too big"); + return ASN_INPUT_E; + } + + e1 = base64Decode[e1 - 0x2B]; + e2 = base64Decode[e2 - 0x2B]; + e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B]; + e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B]; + + b1 = (byte)((e1 << 2) | (e2 >> 4)); + b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2)); + b3 = (byte)(((e3 & 0x3) << 6) | e4); + + out[i++] = b1; + if (!pad3) + out[i++] = b2; + if (!pad4) + out[i++] = b3; + else + break; + + inLen -= 4; + if (inLen && (in[j] == ' ' || in[j] == '\r' || in[j] == '\n')) { + byte endLine = in[j++]; + inLen--; + while (inLen && endLine == ' ') { /* allow trailing whitespace */ + endLine = in[j++]; + inLen--; + } + if (endLine == '\r') { + if (inLen) { + endLine = in[j++]; + inLen--; + } + } + if (endLine != '\n') { + CYASSL_MSG("Bad end of line in Base64 Decode"); + return ASN_INPUT_E; + } + } + } + *outLen = i; + + return 0; +} + + +#if defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER) + +static +const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '+', '/' + }; + + +/* make sure *i (idx) won't exceed max, store and possibly escape to out, + * raw means use e w/o decode, 0 on success */ +static int CEscape(int escaped, byte e, byte* out, word32* i, word32 max, + int raw) +{ + int doEscape = 0; + word32 needed = 1; + word32 idx = *i; + + byte basic; + byte plus = 0; + byte equals = 0; + byte newline = 0; + + if (raw) + basic = e; + else + basic = base64Encode[e]; + + /* check whether to escape */ + if (escaped) { + switch ((char)basic) { + case '+' : + plus = 1; + doEscape = 1; + needed += 2; + break; + case '=' : + equals = 1; + doEscape = 1; + needed += 2; + break; + case '\n' : + newline = 1; + doEscape = 1; + needed += 2; + break; + default: + /* do nothing */ + break; + } + } + + /* check size */ + if ( (idx+needed) > max) { + CYASSL_MSG("Escape buffer max too small"); + return BUFFER_E; + } + + /* store it */ + if (doEscape == 0) { + out[idx++] = basic; + } + else { + out[idx++] = '%'; /* start escape */ + + if (plus) { + out[idx++] = '2'; + out[idx++] = 'B'; + } + else if (equals) { + out[idx++] = '3'; + out[idx++] = 'D'; + } + else if (newline) { + out[idx++] = '0'; + out[idx++] = 'A'; + } + + } + *i = idx; + + return 0; +} + + +/* internal worker, handles both escaped and normal line endings */ +static int DoBase64_Encode(const byte* in, word32 inLen, byte* out, + word32* outLen, int escaped) +{ + int ret = 0; + word32 i = 0, + j = 0, + n = 0; /* new line counter */ + + word32 outSz = (inLen + 3 - 1) / 3 * 4; + word32 addSz = (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ; /* new lines */ + + if (escaped) + addSz *= 3; /* instead of just \n, we're doing %0A triplet */ + + outSz += addSz; + + /* if escaped we can't predetermine size for one pass encoding, but + * make sure we have enough if no escapes are in input */ + if (outSz > *outLen) return BAD_FUNC_ARG; + + while (inLen > 2) { + byte b1 = in[j++]; + byte b2 = in[j++]; + byte b3 = in[j++]; + + /* encoded idx */ + byte e1 = b1 >> 2; + byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4)); + byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6)); + byte e4 = b3 & 0x3F; + + /* store */ + ret = CEscape(escaped, e1, out, &i, *outLen, 0); + if (ret != 0) break; + ret = CEscape(escaped, e2, out, &i, *outLen, 0); + if (ret != 0) break; + ret = CEscape(escaped, e3, out, &i, *outLen, 0); + if (ret != 0) break; + ret = CEscape(escaped, e4, out, &i, *outLen, 0); + if (ret != 0) break; + + inLen -= 3; + + if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen) { + ret = CEscape(escaped, '\n', out, &i, *outLen, 1); + if (ret != 0) break; + } + } + + /* last integral */ + if (inLen && ret == 0) { + int twoBytes = (inLen == 2); + + byte b1 = in[j++]; + byte b2 = (twoBytes) ? in[j++] : 0; + + byte e1 = b1 >> 2; + byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4)); + byte e3 = (byte)((b2 & 0xF) << 2); + + ret = CEscape(escaped, e1, out, &i, *outLen, 0); + if (ret == 0) + ret = CEscape(escaped, e2, out, &i, *outLen, 0); + if (ret == 0) { + /* third */ + if (twoBytes) + ret = CEscape(escaped, e3, out, &i, *outLen, 0); + else + ret = CEscape(escaped, '=', out, &i, *outLen, 1); + } + /* fourth always pad */ + if (ret == 0) + ret = CEscape(escaped, '=', out, &i, *outLen, 1); + } + + if (ret == 0) + ret = CEscape(escaped, '\n', out, &i, *outLen, 1); + + if (i != outSz && escaped == 0 && ret == 0) + return ASN_INPUT_E; + + *outLen = i; + return ret; +} + + +/* Base64 Encode, PEM style, with \n line endings */ +int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + return DoBase64_Encode(in, inLen, out, outLen, 0); +} + + +/* Base64 Encode, with %0A esacped line endings instead of \n */ +int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + return DoBase64_Encode(in, inLen, out, outLen, 1); +} + + +#endif /* defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER) */ + + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS) + +static +const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, + 10, 11, 12, 13, 14, 15, /* upper case A-F */ + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, /* G - ` */ + 10, 11, 12, 13, 14, 15 /* lower case a-f */ + }; /* A starts at 0x41 not 0x3A */ + +int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + word32 inIdx = 0; + word32 outIdx = 0; + + if (inLen == 1 && *outLen && in) { + byte b = in[inIdx++] - 0x30; /* 0 starts at 0x30 */ + + /* sanity check */ + if (b >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return ASN_INPUT_E; + + b = hexDecode[b]; + + if (b == BAD) + return ASN_INPUT_E; + + out[outIdx++] = b; + + *outLen = outIdx; + return 0; + } + + if (inLen % 2) + return BAD_FUNC_ARG; + + if (*outLen < (inLen / 2)) + return BAD_FUNC_ARG; + + while (inLen) { + byte b = in[inIdx++] - 0x30; /* 0 starts at 0x30 */ + byte b2 = in[inIdx++] - 0x30; + + /* sanity checks */ + if (b >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return ASN_INPUT_E; + if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return ASN_INPUT_E; + + b = hexDecode[b]; + b2 = hexDecode[b2]; + + if (b == BAD || b2 == BAD) + return ASN_INPUT_E; + + out[outIdx++] = (byte)((b << 4) | b2); + inLen -= 2; + } + + *outLen = outIdx; + return 0; +} + + +#endif /* (OPENSSL_EXTRA) || (HAVE_WEBSERVER) || (HAVE_FIPS) */ + +#endif /* NO_CODING */ diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c new file mode 100644 index 000000000..5bce1efb4 --- /dev/null +++ b/wolfcrypt/src/ecc.c @@ -0,0 +1,4837 @@ +/* ecc.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL 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. + * + * wolfSSL 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 +#endif + +/* in case user set HAVE_ECC there */ +#include + +#ifdef HAVE_ECC + +#include +#include +#include + +#ifdef HAVE_ECC_ENCRYPT + #include + #include +#endif + + +/* map + + ptmul -> mulmod + +*/ + +#define ECC112 +#define ECC128 +#define ECC160 +#define ECC192 +#define ECC224 +#define ECC256 +#define ECC384 +#define ECC521 + + + +/* This holds the key settings. ***MUST*** be organized by size from + smallest to largest. */ + +const ecc_set_type ecc_sets[] = { +#ifdef ECC112 +{ + 14, + "SECP112R1", + "DB7C2ABF62E35E668076BEAD208B", + "DB7C2ABF62E35E668076BEAD2088", + "659EF8BA043916EEDE8911702B22", + "DB7C2ABF62E35E7628DFAC6561C5", + "09487239995A5EE76B55F9C2F098", + "A89CE5AF8724C0A23E0E0FF77500" +}, +#endif +#ifdef ECC128 +{ + 16, + "SECP128R1", + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", + "E87579C11079F43DD824993C2CEE5ED3", + "FFFFFFFE0000000075A30D1B9038A115", + "161FF7528B899B2D0C28607CA52C5B86", + "CF5AC8395BAFEB13C02DA292DDED7A83", +}, +#endif +#ifdef ECC160 +{ + 20, + "SECP160R1", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "0100000000000000000001F4C8F927AED3CA752257", + "4A96B5688EF573284664698968C38BB913CBFC82", + "23A628553168947D59DCC912042351377AC5FB32", +}, +#endif +#ifdef ECC192 +{ + 24, + "ECC-192", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", +}, +#endif +#ifdef ECC224 +{ + 28, + "ECC-224", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", + "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", +}, +#endif +#ifdef ECC256 +{ + 32, + "ECC-256", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", +}, +#endif +#ifdef ECC384 +{ + 48, + "ECC-384", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", + "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", +}, +#endif +#ifdef ECC521 +{ + 66, + "ECC-521", + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", + "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", + "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", +}, +#endif +{ + 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL +} +}; + + +ecc_point* ecc_new_point(void); +void ecc_del_point(ecc_point* p); +int ecc_map(ecc_point*, mp_int*, mp_digit*); +int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, + mp_int* modulus, mp_digit* mp); +int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* modulus, + mp_digit* mp); +static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, + int map); +#ifdef ECC_SHAMIR +static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, + ecc_point* C, mp_int* modulus); +#endif + +int mp_jacobi(mp_int* a, mp_int* p, int* c); +int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret); +int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d); + +#ifdef HAVE_COMP_KEY +static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); +#endif + +/* helper for either lib */ +static int get_digit_count(mp_int* a) +{ + if (a == NULL) + return 0; + + return a->used; +} + +/* helper for either lib */ +static mp_digit get_digit(mp_int* a, int n) +{ + if (a == NULL) + return 0; + + return (n >= a->used || n < 0) ? 0 : a->dp[n]; +} + + +#if defined(USE_FAST_MATH) + +/* fast math accelerated version, but not for fp ecc yet */ + +/** + Add two ECC points + P The point to add + Q The point to add + R [out] The destination of the double + modulus The modulus of the field the ECC curve is in + mp The "b" value from montgomery_setup() + return MP_OKAY on success +*/ +int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, + mp_int* modulus, mp_digit* mp) +{ + fp_int t1, t2, x, y, z; + int err; + + if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL) + return ECC_BAD_ARG_E; + + if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) { + return err; + } + + /* should we dbl instead? */ + fp_sub(modulus, &Q->y, &t1); + if ( (fp_cmp(&P->x, &Q->x) == FP_EQ) && + (get_digit_count(&Q->z) && fp_cmp(&P->z, &Q->z) == FP_EQ) && + (fp_cmp(&P->y, &Q->y) == FP_EQ || fp_cmp(&P->y, &t1) == FP_EQ)) { + return ecc_projective_dbl_point(P, R, modulus, mp); + } + + fp_copy(&P->x, &x); + fp_copy(&P->y, &y); + fp_copy(&P->z, &z); + + /* if Z is one then these are no-operations */ + if (get_digit_count(&Q->z)) { + /* T1 = Z' * Z' */ + fp_sqr(&Q->z, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + /* X = X * T1 */ + fp_mul(&t1, &x, &x); + fp_montgomery_reduce(&x, modulus, *mp); + /* T1 = Z' * T1 */ + fp_mul(&Q->z, &t1, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + /* Y = Y * T1 */ + fp_mul(&t1, &y, &y); + fp_montgomery_reduce(&y, modulus, *mp); + } + + /* T1 = Z*Z */ + fp_sqr(&z, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + /* T2 = X' * T1 */ + fp_mul(&Q->x, &t1, &t2); + fp_montgomery_reduce(&t2, modulus, *mp); + /* T1 = Z * T1 */ + fp_mul(&z, &t1, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + /* T1 = Y' * T1 */ + fp_mul(&Q->y, &t1, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + + /* Y = Y - T1 */ + fp_sub(&y, &t1, &y); + if (fp_cmp_d(&y, 0) == FP_LT) { + fp_add(&y, modulus, &y); + } + /* T1 = 2T1 */ + fp_add(&t1, &t1, &t1); + if (fp_cmp(&t1, modulus) != FP_LT) { + fp_sub(&t1, modulus, &t1); + } + /* T1 = Y + T1 */ + fp_add(&t1, &y, &t1); + if (fp_cmp(&t1, modulus) != FP_LT) { + fp_sub(&t1, modulus, &t1); + } + /* X = X - T2 */ + fp_sub(&x, &t2, &x); + if (fp_cmp_d(&x, 0) == FP_LT) { + fp_add(&x, modulus, &x); + } + /* T2 = 2T2 */ + fp_add(&t2, &t2, &t2); + if (fp_cmp(&t2, modulus) != FP_LT) { + fp_sub(&t2, modulus, &t2); + } + /* T2 = X + T2 */ + fp_add(&t2, &x, &t2); + if (fp_cmp(&t2, modulus) != FP_LT) { + fp_sub(&t2, modulus, &t2); + } + + /* if Z' != 1 */ + if (get_digit_count(&Q->z)) { + /* Z = Z * Z' */ + fp_mul(&z, &Q->z, &z); + fp_montgomery_reduce(&z, modulus, *mp); + } + + /* Z = Z * X */ + fp_mul(&z, &x, &z); + fp_montgomery_reduce(&z, modulus, *mp); + + /* T1 = T1 * X */ + fp_mul(&t1, &x, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + /* X = X * X */ + fp_sqr(&x, &x); + fp_montgomery_reduce(&x, modulus, *mp); + /* T2 = T2 * x */ + fp_mul(&t2, &x, &t2); + fp_montgomery_reduce(&t2, modulus, *mp); + /* T1 = T1 * X */ + fp_mul(&t1, &x, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + + /* X = Y*Y */ + fp_sqr(&y, &x); + fp_montgomery_reduce(&x, modulus, *mp); + /* X = X - T2 */ + fp_sub(&x, &t2, &x); + if (fp_cmp_d(&x, 0) == FP_LT) { + fp_add(&x, modulus, &x); + } + + /* T2 = T2 - X */ + fp_sub(&t2, &x, &t2); + if (fp_cmp_d(&t2, 0) == FP_LT) { + fp_add(&t2, modulus, &t2); + } + /* T2 = T2 - X */ + fp_sub(&t2, &x, &t2); + if (fp_cmp_d(&t2, 0) == FP_LT) { + fp_add(&t2, modulus, &t2); + } + /* T2 = T2 * Y */ + fp_mul(&t2, &y, &t2); + fp_montgomery_reduce(&t2, modulus, *mp); + /* Y = T2 - T1 */ + fp_sub(&t2, &t1, &y); + if (fp_cmp_d(&y, 0) == FP_LT) { + fp_add(&y, modulus, &y); + } + /* Y = Y/2 */ + if (fp_isodd(&y)) { + fp_add(&y, modulus, &y); + } + fp_div_2(&y, &y); + + fp_copy(&x, &R->x); + fp_copy(&y, &R->y); + fp_copy(&z, &R->z); + + return MP_OKAY; +} + + +/** + Double an ECC point + P The point to double + R [out] The destination of the double + modulus The modulus of the field the ECC curve is in + mp The "b" value from montgomery_setup() + return MP_OKAY on success +*/ +int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus, + mp_digit* mp) +{ + fp_int t1, t2; + int err; + + if (P == NULL || R == NULL || modulus == NULL || mp == NULL) + return ECC_BAD_ARG_E; + + if (P != R) { + fp_copy(&P->x, &R->x); + fp_copy(&P->y, &R->y); + fp_copy(&P->z, &R->z); + } + + if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { + return err; + } + + /* t1 = Z * Z */ + fp_sqr(&R->z, &t1); + fp_montgomery_reduce(&t1, modulus, *mp); + /* Z = Y * Z */ + fp_mul(&R->z, &R->y, &R->z); + fp_montgomery_reduce(&R->z, modulus, *mp); + /* Z = 2Z */ + fp_add(&R->z, &R->z, &R->z); + if (fp_cmp(&R->z, modulus) != FP_LT) { + fp_sub(&R->z, modulus, &R->z); + } + + /* &t2 = X - T1 */ + fp_sub(&R->x, &t1, &t2); + if (fp_cmp_d(&t2, 0) == FP_LT) { + fp_add(&t2, modulus, &t2); + } + /* T1 = X + T1 */ + fp_add(&t1, &R->x, &t1); + if (fp_cmp(&t1, modulus) != FP_LT) { + fp_sub(&t1, modulus, &t1); + } + /* T2 = T1 * T2 */ + fp_mul(&t1, &t2, &t2); + fp_montgomery_reduce(&t2, modulus, *mp); + /* T1 = 2T2 */ + fp_add(&t2, &t2, &t1); + if (fp_cmp(&t1, modulus) != FP_LT) { + fp_sub(&t1, modulus, &t1); + } + /* T1 = T1 + T2 */ + fp_add(&t1, &t2, &t1); + if (fp_cmp(&t1, modulus) != FP_LT) { + fp_sub(&t1, modulus, &t1); + } + + /* Y = 2Y */ + fp_add(&R->y, &R->y, &R->y); + if (fp_cmp(&R->y, modulus) != FP_LT) { + fp_sub(&R->y, modulus, &R->y); + } + /* Y = Y * Y */ + fp_sqr(&R->y, &R->y); + fp_montgomery_reduce(&R->y, modulus, *mp); + /* T2 = Y * Y */ + fp_sqr(&R->y, &t2); + fp_montgomery_reduce(&t2, modulus, *mp); + /* T2 = T2/2 */ + if (fp_isodd(&t2)) { + fp_add(&t2, modulus, &t2); + } + fp_div_2(&t2, &t2); + /* Y = Y * X */ + fp_mul(&R->y, &R->x, &R->y); + fp_montgomery_reduce(&R->y, modulus, *mp); + + /* X = T1 * T1 */ + fp_sqr(&t1, &R->x); + fp_montgomery_reduce(&R->x, modulus, *mp); + /* X = X - Y */ + fp_sub(&R->x, &R->y, &R->x); + if (fp_cmp_d(&R->x, 0) == FP_LT) { + fp_add(&R->x, modulus, &R->x); + } + /* X = X - Y */ + fp_sub(&R->x, &R->y, &R->x); + if (fp_cmp_d(&R->x, 0) == FP_LT) { + fp_add(&R->x, modulus, &R->x); + } + + /* Y = Y - X */ + fp_sub(&R->y, &R->x, &R->y); + if (fp_cmp_d(&R->y, 0) == FP_LT) { + fp_add(&R->y, modulus, &R->y); + } + /* Y = Y * T1 */ + fp_mul(&R->y, &t1, &R->y); + fp_montgomery_reduce(&R->y, modulus, *mp); + /* Y = Y - T2 */ + fp_sub(&R->y, &t2, &R->y); + if (fp_cmp_d(&R->y, 0) == FP_LT) { + fp_add(&R->y, modulus, &R->y); + } + + return MP_OKAY; +} + +#else /* USE_FAST_MATH */ + +/** + Add two ECC points + P The point to add + Q The point to add + R [out] The destination of the double + modulus The modulus of the field the ECC curve is in + mp The "b" value from montgomery_setup() + return MP_OKAY on success +*/ +int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, + mp_int* modulus, mp_digit* mp) +{ + mp_int t1; + mp_int t2; + mp_int x; + mp_int y; + mp_int z; + int err; + + if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL) + return ECC_BAD_ARG_E; + + if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) { + return err; + } + + /* should we dbl instead? */ + err = mp_sub(modulus, &Q->y, &t1); + + if (err == MP_OKAY) { + if ( (mp_cmp(&P->x, &Q->x) == MP_EQ) && + (get_digit_count(&Q->z) && mp_cmp(&P->z, &Q->z) == MP_EQ) && + (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &t1) == MP_EQ)) { + mp_clear(&t1); + mp_clear(&t2); + mp_clear(&x); + mp_clear(&y); + mp_clear(&z); + + return ecc_projective_dbl_point(P, R, modulus, mp); + } + } + + if (err == MP_OKAY) + err = mp_copy(&P->x, &x); + if (err == MP_OKAY) + err = mp_copy(&P->y, &y); + if (err == MP_OKAY) + err = mp_copy(&P->z, &z); + + /* if Z is one then these are no-operations */ + if (err == MP_OKAY) { + if (get_digit_count(&Q->z)) { + /* T1 = Z' * Z' */ + err = mp_sqr(&Q->z, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* X = X * T1 */ + if (err == MP_OKAY) + err = mp_mul(&t1, &x, &x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&x, modulus, *mp); + + /* T1 = Z' * T1 */ + if (err == MP_OKAY) + err = mp_mul(&Q->z, &t1, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* Y = Y * T1 */ + if (err == MP_OKAY) + err = mp_mul(&t1, &y, &y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&y, modulus, *mp); + } + } + + /* T1 = Z*Z */ + if (err == MP_OKAY) + err = mp_sqr(&z, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* T2 = X' * T1 */ + if (err == MP_OKAY) + err = mp_mul(&Q->x, &t1, &t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t2, modulus, *mp); + + /* T1 = Z * T1 */ + if (err == MP_OKAY) + err = mp_mul(&z, &t1, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* T1 = Y' * T1 */ + if (err == MP_OKAY) + err = mp_mul(&Q->y, &t1, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* Y = Y - T1 */ + if (err == MP_OKAY) + err = mp_sub(&y, &t1, &y); + if (err == MP_OKAY) { + if (mp_cmp_d(&y, 0) == MP_LT) + err = mp_add(&y, modulus, &y); + } + /* T1 = 2T1 */ + if (err == MP_OKAY) + err = mp_add(&t1, &t1, &t1); + if (err == MP_OKAY) { + if (mp_cmp(&t1, modulus) != MP_LT) + err = mp_sub(&t1, modulus, &t1); + } + /* T1 = Y + T1 */ + if (err == MP_OKAY) + err = mp_add(&t1, &y, &t1); + if (err == MP_OKAY) { + if (mp_cmp(&t1, modulus) != MP_LT) + err = mp_sub(&t1, modulus, &t1); + } + /* X = X - T2 */ + if (err == MP_OKAY) + err = mp_sub(&x, &t2, &x); + if (err == MP_OKAY) { + if (mp_cmp_d(&x, 0) == MP_LT) + err = mp_add(&x, modulus, &x); + } + /* T2 = 2T2 */ + if (err == MP_OKAY) + err = mp_add(&t2, &t2, &t2); + if (err == MP_OKAY) { + if (mp_cmp(&t2, modulus) != MP_LT) + err = mp_sub(&t2, modulus, &t2); + } + /* T2 = X + T2 */ + if (err == MP_OKAY) + err = mp_add(&t2, &x, &t2); + if (err == MP_OKAY) { + if (mp_cmp(&t2, modulus) != MP_LT) + err = mp_sub(&t2, modulus, &t2); + } + + if (err == MP_OKAY) { + if (get_digit_count(&Q->z)) { + /* Z = Z * Z' */ + err = mp_mul(&z, &Q->z, &z); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&z, modulus, *mp); + } + } + + /* Z = Z * X */ + if (err == MP_OKAY) + err = mp_mul(&z, &x, &z); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&z, modulus, *mp); + + /* T1 = T1 * X */ + if (err == MP_OKAY) + err = mp_mul(&t1, &x, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* X = X * X */ + if (err == MP_OKAY) + err = mp_sqr(&x, &x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&x, modulus, *mp); + + /* T2 = T2 * x */ + if (err == MP_OKAY) + err = mp_mul(&t2, &x, &t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t2, modulus, *mp); + + /* T1 = T1 * X */ + if (err == MP_OKAY) + err = mp_mul(&t1, &x, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* X = Y*Y */ + if (err == MP_OKAY) + err = mp_sqr(&y, &x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&x, modulus, *mp); + + /* X = X - T2 */ + if (err == MP_OKAY) + err = mp_sub(&x, &t2, &x); + if (err == MP_OKAY) { + if (mp_cmp_d(&x, 0) == MP_LT) + err = mp_add(&x, modulus, &x); + } + /* T2 = T2 - X */ + if (err == MP_OKAY) + err = mp_sub(&t2, &x, &t2); + if (err == MP_OKAY) { + if (mp_cmp_d(&t2, 0) == MP_LT) + err = mp_add(&t2, modulus, &t2); + } + /* T2 = T2 - X */ + if (err == MP_OKAY) + err = mp_sub(&t2, &x, &t2); + if (err == MP_OKAY) { + if (mp_cmp_d(&t2, 0) == MP_LT) + err = mp_add(&t2, modulus, &t2); + } + /* T2 = T2 * Y */ + if (err == MP_OKAY) + err = mp_mul(&t2, &y, &t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t2, modulus, *mp); + + /* Y = T2 - T1 */ + if (err == MP_OKAY) + err = mp_sub(&t2, &t1, &y); + if (err == MP_OKAY) { + if (mp_cmp_d(&y, 0) == MP_LT) + err = mp_add(&y, modulus, &y); + } + /* Y = Y/2 */ + if (err == MP_OKAY) { + if (mp_isodd(&y)) + err = mp_add(&y, modulus, &y); + } + if (err == MP_OKAY) + err = mp_div_2(&y, &y); + + if (err == MP_OKAY) + err = mp_copy(&x, &R->x); + if (err == MP_OKAY) + err = mp_copy(&y, &R->y); + if (err == MP_OKAY) + err = mp_copy(&z, &R->z); + + /* clean up */ + mp_clear(&t1); + mp_clear(&t2); + mp_clear(&x); + mp_clear(&y); + mp_clear(&z); + + return err; +} + + +/** + Double an ECC point + P The point to double + R [out] The destination of the double + modulus The modulus of the field the ECC curve is in + mp The "b" value from montgomery_setup() + return MP_OKAY on success +*/ +int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus, + mp_digit* mp) +{ + mp_int t1; + mp_int t2; + int err; + + if (P == NULL || R == NULL || modulus == NULL || mp == NULL) + return ECC_BAD_ARG_E; + + if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { + return err; + } + + if (P != R) { + err = mp_copy(&P->x, &R->x); + if (err == MP_OKAY) + err = mp_copy(&P->y, &R->y); + if (err == MP_OKAY) + err = mp_copy(&P->z, &R->z); + } + + /* t1 = Z * Z */ + if (err == MP_OKAY) + err = mp_sqr(&R->z, &t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t1, modulus, *mp); + + /* Z = Y * Z */ + if (err == MP_OKAY) + err = mp_mul(&R->z, &R->y, &R->z); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&R->z, modulus, *mp); + + /* Z = 2Z */ + if (err == MP_OKAY) + err = mp_add(&R->z, &R->z, &R->z); + if (err == MP_OKAY) { + if (mp_cmp(&R->z, modulus) != MP_LT) + err = mp_sub(&R->z, modulus, &R->z); + } + + /* T2 = X - T1 */ + if (err == MP_OKAY) + err = mp_sub(&R->x, &t1, &t2); + if (err == MP_OKAY) { + if (mp_cmp_d(&t2, 0) == MP_LT) + err = mp_add(&t2, modulus, &t2); + } + /* T1 = X + T1 */ + if (err == MP_OKAY) + err = mp_add(&t1, &R->x, &t1); + if (err == MP_OKAY) { + if (mp_cmp(&t1, modulus) != MP_LT) + err = mp_sub(&t1, modulus, &t1); + } + /* T2 = T1 * T2 */ + if (err == MP_OKAY) + err = mp_mul(&t1, &t2, &t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t2, modulus, *mp); + + /* T1 = 2T2 */ + if (err == MP_OKAY) + err = mp_add(&t2, &t2, &t1); + if (err == MP_OKAY) { + if (mp_cmp(&t1, modulus) != MP_LT) + err = mp_sub(&t1, modulus, &t1); + } + /* T1 = T1 + T2 */ + if (err == MP_OKAY) + err = mp_add(&t1, &t2, &t1); + if (err == MP_OKAY) { + if (mp_cmp(&t1, modulus) != MP_LT) + err = mp_sub(&t1, modulus, &t1); + } + /* Y = 2Y */ + if (err == MP_OKAY) + err = mp_add(&R->y, &R->y, &R->y); + if (err == MP_OKAY) { + if (mp_cmp(&R->y, modulus) != MP_LT) + err = mp_sub(&R->y, modulus, &R->y); + } + /* Y = Y * Y */ + if (err == MP_OKAY) + err = mp_sqr(&R->y, &R->y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&R->y, modulus, *mp); + + /* T2 = Y * Y */ + if (err == MP_OKAY) + err = mp_sqr(&R->y, &t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&t2, modulus, *mp); + + /* T2 = T2/2 */ + if (err == MP_OKAY) { + if (mp_isodd(&t2)) + err = mp_add(&t2, modulus, &t2); + } + if (err == MP_OKAY) + err = mp_div_2(&t2, &t2); + + /* Y = Y * X */ + if (err == MP_OKAY) + err = mp_mul(&R->y, &R->x, &R->y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&R->y, modulus, *mp); + + /* X = T1 * T1 */ + if (err == MP_OKAY) + err = mp_sqr(&t1, &R->x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&R->x, modulus, *mp); + + /* X = X - Y */ + if (err == MP_OKAY) + err = mp_sub(&R->x, &R->y, &R->x); + if (err == MP_OKAY) { + if (mp_cmp_d(&R->x, 0) == MP_LT) + err = mp_add(&R->x, modulus, &R->x); + } + /* X = X - Y */ + if (err == MP_OKAY) + err = mp_sub(&R->x, &R->y, &R->x); + if (err == MP_OKAY) { + if (mp_cmp_d(&R->x, 0) == MP_LT) + err = mp_add(&R->x, modulus, &R->x); + } + /* Y = Y - X */ + if (err == MP_OKAY) + err = mp_sub(&R->y, &R->x, &R->y); + if (err == MP_OKAY) { + if (mp_cmp_d(&R->y, 0) == MP_LT) + err = mp_add(&R->y, modulus, &R->y); + } + /* Y = Y * T1 */ + if (err == MP_OKAY) + err = mp_mul(&R->y, &t1, &R->y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&R->y, modulus, *mp); + + /* Y = Y - T2 */ + if (err == MP_OKAY) + err = mp_sub(&R->y, &t2, &R->y); + if (err == MP_OKAY) { + if (mp_cmp_d(&R->y, 0) == MP_LT) + err = mp_add(&R->y, modulus, &R->y); + } + + /* clean up */ + mp_clear(&t1); + mp_clear(&t2); + + return err; +} + +#endif /* USE_FAST_MATH */ + +/** + Map a projective jacbobian point back to affine space + P [in/out] The point to map + modulus The modulus of the field the ECC curve is in + mp The "b" value from montgomery_setup() + return MP_OKAY on success +*/ +int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp) +{ + mp_int t1; + mp_int t2; + int err; + + if (P == NULL || mp == NULL || modulus == NULL) + return ECC_BAD_ARG_E; + + if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { + return MEMORY_E; + } + + /* first map z back to normal */ + err = mp_montgomery_reduce(&P->z, modulus, *mp); + + /* get 1/z */ + if (err == MP_OKAY) + err = mp_invmod(&P->z, modulus, &t1); + + /* get 1/z^2 and 1/z^3 */ + if (err == MP_OKAY) + err = mp_sqr(&t1, &t2); + if (err == MP_OKAY) + err = mp_mod(&t2, modulus, &t2); + if (err == MP_OKAY) + err = mp_mul(&t1, &t2, &t1); + if (err == MP_OKAY) + err = mp_mod(&t1, modulus, &t1); + + /* multiply against x/y */ + if (err == MP_OKAY) + err = mp_mul(&P->x, &t2, &P->x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&P->x, modulus, *mp); + if (err == MP_OKAY) + err = mp_mul(&P->y, &t1, &P->y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(&P->y, modulus, *mp); + + if (err == MP_OKAY) + mp_set(&P->z, 1); + + /* clean up */ + mp_clear(&t1); + mp_clear(&t2); + + return err; +} + + +#ifndef ECC_TIMING_RESISTANT + +/* size of sliding window, don't change this! */ +#define WINSIZE 4 + +/** + Perform a point multiplication + k The scalar to multiply by + G The base point + R [out] Destination for kG + modulus The modulus of the field the ECC curve is in + map Boolean whether to map back to affine or not + (1==map, 0 == leave in projective) + return MP_OKAY on success +*/ +#ifdef FP_ECC +static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, + mp_int* modulus, int map) +#else +static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, + int map) +#endif +{ + ecc_point *tG, *M[8]; + int i, j, err; + mp_int mu; + mp_digit mp; + mp_digit buf; + int first = 1, bitbuf = 0, bitcpy = 0, bitcnt = 0, mode = 0, + digidx = 0; + + if (k == NULL || G == NULL || R == NULL || modulus == NULL) + return ECC_BAD_ARG_E; + + /* init montgomery reduction */ + if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { + return err; + } + if ((err = mp_init(&mu)) != MP_OKAY) { + return err; + } + if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { + mp_clear(&mu); + return err; + } + + /* alloc ram for window temps */ + for (i = 0; i < 8; i++) { + M[i] = ecc_new_point(); + if (M[i] == NULL) { + for (j = 0; j < i; j++) { + ecc_del_point(M[j]); + } + mp_clear(&mu); + return MEMORY_E; + } + } + + /* make a copy of G incase R==G */ + tG = ecc_new_point(); + if (tG == NULL) + err = MEMORY_E; + + /* tG = G and convert to montgomery */ + if (err == MP_OKAY) { + if (mp_cmp_d(&mu, 1) == MP_EQ) { + err = mp_copy(&G->x, &tG->x); + if (err == MP_OKAY) + err = mp_copy(&G->y, &tG->y); + if (err == MP_OKAY) + err = mp_copy(&G->z, &tG->z); + } else { + err = mp_mulmod(&G->x, &mu, modulus, &tG->x); + if (err == MP_OKAY) + err = mp_mulmod(&G->y, &mu, modulus, &tG->y); + if (err == MP_OKAY) + err = mp_mulmod(&G->z, &mu, modulus, &tG->z); + } + } + mp_clear(&mu); + + /* calc the M tab, which holds kG for k==8..15 */ + /* M[0] == 8G */ + if (err == MP_OKAY) + err = ecc_projective_dbl_point(tG, M[0], modulus, &mp); + if (err == MP_OKAY) + err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp); + if (err == MP_OKAY) + err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp); + + /* now find (8+k)G for k=1..7 */ + if (err == MP_OKAY) + for (j = 9; j < 16; j++) { + err = ecc_projective_add_point(M[j-9], tG, M[j-8], modulus, &mp); + if (err != MP_OKAY) break; + } + + /* setup sliding window */ + if (err == MP_OKAY) { + mode = 0; + bitcnt = 1; + buf = 0; + digidx = get_digit_count(k) - 1; + bitcpy = bitbuf = 0; + first = 1; + + /* perform ops */ + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = get_digit(k, digidx); + bitcnt = (int) DIGIT_BIT; + --digidx; + } + + /* grab the next msb from the ltiplicand */ + i = (int)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= 1; + + /* skip leading zero bits */ + if (mode == 0 && i == 0) + continue; + + /* if the bit is zero and mode == 1 then we double */ + if (mode == 1 && i == 0) { + err = ecc_projective_dbl_point(R, R, modulus, &mp); + if (err != MP_OKAY) break; + continue; + } + + /* else we add it to the window */ + bitbuf |= (i << (WINSIZE - ++bitcpy)); + mode = 2; + + if (bitcpy == WINSIZE) { + /* if this is the first window we do a simple copy */ + if (first == 1) { + /* R = kG [k = first window] */ + err = mp_copy(&M[bitbuf-8]->x, &R->x); + if (err != MP_OKAY) break; + + err = mp_copy(&M[bitbuf-8]->y, &R->y); + if (err != MP_OKAY) break; + + err = mp_copy(&M[bitbuf-8]->z, &R->z); + first = 0; + } else { + /* normal window */ + /* ok window is filled so double as required and add */ + /* double first */ + for (j = 0; j < WINSIZE; j++) { + err = ecc_projective_dbl_point(R, R, modulus, &mp); + if (err != MP_OKAY) break; + } + if (err != MP_OKAY) break; /* out of first for(;;) */ + + /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranted */ + err = ecc_projective_add_point(R,M[bitbuf-8],R,modulus,&mp); + } + if (err != MP_OKAY) break; + /* empty window and reset */ + bitcpy = bitbuf = 0; + mode = 1; + } + } + } + + /* if bits remain then double/add */ + if (err == MP_OKAY) { + if (mode == 2 && bitcpy > 0) { + /* double then add */ + for (j = 0; j < bitcpy; j++) { + /* only double if we have had at least one add first */ + if (first == 0) { + err = ecc_projective_dbl_point(R, R, modulus, &mp); + if (err != MP_OKAY) break; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << WINSIZE)) != 0) { + if (first == 1) { + /* first add, so copy */ + err = mp_copy(&tG->x, &R->x); + if (err != MP_OKAY) break; + + err = mp_copy(&tG->y, &R->y); + if (err != MP_OKAY) break; + + err = mp_copy(&tG->z, &R->z); + if (err != MP_OKAY) break; + first = 0; + } else { + /* then add */ + err = ecc_projective_add_point(R, tG, R, modulus, &mp); + if (err != MP_OKAY) break; + } + } + } + } + } + + /* map R back from projective space */ + if (err == MP_OKAY && map) + err = ecc_map(R, modulus, &mp); + + mp_clear(&mu); + ecc_del_point(tG); + for (i = 0; i < 8; i++) { + ecc_del_point(M[i]); + } + return err; +} + +#undef WINSIZE + +#else /* ECC_TIMING_RESISTANT */ + +/** + Perform a point multiplication (timing resistant) + k The scalar to multiply by + G The base point + R [out] Destination for kG + modulus The modulus of the field the ECC curve is in + map Boolean whether to map back to affine or not + (1==map, 0 == leave in projective) + return MP_OKAY on success +*/ +#ifdef FP_ECC +static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, + mp_int* modulus, int map) +#else +static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, + int map) +#endif +{ + ecc_point *tG, *M[3]; + int i, j, err; + mp_int mu; + mp_digit mp; + mp_digit buf; + int first = 1, bitbuf = 0, bitcpy = 0, bitcnt = 0, mode = 0, + digidx = 0; + + if (k == NULL || G == NULL || R == NULL || modulus == NULL) + return ECC_BAD_ARG_E; + + /* init montgomery reduction */ + if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { + return err; + } + if ((err = mp_init(&mu)) != MP_OKAY) { + return err; + } + if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { + mp_clear(&mu); + return err; + } + + /* alloc ram for window temps */ + for (i = 0; i < 3; i++) { + M[i] = ecc_new_point(); + if (M[i] == NULL) { + for (j = 0; j < i; j++) { + ecc_del_point(M[j]); + } + mp_clear(&mu); + return MEMORY_E; + } + } + + /* make a copy of G incase R==G */ + tG = ecc_new_point(); + if (tG == NULL) + err = MEMORY_E; + + /* tG = G and convert to montgomery */ + if (err == MP_OKAY) { + err = mp_mulmod(&G->x, &mu, modulus, &tG->x); + if (err == MP_OKAY) + err = mp_mulmod(&G->y, &mu, modulus, &tG->y); + if (err == MP_OKAY) + err = mp_mulmod(&G->z, &mu, modulus, &tG->z); + } + mp_clear(&mu); + + /* calc the M tab */ + /* M[0] == G */ + if (err == MP_OKAY) + err = mp_copy(&tG->x, &M[0]->x); + if (err == MP_OKAY) + err = mp_copy(&tG->y, &M[0]->y); + if (err == MP_OKAY) + err = mp_copy(&tG->z, &M[0]->z); + + /* M[1] == 2G */ + if (err == MP_OKAY) + err = ecc_projective_dbl_point(tG, M[1], modulus, &mp); + + /* setup sliding window */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = get_digit_count(k) - 1; + bitcpy = bitbuf = 0; + first = 1; + + /* perform ops */ + if (err == MP_OKAY) { + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = get_digit(k, digidx); + bitcnt = (int) DIGIT_BIT; + --digidx; + } + + /* grab the next msb from the ltiplicand */ + i = (buf >> (DIGIT_BIT - 1)) & 1; + buf <<= 1; + + if (mode == 0 && i == 0) { + /* dummy operations */ + if (err == MP_OKAY) + err = ecc_projective_add_point(M[0], M[1], M[2], modulus, + &mp); + if (err == MP_OKAY) + err = ecc_projective_dbl_point(M[1], M[2], modulus, &mp); + if (err == MP_OKAY) + continue; + } + + if (mode == 0 && i == 1) { + mode = 1; + /* dummy operations */ + if (err == MP_OKAY) + err = ecc_projective_add_point(M[0], M[1], M[2], modulus, + &mp); + if (err == MP_OKAY) + err = ecc_projective_dbl_point(M[1], M[2], modulus, &mp); + if (err == MP_OKAY) + continue; + } + + if (err == MP_OKAY) + err = ecc_projective_add_point(M[0], M[1], M[i^1], modulus, &mp); + if (err == MP_OKAY) + err = ecc_projective_dbl_point(M[i], M[i], modulus, &mp); + if (err != MP_OKAY) + break; + } /* end for */ + } + + /* copy result out */ + if (err == MP_OKAY) + err = mp_copy(&M[0]->x, &R->x); + if (err == MP_OKAY) + err = mp_copy(&M[0]->y, &R->y); + if (err == MP_OKAY) + err = mp_copy(&M[0]->z, &R->z); + + /* map R back from projective space */ + if (err == MP_OKAY && map) + err = ecc_map(R, modulus, &mp); + + /* done */ + mp_clear(&mu); + ecc_del_point(tG); + for (i = 0; i < 3; i++) { + ecc_del_point(M[i]); + } + return err; +} + +#endif /* ECC_TIMING_RESISTANT */ + + +/** + Allocate a new ECC point + return A newly allocated point or NULL on error +*/ +ecc_point* ecc_new_point(void) +{ + ecc_point* p; + p = (ecc_point*)XMALLOC(sizeof(ecc_point), 0, DYNAMIC_TYPE_BIGINT); + if (p == NULL) { + return NULL; + } + XMEMSET(p, 0, sizeof(ecc_point)); + if (mp_init_multi(&p->x, &p->y, &p->z, NULL, NULL, NULL) != MP_OKAY) { + XFREE(p, 0, DYNAMIC_TYPE_BIGINT); + return NULL; + } + return p; +} + +/** Free an ECC point from memory + p The point to free +*/ +void ecc_del_point(ecc_point* p) +{ + /* prevents free'ing null arguments */ + if (p != NULL) { + mp_clear(&p->x); + mp_clear(&p->y); + mp_clear(&p->z); + XFREE(p, 0, DYNAMIC_TYPE_BIGINT); + } +} + + +/** Returns whether an ECC idx is valid or not + n The idx number to check + return 1 if valid, 0 if not +*/ +static int ecc_is_valid_idx(int n) +{ + int x; + + for (x = 0; ecc_sets[x].size != 0; x++) + ; + /* -1 is a valid index --- indicating that the domain params + were supplied by the user */ + if ((n >= -1) && (n < x)) { + return 1; + } + return 0; +} + + +/** + Create an ECC shared secret between two keys + private_key The private ECC key + public_key The public key + out [out] Destination of the shared secret + Conforms to EC-DH from ANSI X9.63 + outlen [in/out] The max size and resulting size of the shared secret + return MP_OKAY if successful +*/ +int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, + word32* outlen) +{ + word32 x = 0; + ecc_point* result; + mp_int prime; + int err; + + if (private_key == NULL || public_key == NULL || out == NULL || + outlen == NULL) + return BAD_FUNC_ARG; + + /* type valid? */ + if (private_key->type != ECC_PRIVATEKEY) { + return ECC_BAD_ARG_E; + } + + if (ecc_is_valid_idx(private_key->idx) == 0 || + ecc_is_valid_idx(public_key->idx) == 0) + return ECC_BAD_ARG_E; + + if (XSTRNCMP(private_key->dp->name, public_key->dp->name, ECC_MAXNAME) != 0) + return ECC_BAD_ARG_E; + + /* make new point */ + result = ecc_new_point(); + if (result == NULL) { + return MEMORY_E; + } + + if ((err = mp_init(&prime)) != MP_OKAY) { + ecc_del_point(result); + return err; + } + + err = mp_read_radix(&prime, (char *)private_key->dp->prime, 16); + + if (err == MP_OKAY) + err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime,1); + + if (err == MP_OKAY) { + x = mp_unsigned_bin_size(&prime); + if (*outlen < x) + err = BUFFER_E; + } + + if (err == MP_OKAY) { + XMEMSET(out, 0, x); + err = mp_to_unsigned_bin(&result->x,out + (x - + mp_unsigned_bin_size(&result->x))); + *outlen = x; + } + + mp_clear(&prime); + ecc_del_point(result); + + return err; +} + + +int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp); + +/** + Make a new ECC key + rng An active RNG state + keysize The keysize for the new key (in octets from 20 to 65 bytes) + key [out] Destination of the newly created key + return MP_OKAY if successful, + upon error all allocated memory will be freed +*/ +int wc_ecc_make_key(RNG* rng, int keysize, ecc_key* key) +{ + int x, err; + + if (key == NULL || rng == NULL) + return ECC_BAD_ARG_E; + + /* find key size */ + for (x = 0; (keysize > ecc_sets[x].size) && (ecc_sets[x].size != 0); x++) + ; + keysize = ecc_sets[x].size; + + if (keysize > ECC_MAXSIZE || ecc_sets[x].size == 0) { + return BAD_FUNC_ARG; + } + err = wc_ecc_make_key_ex(rng, key, &ecc_sets[x]); + key->idx = x; + + return err; +} + +int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp) +{ + int err; + ecc_point* base; + mp_int prime; + mp_int order; +#ifdef CYASSL_SMALL_STACK + byte* buf; +#else + byte buf[ECC_MAXSIZE]; +#endif + int keysize; + + if (key == NULL || rng == NULL || dp == NULL) + return ECC_BAD_ARG_E; + +#ifdef CYASSL_SMALL_STACK + buf = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) + return MEMORY_E; +#endif + + key->idx = -1; + key->dp = dp; + keysize = dp->size; + + /* allocate ram */ + base = NULL; + + /* make up random string */ + err = RNG_GenerateBlock(rng, buf, keysize); + if (err == 0) + buf[0] |= 0x0c; + + /* setup the key variables */ + if (err == 0) { + err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, + &key->k, &prime, &order); + if (err != MP_OKAY) + err = MEMORY_E; + } + + if (err == MP_OKAY) { + base = ecc_new_point(); + if (base == NULL) + err = MEMORY_E; + } + + /* read in the specs for this key */ + if (err == MP_OKAY) + err = mp_read_radix(&prime, (char *)key->dp->prime, 16); + if (err == MP_OKAY) + err = mp_read_radix(&order, (char *)key->dp->order, 16); + if (err == MP_OKAY) + err = mp_read_radix(&base->x, (char *)key->dp->Gx, 16); + if (err == MP_OKAY) + err = mp_read_radix(&base->y, (char *)key->dp->Gy, 16); + + if (err == MP_OKAY) + mp_set(&base->z, 1); + if (err == MP_OKAY) + err = mp_read_unsigned_bin(&key->k, (byte*)buf, keysize); + + /* the key should be smaller than the order of base point */ + if (err == MP_OKAY) { + if (mp_cmp(&key->k, &order) != MP_LT) + err = mp_mod(&key->k, &order, &key->k); + } + /* make the public key */ + if (err == MP_OKAY) + err = ecc_mulmod(&key->k, base, &key->pubkey, &prime, 1); + if (err == MP_OKAY) + key->type = ECC_PRIVATEKEY; + + if (err != MP_OKAY) { + /* clean up */ + mp_clear(&key->pubkey.x); + mp_clear(&key->pubkey.y); + mp_clear(&key->pubkey.z); + mp_clear(&key->k); + } + ecc_del_point(base); + mp_clear(&prime); + mp_clear(&order); + +#ifdef ECC_CLEAN_STACK + XMEMSET(buf, 0, ECC_MAXSIZE); +#endif + +#ifdef CYASSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return err; +} + + +/* Setup dynamic pointers is using normal math for proper freeing */ +void wc_ecc_init(ecc_key* key) +{ + (void)key; +#ifndef USE_FAST_MATH + key->pubkey.x.dp = NULL; + key->pubkey.y.dp = NULL; + key->pubkey.z.dp = NULL; + + key->k.dp = NULL; +#endif +} + + +/** + Sign a message digest + in The message digest to sign + inlen The length of the digest + out [out] The destination for the signature + outlen [in/out] The max size and resulting size of the signature + key A private ECC key + return MP_OKAY if successful +*/ +int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, + RNG* rng, ecc_key* key) +{ + mp_int r; + mp_int s; + mp_int e; + mp_int p; + int err; + + if (in == NULL || out == NULL || outlen == NULL || key == NULL || rng ==NULL) + return ECC_BAD_ARG_E; + + /* is this a private key? */ + if (key->type != ECC_PRIVATEKEY) { + return ECC_BAD_ARG_E; + } + + /* is the IDX valid ? */ + if (ecc_is_valid_idx(key->idx) != 1) { + return ECC_BAD_ARG_E; + } + + /* get the hash and load it as a bignum into 'e' */ + /* init the bignums */ + if ((err = mp_init_multi(&r, &s, &p, &e, NULL, NULL)) != MP_OKAY) { + return err; + } + err = mp_read_radix(&p, (char *)key->dp->order, 16); + + if (err == MP_OKAY) { + /* we may need to truncate if hash is longer than key size */ + word32 orderBits = mp_count_bits(&p); + + /* truncate down to byte size, may be all that's needed */ + if ( (CYASSL_BIT_SIZE * inlen) > orderBits) + inlen = (orderBits + CYASSL_BIT_SIZE - 1)/CYASSL_BIT_SIZE; + err = mp_read_unsigned_bin(&e, (byte*)in, inlen); + + /* may still need bit truncation too */ + if (err == MP_OKAY && (CYASSL_BIT_SIZE * inlen) > orderBits) + mp_rshb(&e, CYASSL_BIT_SIZE - (orderBits & 0x7)); + } + + /* make up a key and export the public copy */ + if (err == MP_OKAY) { + ecc_key pubkey; + wc_ecc_init(&pubkey); + for (;;) { + err = wc_ecc_make_key_ex(rng, &pubkey, key->dp); + if (err != MP_OKAY) break; + + /* find r = x1 mod n */ + err = mp_mod(&pubkey.pubkey.x, &p, &r); + if (err != MP_OKAY) break; + + if (mp_iszero(&r) == MP_YES) + wc_ecc_free(&pubkey); + else { + /* find s = (e + xr)/k */ + err = mp_invmod(&pubkey.k, &p, &pubkey.k); + if (err != MP_OKAY) break; + + err = mp_mulmod(&key->k, &r, &p, &s); /* s = xr */ + if (err != MP_OKAY) break; + + err = mp_add(&e, &s, &s); /* s = e + xr */ + if (err != MP_OKAY) break; + + err = mp_mod(&s, &p, &s); /* s = e + xr */ + if (err != MP_OKAY) break; + + err = mp_mulmod(&s, &pubkey.k, &p, &s); /* s = (e + xr)/k */ + if (err != MP_OKAY) break; + + wc_ecc_free(&pubkey); + if (mp_iszero(&s) == MP_NO) + break; + } + } + wc_ecc_free(&pubkey); + } + + /* store as SEQUENCE { r, s -- integer } */ + if (err == MP_OKAY) + err = StoreECC_DSA_Sig(out, outlen, &r, &s); + + mp_clear(&r); + mp_clear(&s); + mp_clear(&p); + mp_clear(&e); + + return err; +} + + +/** + Free an ECC key from memory + key The key you wish to free +*/ +void wc_ecc_free(ecc_key* key) +{ + if (key == NULL) + return; + + mp_clear(&key->pubkey.x); + mp_clear(&key->pubkey.y); + mp_clear(&key->pubkey.z); + mp_clear(&key->k); +} + + +#ifdef USE_FAST_MATH + #define GEN_MEM_ERR FP_MEM +#else + #define GEN_MEM_ERR MP_MEM +#endif + +#ifdef ECC_SHAMIR + +/** Computes kA*A + kB*B = C using Shamir's Trick + A First point to multiply + kA What to multiple A by + B Second point to multiply + kB What to multiple B by + C [out] Destination point (can overlap with A or B) + modulus Modulus for curve + return MP_OKAY on success +*/ +#ifdef FP_ECC +static int normal_ecc_mul2add(ecc_point* A, mp_int* kA, + ecc_point* B, mp_int* kB, + ecc_point* C, mp_int* modulus) +#else +static int ecc_mul2add(ecc_point* A, mp_int* kA, + ecc_point* B, mp_int* kB, + ecc_point* C, mp_int* modulus) +#endif +{ + ecc_point* precomp[16]; + unsigned bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble; + unsigned char* tA; + unsigned char* tB; + int err = MP_OKAY, first; + int muInit = 0; + int tableInit = 0; + mp_digit mp; + mp_int mu; + + /* argchks */ + if (A == NULL || kA == NULL || B == NULL || kB == NULL || C == NULL || + modulus == NULL) + return ECC_BAD_ARG_E; + + + /* allocate memory */ + tA = (unsigned char*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tA == NULL) { + return GEN_MEM_ERR; + } + tB = (unsigned char*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tB == NULL) { + XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return GEN_MEM_ERR; + } + XMEMSET(tA, 0, ECC_BUFSIZE); + XMEMSET(tB, 0, ECC_BUFSIZE); + + /* get sizes */ + lenA = mp_unsigned_bin_size(kA); + lenB = mp_unsigned_bin_size(kB); + len = MAX(lenA, lenB); + + /* sanity check */ + if ((lenA > ECC_BUFSIZE) || (lenB > ECC_BUFSIZE)) { + err = BAD_FUNC_ARG; + } + + if (err == MP_OKAY) { + /* extract and justify kA */ + err = mp_to_unsigned_bin(kA, (len - lenA) + tA); + + /* extract and justify kB */ + if (err == MP_OKAY) + err = mp_to_unsigned_bin(kB, (len - lenB) + tB); + + /* allocate the table */ + if (err == MP_OKAY) { + for (x = 0; x < 16; x++) { + precomp[x] = ecc_new_point(); + if (precomp[x] == NULL) { + for (y = 0; y < x; ++y) { + ecc_del_point(precomp[y]); + } + err = GEN_MEM_ERR; + break; + } + } + } + } + + if (err == MP_OKAY) + tableInit = 1; + + if (err == MP_OKAY) + /* init montgomery reduction */ + err = mp_montgomery_setup(modulus, &mp); + + if (err == MP_OKAY) + err = mp_init(&mu); + if (err == MP_OKAY) + muInit = 1; + + if (err == MP_OKAY) + err = mp_montgomery_calc_normalization(&mu, modulus); + + if (err == MP_OKAY) + /* copy ones ... */ + err = mp_mulmod(&A->x, &mu, modulus, &precomp[1]->x); + + if (err == MP_OKAY) + err = mp_mulmod(&A->y, &mu, modulus, &precomp[1]->y); + if (err == MP_OKAY) + err = mp_mulmod(&A->z, &mu, modulus, &precomp[1]->z); + + if (err == MP_OKAY) + err = mp_mulmod(&B->x, &mu, modulus, &precomp[1<<2]->x); + if (err == MP_OKAY) + err = mp_mulmod(&B->y, &mu, modulus, &precomp[1<<2]->y); + if (err == MP_OKAY) + err = mp_mulmod(&B->z, &mu, modulus, &precomp[1<<2]->z); + + if (err == MP_OKAY) + /* precomp [i,0](A + B) table */ + err = ecc_projective_dbl_point(precomp[1], precomp[2], modulus, &mp); + + if (err == MP_OKAY) + err = ecc_projective_add_point(precomp[1], precomp[2], precomp[3], + modulus, &mp); + if (err == MP_OKAY) + /* precomp [0,i](A + B) table */ + err = ecc_projective_dbl_point(precomp[1<<2], precomp[2<<2], modulus, &mp); + + if (err == MP_OKAY) + err = ecc_projective_add_point(precomp[1<<2], precomp[2<<2], precomp[3<<2], + modulus, &mp); + + if (err == MP_OKAY) { + /* precomp [i,j](A + B) table (i != 0, j != 0) */ + for (x = 1; x < 4; x++) { + for (y = 1; y < 4; y++) { + if (err == MP_OKAY) + err = ecc_projective_add_point(precomp[x], precomp[(y<<2)], + precomp[x+(y<<2)], modulus, &mp); + } + } + } + + if (err == MP_OKAY) { + nibble = 3; + first = 1; + bitbufA = tA[0]; + bitbufB = tB[0]; + + /* for every byte of the multiplicands */ + for (x = -1;; ) { + /* grab a nibble */ + if (++nibble == 4) { + ++x; if (x == len) break; + bitbufA = tA[x]; + bitbufB = tB[x]; + nibble = 0; + } + + /* extract two bits from both, shift/update */ + nA = (bitbufA >> 6) & 0x03; + nB = (bitbufB >> 6) & 0x03; + bitbufA = (bitbufA << 2) & 0xFF; + bitbufB = (bitbufB << 2) & 0xFF; + + /* if both zero, if first, continue */ + if ((nA == 0) && (nB == 0) && (first == 1)) { + continue; + } + + /* double twice, only if this isn't the first */ + if (first == 0) { + /* double twice */ + if (err == MP_OKAY) + err = ecc_projective_dbl_point(C, C, modulus, &mp); + if (err == MP_OKAY) + err = ecc_projective_dbl_point(C, C, modulus, &mp); + else + break; + } + + /* if not both zero */ + if ((nA != 0) || (nB != 0)) { + if (first == 1) { + /* if first, copy from table */ + first = 0; + if (err == MP_OKAY) + err = mp_copy(&precomp[nA + (nB<<2)]->x, &C->x); + + if (err == MP_OKAY) + err = mp_copy(&precomp[nA + (nB<<2)]->y, &C->y); + + if (err == MP_OKAY) + err = mp_copy(&precomp[nA + (nB<<2)]->z, &C->z); + else + break; + } else { + /* if not first, add from table */ + if (err == MP_OKAY) + err = ecc_projective_add_point(C, precomp[nA + (nB<<2)], C, + modulus, &mp); + else + break; + } + } + } + } + + if (err == MP_OKAY) + /* reduce to affine */ + err = ecc_map(C, modulus, &mp); + + /* clean up */ + if (muInit) + mp_clear(&mu); + + if (tableInit) { + for (x = 0; x < 16; x++) { + ecc_del_point(precomp[x]); + } + } +#ifdef ECC_CLEAN_STACK + XMEMSET(tA, 0, ECC_BUFSIZE); + XMEMSET(tB, 0, ECC_BUFSIZE); +#endif + XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(tB, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return err; +} + + +#endif /* ECC_SHAMIR */ + + + +/* verify + * + * w = s^-1 mod n + * u1 = xw + * u2 = rw + * X = u1*G + u2*Q + * v = X_x1 mod n + * accept if v == r + */ + +/** + Verify an ECC signature + sig The signature to verify + siglen The length of the signature (octets) + hash The hash (message digest) that was signed + hashlen The length of the hash (octets) + stat Result of signature, 1==valid, 0==invalid + key The corresponding public ECC key + return MP_OKAY if successful (even if the signature is not valid) +*/ +int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, + word32 hashlen, int* stat, ecc_key* key) +{ + ecc_point *mG, *mQ; + mp_int r; + mp_int s; + mp_int v; + mp_int w; + mp_int u1; + mp_int u2; + mp_int e; + mp_int p; + mp_int m; + int err; + + if (sig == NULL || hash == NULL || stat == NULL || key == NULL) + return ECC_BAD_ARG_E; + + /* default to invalid signature */ + *stat = 0; + + /* is the IDX valid ? */ + if (ecc_is_valid_idx(key->idx) != 1) { + return ECC_BAD_ARG_E; + } + + /* allocate ints */ + if ((err = mp_init_multi(&v, &w, &u1, &u2, &p, &e)) != MP_OKAY) { + return MEMORY_E; + } + + if ((err = mp_init(&m)) != MP_OKAY) { + mp_clear(&v); + mp_clear(&w); + mp_clear(&u1); + mp_clear(&u2); + mp_clear(&p); + mp_clear(&e); + return MEMORY_E; + } + + /* allocate points */ + mG = ecc_new_point(); + mQ = ecc_new_point(); + if (mQ == NULL || mG == NULL) + err = MEMORY_E; + + /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s. + * If either of those don't allocate correctly, none of + * the rest of this function will execute, and everything + * gets cleaned up at the end. */ + XMEMSET(&r, 0, sizeof(r)); + XMEMSET(&s, 0, sizeof(s)); + if (err == MP_OKAY) + err = DecodeECC_DSA_Sig(sig, siglen, &r, &s); + + /* get the order */ + if (err == MP_OKAY) + err = mp_read_radix(&p, (char *)key->dp->order, 16); + + /* get the modulus */ + if (err == MP_OKAY) + err = mp_read_radix(&m, (char *)key->dp->prime, 16); + + /* check for zero */ + if (err == MP_OKAY) { + if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT || + mp_cmp(&s, &p) != MP_LT) + err = MP_ZERO_E; + } + /* read hash */ + if (err == MP_OKAY) { + /* we may need to truncate if hash is longer than key size */ + unsigned int orderBits = mp_count_bits(&p); + + /* truncate down to byte size, may be all that's needed */ + if ( (CYASSL_BIT_SIZE * hashlen) > orderBits) + hashlen = (orderBits + CYASSL_BIT_SIZE - 1)/CYASSL_BIT_SIZE; + err = mp_read_unsigned_bin(&e, hash, hashlen); + + /* may still need bit truncation too */ + if (err == MP_OKAY && (CYASSL_BIT_SIZE * hashlen) > orderBits) + mp_rshb(&e, CYASSL_BIT_SIZE - (orderBits & 0x7)); + } + + /* w = s^-1 mod n */ + if (err == MP_OKAY) + err = mp_invmod(&s, &p, &w); + + /* u1 = ew */ + if (err == MP_OKAY) + err = mp_mulmod(&e, &w, &p, &u1); + + /* u2 = rw */ + if (err == MP_OKAY) + err = mp_mulmod(&r, &w, &p, &u2); + + /* find mG and mQ */ + if (err == MP_OKAY) + err = mp_read_radix(&mG->x, (char *)key->dp->Gx, 16); + + if (err == MP_OKAY) + err = mp_read_radix(&mG->y, (char *)key->dp->Gy, 16); + if (err == MP_OKAY) + mp_set(&mG->z, 1); + + if (err == MP_OKAY) + err = mp_copy(&key->pubkey.x, &mQ->x); + if (err == MP_OKAY) + err = mp_copy(&key->pubkey.y, &mQ->y); + if (err == MP_OKAY) + err = mp_copy(&key->pubkey.z, &mQ->z); + +#ifndef ECC_SHAMIR + { + mp_digit mp; + + /* compute u1*mG + u2*mQ = mG */ + if (err == MP_OKAY) + err = ecc_mulmod(&u1, mG, mG, &m, 0); + if (err == MP_OKAY) + err = ecc_mulmod(&u2, mQ, mQ, &m, 0); + + /* find the montgomery mp */ + if (err == MP_OKAY) + err = mp_montgomery_setup(&m, &mp); + + /* add them */ + if (err == MP_OKAY) + err = ecc_projective_add_point(mQ, mG, mG, &m, &mp); + + /* reduce */ + if (err == MP_OKAY) + err = ecc_map(mG, &m, &mp); + } +#else + /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */ + if (err == MP_OKAY) + err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &m); +#endif /* ECC_SHAMIR */ + + /* v = X_x1 mod n */ + if (err == MP_OKAY) + err = mp_mod(&mG->x, &p, &v); + + /* does v == r */ + if (err == MP_OKAY) { + if (mp_cmp(&v, &r) == MP_EQ) + *stat = 1; + } + + ecc_del_point(mG); + ecc_del_point(mQ); + + mp_clear(&r); + mp_clear(&s); + mp_clear(&v); + mp_clear(&w); + mp_clear(&u1); + mp_clear(&u2); + mp_clear(&p); + mp_clear(&e); + mp_clear(&m); + + return err; +} + + +/* export public ECC key in ANSI X9.63 format */ +int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) +{ +#ifdef CYASSL_SMALL_STACK + byte* buf; +#else + byte buf[ECC_BUFSIZE]; +#endif + word32 numlen; + int ret = MP_OKAY; + + /* return length needed only */ + if (key != NULL && out == NULL && outLen != NULL) { + numlen = key->dp->size; + *outLen = 1 + 2*numlen; + return LENGTH_ONLY_E; + } + + if (key == NULL || out == NULL || outLen == NULL) + return ECC_BAD_ARG_E; + + if (ecc_is_valid_idx(key->idx) == 0) { + return ECC_BAD_ARG_E; + } + numlen = key->dp->size; + + if (*outLen < (1 + 2*numlen)) { + *outLen = 1 + 2*numlen; + return BUFFER_E; + } + + /* store byte 0x04 */ + out[0] = 0x04; + +#ifdef CYASSL_SMALL_STACK + buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) + return MEMORY_E; +#endif + + do { + /* pad and store x */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(&key->pubkey.x, + buf + (numlen - mp_unsigned_bin_size(&key->pubkey.x))); + if (ret != MP_OKAY) + break; + XMEMCPY(out+1, buf, numlen); + + /* pad and store y */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(&key->pubkey.y, + buf + (numlen - mp_unsigned_bin_size(&key->pubkey.y))); + if (ret != MP_OKAY) + break; + XMEMCPY(out+1+numlen, buf, numlen); + + *outLen = 1 + 2*numlen; + } while (0); + +#ifdef CYASSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +/* export public ECC key in ANSI X9.63 format, extended with + * compression option */ +int wc_wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, int compressed) +{ + if (compressed == 0) + return wc_ecc_export_x963(key, out, outLen); +#ifdef HAVE_COMP_KEY + else + return wc_ecc_export_x963_compressed(key, out, outLen); +#endif + + return NOT_COMPILED_IN; +} + + +/* import public ECC key in ANSI X9.63 format */ +int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) +{ + int x, err; + int compressed = 0; + + if (in == NULL || key == NULL) + return ECC_BAD_ARG_E; + + /* must be odd */ + if ((inLen & 1) == 0) { + return ECC_BAD_ARG_E; + } + + /* init key */ + if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, + NULL, NULL) != MP_OKAY) { + return MEMORY_E; + } + err = MP_OKAY; + + /* check for 4, 2, or 3 */ + if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) { + err = ASN_PARSE_E; + } + + if (in[0] == 0x02 || in[0] == 0x03) { +#ifdef HAVE_COMP_KEY + compressed = 1; +#else + err = NOT_COMPILED_IN; +#endif + } + + if (err == MP_OKAY) { + /* determine the idx */ + + if (compressed) + inLen = (inLen-1)*2 + 1; /* used uncompressed len */ + + for (x = 0; ecc_sets[x].size != 0; x++) { + if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) { + break; + } + } + if (ecc_sets[x].size == 0) { + err = ASN_PARSE_E; + } else { + /* set the idx */ + key->idx = x; + key->dp = &ecc_sets[x]; + key->type = ECC_PUBLICKEY; + } + } + + /* read data */ + if (err == MP_OKAY) + err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1); + +#ifdef HAVE_COMP_KEY + if (err == MP_OKAY && compressed == 1) { /* build y */ + mp_int t1, t2, prime, a, b; + + if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY) + err = MEMORY_E; + + /* load prime */ + if (err == MP_OKAY) + err = mp_read_radix(&prime, (char *)key->dp->prime, 16); + + /* load a */ + if (err == MP_OKAY) + err = mp_read_radix(&a, (char *)key->dp->Af, 16); + + /* load b */ + if (err == MP_OKAY) + err = mp_read_radix(&b, (char *)key->dp->Bf, 16); + + /* compute x^3 */ + if (err == MP_OKAY) + err = mp_sqr(&key->pubkey.x, &t1); + + if (err == MP_OKAY) + err = mp_mulmod(&t1, &key->pubkey.x, &prime, &t1); + + /* compute x^3 + a*x */ + if (err == MP_OKAY) + err = mp_mulmod(&a, &key->pubkey.x, &prime, &t2); + + if (err == MP_OKAY) + err = mp_add(&t1, &t2, &t1); + + /* compute x^3 + a*x + b */ + if (err == MP_OKAY) + err = mp_add(&t1, &b, &t1); + + /* compute sqrt(x^3 + a*x + b) */ + if (err == MP_OKAY) + err = mp_sqrtmod_prime(&t1, &prime, &t2); + + /* adjust y */ + if (err == MP_OKAY) { + if ((mp_isodd(&t2) && in[0] == 0x03) || + (!mp_isodd(&t2) && in[0] == 0x02)) { + err = mp_mod(&t2, &prime, &key->pubkey.y); + } + else { + err = mp_submod(&prime, &t2, &prime, &key->pubkey.y); + } + } + + mp_clear(&a); + mp_clear(&b); + mp_clear(&prime); + mp_clear(&t2); + mp_clear(&t1); + } +#endif + + if (err == MP_OKAY && compressed == 0) + err = mp_read_unsigned_bin(&key->pubkey.y, (byte*)in+1+((inLen-1)>>1), + (inLen-1)>>1); + if (err == MP_OKAY) + mp_set(&key->pubkey.z, 1); + + if (err != MP_OKAY) { + mp_clear(&key->pubkey.x); + mp_clear(&key->pubkey.y); + mp_clear(&key->pubkey.z); + mp_clear(&key->k); + } + + return err; +} + + +/* export ecc private key only raw, outLen is in/out size + return MP_OKAY on success */ +int wc_ecc_export_private_only(ecc_key* key, byte* out, word32* outLen) +{ + word32 numlen; + + if (key == NULL || out == NULL || outLen == NULL) + return ECC_BAD_ARG_E; + + if (ecc_is_valid_idx(key->idx) == 0) { + return ECC_BAD_ARG_E; + } + numlen = key->dp->size; + + if (*outLen < numlen) { + *outLen = numlen; + return BUFFER_E; + } + *outLen = numlen; + XMEMSET(out, 0, *outLen); + return mp_to_unsigned_bin(&key->k, out + (numlen - + mp_unsigned_bin_size(&key->k))); +} + + +/* ecc private key import, public key in ANSI X9.63 format, private raw */ +int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, + word32 pubSz, ecc_key* key) +{ + int ret = wc_ecc_import_x963(pub, pubSz, key); + if (ret != 0) + return ret; + + key->type = ECC_PRIVATEKEY; + + return mp_read_unsigned_bin(&key->k, priv, privSz); +} + +/** + Convert ECC R,S to signature + r R component of signature + s S component of signature + out DER-encoded ECDSA signature + outlen [in/out] output buffer size, output signature size + return MP_OKAY on success +*/ +int wc_ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen) +{ + int err; + mp_int rtmp; + mp_int stmp; + + if (r == NULL || s == NULL || out == NULL || outlen == NULL) + return ECC_BAD_ARG_E; + + err = mp_init_multi(&rtmp, &stmp, NULL, NULL, NULL, NULL); + if (err != MP_OKAY) + return err; + + err = mp_read_radix(&rtmp, r, 16); + if (err == MP_OKAY) + err = mp_read_radix(&stmp, s, 16); + + /* convert mp_ints to ECDSA sig, initializes rtmp and stmp internally */ + if (err == MP_OKAY) + err = StoreECC_DSA_Sig(out, outlen, &rtmp, &stmp); + + if (err == MP_OKAY) { + if (mp_iszero(&rtmp) || mp_iszero(&stmp)) + err = MP_ZERO_E; + } + + mp_clear(&rtmp); + mp_clear(&stmp); + + return err; +} + +/** + Import raw ECC key + key The destination ecc_key structure + qx x component of base point, as ASCII hex string + qy y component of base point, as ASCII hex string + d private key, as ASCII hex string + curveName ECC curve name, from ecc_sets[] + return MP_OKAY on success +*/ +int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, + const char* d, const char* curveName) +{ + int err, x; + + if (key == NULL || qx == NULL || qy == NULL || d == NULL || + curveName == NULL) + return ECC_BAD_ARG_E; + + /* init key */ + if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, + NULL, NULL) != MP_OKAY) { + return MEMORY_E; + } + err = MP_OKAY; + + /* read Qx */ + if (err == MP_OKAY) + err = mp_read_radix(&key->pubkey.x, qx, 16); + + /* read Qy */ + if (err == MP_OKAY) + err = mp_read_radix(&key->pubkey.y, qy, 16); + + if (err == MP_OKAY) + mp_set(&key->pubkey.z, 1); + + /* read and set the curve */ + if (err == MP_OKAY) { + for (x = 0; ecc_sets[x].size != 0; x++) { + if (XSTRNCMP(ecc_sets[x].name, curveName, + XSTRLEN(curveName)) == 0) { + break; + } + } + if (ecc_sets[x].size == 0) { + err = ASN_PARSE_E; + } else { + /* set the curve */ + key->idx = x; + key->dp = &ecc_sets[x]; + key->type = ECC_PUBLICKEY; + } + } + + /* import private key */ + if (err == MP_OKAY) { + key->type = ECC_PRIVATEKEY; + err = mp_read_radix(&key->k, d, 16); + } + + if (err != MP_OKAY) { + mp_clear(&key->pubkey.x); + mp_clear(&key->pubkey.y); + mp_clear(&key->pubkey.z); + mp_clear(&key->k); + } + + return err; +} + + +/* key size in octets */ +int wc_ecc_size(ecc_key* key) +{ + if (key == NULL) return 0; + + return key->dp->size; +} + + +/* worst case estimate, check actual return from wc_ecc_sign_hash for actual value + of signature size in octets */ +int wc_ecc_sig_size(ecc_key* key) +{ + int sz = wc_ecc_size(key); + if (sz < 0) + return sz; + + return sz * 2 + SIG_HEADER_SZ + 4; /* (4) worst case estimate */ +} + + +#ifdef FP_ECC + +/* fixed point ECC cache */ +/* number of entries in the cache */ +#ifndef FP_ENTRIES + #define FP_ENTRIES 16 +#endif + +/* number of bits in LUT */ +#ifndef FP_LUT + #define FP_LUT 8U +#endif + +#ifdef ECC_SHAMIR + /* Sharmir requires a bigger LUT, TAO */ + #if (FP_LUT > 12) || (FP_LUT < 4) + #error FP_LUT must be between 4 and 12 inclusively + #endif +#else + #if (FP_LUT > 12) || (FP_LUT < 2) + #error FP_LUT must be between 2 and 12 inclusively + #endif +#endif + + +/** Our FP cache */ +typedef struct { + ecc_point* g; /* cached COPY of base point */ + ecc_point* LUT[1U< 6 + { 1, 0, 0 }, { 2, 1, 64 }, { 2, 2, 64 }, { 3, 3, 64 }, { 2, 4, 64 }, { 3, 5, 64 }, { 3, 6, 64 }, { 4, 7, 64 }, + { 2, 8, 64 }, { 3, 9, 64 }, { 3, 10, 64 }, { 4, 11, 64 }, { 3, 12, 64 }, { 4, 13, 64 }, { 4, 14, 64 }, { 5, 15, 64 }, + { 2, 16, 64 }, { 3, 17, 64 }, { 3, 18, 64 }, { 4, 19, 64 }, { 3, 20, 64 }, { 4, 21, 64 }, { 4, 22, 64 }, { 5, 23, 64 }, + { 3, 24, 64 }, { 4, 25, 64 }, { 4, 26, 64 }, { 5, 27, 64 }, { 4, 28, 64 }, { 5, 29, 64 }, { 5, 30, 64 }, { 6, 31, 64 }, + { 2, 32, 64 }, { 3, 33, 64 }, { 3, 34, 64 }, { 4, 35, 64 }, { 3, 36, 64 }, { 4, 37, 64 }, { 4, 38, 64 }, { 5, 39, 64 }, + { 3, 40, 64 }, { 4, 41, 64 }, { 4, 42, 64 }, { 5, 43, 64 }, { 4, 44, 64 }, { 5, 45, 64 }, { 5, 46, 64 }, { 6, 47, 64 }, + { 3, 48, 64 }, { 4, 49, 64 }, { 4, 50, 64 }, { 5, 51, 64 }, { 4, 52, 64 }, { 5, 53, 64 }, { 5, 54, 64 }, { 6, 55, 64 }, + { 4, 56, 64 }, { 5, 57, 64 }, { 5, 58, 64 }, { 6, 59, 64 }, { 5, 60, 64 }, { 6, 61, 64 }, { 6, 62, 64 }, { 7, 63, 64 }, +#if FP_LUT > 7 + { 1, 0, 0 }, { 2, 1, 128 }, { 2, 2, 128 }, { 3, 3, 128 }, { 2, 4, 128 }, { 3, 5, 128 }, { 3, 6, 128 }, { 4, 7, 128 }, + { 2, 8, 128 }, { 3, 9, 128 }, { 3, 10, 128 }, { 4, 11, 128 }, { 3, 12, 128 }, { 4, 13, 128 }, { 4, 14, 128 }, { 5, 15, 128 }, + { 2, 16, 128 }, { 3, 17, 128 }, { 3, 18, 128 }, { 4, 19, 128 }, { 3, 20, 128 }, { 4, 21, 128 }, { 4, 22, 128 }, { 5, 23, 128 }, + { 3, 24, 128 }, { 4, 25, 128 }, { 4, 26, 128 }, { 5, 27, 128 }, { 4, 28, 128 }, { 5, 29, 128 }, { 5, 30, 128 }, { 6, 31, 128 }, + { 2, 32, 128 }, { 3, 33, 128 }, { 3, 34, 128 }, { 4, 35, 128 }, { 3, 36, 128 }, { 4, 37, 128 }, { 4, 38, 128 }, { 5, 39, 128 }, + { 3, 40, 128 }, { 4, 41, 128 }, { 4, 42, 128 }, { 5, 43, 128 }, { 4, 44, 128 }, { 5, 45, 128 }, { 5, 46, 128 }, { 6, 47, 128 }, + { 3, 48, 128 }, { 4, 49, 128 }, { 4, 50, 128 }, { 5, 51, 128 }, { 4, 52, 128 }, { 5, 53, 128 }, { 5, 54, 128 }, { 6, 55, 128 }, + { 4, 56, 128 }, { 5, 57, 128 }, { 5, 58, 128 }, { 6, 59, 128 }, { 5, 60, 128 }, { 6, 61, 128 }, { 6, 62, 128 }, { 7, 63, 128 }, + { 2, 64, 128 }, { 3, 65, 128 }, { 3, 66, 128 }, { 4, 67, 128 }, { 3, 68, 128 }, { 4, 69, 128 }, { 4, 70, 128 }, { 5, 71, 128 }, + { 3, 72, 128 }, { 4, 73, 128 }, { 4, 74, 128 }, { 5, 75, 128 }, { 4, 76, 128 }, { 5, 77, 128 }, { 5, 78, 128 }, { 6, 79, 128 }, + { 3, 80, 128 }, { 4, 81, 128 }, { 4, 82, 128 }, { 5, 83, 128 }, { 4, 84, 128 }, { 5, 85, 128 }, { 5, 86, 128 }, { 6, 87, 128 }, + { 4, 88, 128 }, { 5, 89, 128 }, { 5, 90, 128 }, { 6, 91, 128 }, { 5, 92, 128 }, { 6, 93, 128 }, { 6, 94, 128 }, { 7, 95, 128 }, + { 3, 96, 128 }, { 4, 97, 128 }, { 4, 98, 128 }, { 5, 99, 128 }, { 4, 100, 128 }, { 5, 101, 128 }, { 5, 102, 128 }, { 6, 103, 128 }, + { 4, 104, 128 }, { 5, 105, 128 }, { 5, 106, 128 }, { 6, 107, 128 }, { 5, 108, 128 }, { 6, 109, 128 }, { 6, 110, 128 }, { 7, 111, 128 }, + { 4, 112, 128 }, { 5, 113, 128 }, { 5, 114, 128 }, { 6, 115, 128 }, { 5, 116, 128 }, { 6, 117, 128 }, { 6, 118, 128 }, { 7, 119, 128 }, + { 5, 120, 128 }, { 6, 121, 128 }, { 6, 122, 128 }, { 7, 123, 128 }, { 6, 124, 128 }, { 7, 125, 128 }, { 7, 126, 128 }, { 8, 127, 128 }, +#if FP_LUT > 8 + { 1, 0, 0 }, { 2, 1, 256 }, { 2, 2, 256 }, { 3, 3, 256 }, { 2, 4, 256 }, { 3, 5, 256 }, { 3, 6, 256 }, { 4, 7, 256 }, + { 2, 8, 256 }, { 3, 9, 256 }, { 3, 10, 256 }, { 4, 11, 256 }, { 3, 12, 256 }, { 4, 13, 256 }, { 4, 14, 256 }, { 5, 15, 256 }, + { 2, 16, 256 }, { 3, 17, 256 }, { 3, 18, 256 }, { 4, 19, 256 }, { 3, 20, 256 }, { 4, 21, 256 }, { 4, 22, 256 }, { 5, 23, 256 }, + { 3, 24, 256 }, { 4, 25, 256 }, { 4, 26, 256 }, { 5, 27, 256 }, { 4, 28, 256 }, { 5, 29, 256 }, { 5, 30, 256 }, { 6, 31, 256 }, + { 2, 32, 256 }, { 3, 33, 256 }, { 3, 34, 256 }, { 4, 35, 256 }, { 3, 36, 256 }, { 4, 37, 256 }, { 4, 38, 256 }, { 5, 39, 256 }, + { 3, 40, 256 }, { 4, 41, 256 }, { 4, 42, 256 }, { 5, 43, 256 }, { 4, 44, 256 }, { 5, 45, 256 }, { 5, 46, 256 }, { 6, 47, 256 }, + { 3, 48, 256 }, { 4, 49, 256 }, { 4, 50, 256 }, { 5, 51, 256 }, { 4, 52, 256 }, { 5, 53, 256 }, { 5, 54, 256 }, { 6, 55, 256 }, + { 4, 56, 256 }, { 5, 57, 256 }, { 5, 58, 256 }, { 6, 59, 256 }, { 5, 60, 256 }, { 6, 61, 256 }, { 6, 62, 256 }, { 7, 63, 256 }, + { 2, 64, 256 }, { 3, 65, 256 }, { 3, 66, 256 }, { 4, 67, 256 }, { 3, 68, 256 }, { 4, 69, 256 }, { 4, 70, 256 }, { 5, 71, 256 }, + { 3, 72, 256 }, { 4, 73, 256 }, { 4, 74, 256 }, { 5, 75, 256 }, { 4, 76, 256 }, { 5, 77, 256 }, { 5, 78, 256 }, { 6, 79, 256 }, + { 3, 80, 256 }, { 4, 81, 256 }, { 4, 82, 256 }, { 5, 83, 256 }, { 4, 84, 256 }, { 5, 85, 256 }, { 5, 86, 256 }, { 6, 87, 256 }, + { 4, 88, 256 }, { 5, 89, 256 }, { 5, 90, 256 }, { 6, 91, 256 }, { 5, 92, 256 }, { 6, 93, 256 }, { 6, 94, 256 }, { 7, 95, 256 }, + { 3, 96, 256 }, { 4, 97, 256 }, { 4, 98, 256 }, { 5, 99, 256 }, { 4, 100, 256 }, { 5, 101, 256 }, { 5, 102, 256 }, { 6, 103, 256 }, + { 4, 104, 256 }, { 5, 105, 256 }, { 5, 106, 256 }, { 6, 107, 256 }, { 5, 108, 256 }, { 6, 109, 256 }, { 6, 110, 256 }, { 7, 111, 256 }, + { 4, 112, 256 }, { 5, 113, 256 }, { 5, 114, 256 }, { 6, 115, 256 }, { 5, 116, 256 }, { 6, 117, 256 }, { 6, 118, 256 }, { 7, 119, 256 }, + { 5, 120, 256 }, { 6, 121, 256 }, { 6, 122, 256 }, { 7, 123, 256 }, { 6, 124, 256 }, { 7, 125, 256 }, { 7, 126, 256 }, { 8, 127, 256 }, + { 2, 128, 256 }, { 3, 129, 256 }, { 3, 130, 256 }, { 4, 131, 256 }, { 3, 132, 256 }, { 4, 133, 256 }, { 4, 134, 256 }, { 5, 135, 256 }, + { 3, 136, 256 }, { 4, 137, 256 }, { 4, 138, 256 }, { 5, 139, 256 }, { 4, 140, 256 }, { 5, 141, 256 }, { 5, 142, 256 }, { 6, 143, 256 }, + { 3, 144, 256 }, { 4, 145, 256 }, { 4, 146, 256 }, { 5, 147, 256 }, { 4, 148, 256 }, { 5, 149, 256 }, { 5, 150, 256 }, { 6, 151, 256 }, + { 4, 152, 256 }, { 5, 153, 256 }, { 5, 154, 256 }, { 6, 155, 256 }, { 5, 156, 256 }, { 6, 157, 256 }, { 6, 158, 256 }, { 7, 159, 256 }, + { 3, 160, 256 }, { 4, 161, 256 }, { 4, 162, 256 }, { 5, 163, 256 }, { 4, 164, 256 }, { 5, 165, 256 }, { 5, 166, 256 }, { 6, 167, 256 }, + { 4, 168, 256 }, { 5, 169, 256 }, { 5, 170, 256 }, { 6, 171, 256 }, { 5, 172, 256 }, { 6, 173, 256 }, { 6, 174, 256 }, { 7, 175, 256 }, + { 4, 176, 256 }, { 5, 177, 256 }, { 5, 178, 256 }, { 6, 179, 256 }, { 5, 180, 256 }, { 6, 181, 256 }, { 6, 182, 256 }, { 7, 183, 256 }, + { 5, 184, 256 }, { 6, 185, 256 }, { 6, 186, 256 }, { 7, 187, 256 }, { 6, 188, 256 }, { 7, 189, 256 }, { 7, 190, 256 }, { 8, 191, 256 }, + { 3, 192, 256 }, { 4, 193, 256 }, { 4, 194, 256 }, { 5, 195, 256 }, { 4, 196, 256 }, { 5, 197, 256 }, { 5, 198, 256 }, { 6, 199, 256 }, + { 4, 200, 256 }, { 5, 201, 256 }, { 5, 202, 256 }, { 6, 203, 256 }, { 5, 204, 256 }, { 6, 205, 256 }, { 6, 206, 256 }, { 7, 207, 256 }, + { 4, 208, 256 }, { 5, 209, 256 }, { 5, 210, 256 }, { 6, 211, 256 }, { 5, 212, 256 }, { 6, 213, 256 }, { 6, 214, 256 }, { 7, 215, 256 }, + { 5, 216, 256 }, { 6, 217, 256 }, { 6, 218, 256 }, { 7, 219, 256 }, { 6, 220, 256 }, { 7, 221, 256 }, { 7, 222, 256 }, { 8, 223, 256 }, + { 4, 224, 256 }, { 5, 225, 256 }, { 5, 226, 256 }, { 6, 227, 256 }, { 5, 228, 256 }, { 6, 229, 256 }, { 6, 230, 256 }, { 7, 231, 256 }, + { 5, 232, 256 }, { 6, 233, 256 }, { 6, 234, 256 }, { 7, 235, 256 }, { 6, 236, 256 }, { 7, 237, 256 }, { 7, 238, 256 }, { 8, 239, 256 }, + { 5, 240, 256 }, { 6, 241, 256 }, { 6, 242, 256 }, { 7, 243, 256 }, { 6, 244, 256 }, { 7, 245, 256 }, { 7, 246, 256 }, { 8, 247, 256 }, + { 6, 248, 256 }, { 7, 249, 256 }, { 7, 250, 256 }, { 8, 251, 256 }, { 7, 252, 256 }, { 8, 253, 256 }, { 8, 254, 256 }, { 9, 255, 256 }, +#if FP_LUT > 9 + { 1, 0, 0 }, { 2, 1, 512 }, { 2, 2, 512 }, { 3, 3, 512 }, { 2, 4, 512 }, { 3, 5, 512 }, { 3, 6, 512 }, { 4, 7, 512 }, + { 2, 8, 512 }, { 3, 9, 512 }, { 3, 10, 512 }, { 4, 11, 512 }, { 3, 12, 512 }, { 4, 13, 512 }, { 4, 14, 512 }, { 5, 15, 512 }, + { 2, 16, 512 }, { 3, 17, 512 }, { 3, 18, 512 }, { 4, 19, 512 }, { 3, 20, 512 }, { 4, 21, 512 }, { 4, 22, 512 }, { 5, 23, 512 }, + { 3, 24, 512 }, { 4, 25, 512 }, { 4, 26, 512 }, { 5, 27, 512 }, { 4, 28, 512 }, { 5, 29, 512 }, { 5, 30, 512 }, { 6, 31, 512 }, + { 2, 32, 512 }, { 3, 33, 512 }, { 3, 34, 512 }, { 4, 35, 512 }, { 3, 36, 512 }, { 4, 37, 512 }, { 4, 38, 512 }, { 5, 39, 512 }, + { 3, 40, 512 }, { 4, 41, 512 }, { 4, 42, 512 }, { 5, 43, 512 }, { 4, 44, 512 }, { 5, 45, 512 }, { 5, 46, 512 }, { 6, 47, 512 }, + { 3, 48, 512 }, { 4, 49, 512 }, { 4, 50, 512 }, { 5, 51, 512 }, { 4, 52, 512 }, { 5, 53, 512 }, { 5, 54, 512 }, { 6, 55, 512 }, + { 4, 56, 512 }, { 5, 57, 512 }, { 5, 58, 512 }, { 6, 59, 512 }, { 5, 60, 512 }, { 6, 61, 512 }, { 6, 62, 512 }, { 7, 63, 512 }, + { 2, 64, 512 }, { 3, 65, 512 }, { 3, 66, 512 }, { 4, 67, 512 }, { 3, 68, 512 }, { 4, 69, 512 }, { 4, 70, 512 }, { 5, 71, 512 }, + { 3, 72, 512 }, { 4, 73, 512 }, { 4, 74, 512 }, { 5, 75, 512 }, { 4, 76, 512 }, { 5, 77, 512 }, { 5, 78, 512 }, { 6, 79, 512 }, + { 3, 80, 512 }, { 4, 81, 512 }, { 4, 82, 512 }, { 5, 83, 512 }, { 4, 84, 512 }, { 5, 85, 512 }, { 5, 86, 512 }, { 6, 87, 512 }, + { 4, 88, 512 }, { 5, 89, 512 }, { 5, 90, 512 }, { 6, 91, 512 }, { 5, 92, 512 }, { 6, 93, 512 }, { 6, 94, 512 }, { 7, 95, 512 }, + { 3, 96, 512 }, { 4, 97, 512 }, { 4, 98, 512 }, { 5, 99, 512 }, { 4, 100, 512 }, { 5, 101, 512 }, { 5, 102, 512 }, { 6, 103, 512 }, + { 4, 104, 512 }, { 5, 105, 512 }, { 5, 106, 512 }, { 6, 107, 512 }, { 5, 108, 512 }, { 6, 109, 512 }, { 6, 110, 512 }, { 7, 111, 512 }, + { 4, 112, 512 }, { 5, 113, 512 }, { 5, 114, 512 }, { 6, 115, 512 }, { 5, 116, 512 }, { 6, 117, 512 }, { 6, 118, 512 }, { 7, 119, 512 }, + { 5, 120, 512 }, { 6, 121, 512 }, { 6, 122, 512 }, { 7, 123, 512 }, { 6, 124, 512 }, { 7, 125, 512 }, { 7, 126, 512 }, { 8, 127, 512 }, + { 2, 128, 512 }, { 3, 129, 512 }, { 3, 130, 512 }, { 4, 131, 512 }, { 3, 132, 512 }, { 4, 133, 512 }, { 4, 134, 512 }, { 5, 135, 512 }, + { 3, 136, 512 }, { 4, 137, 512 }, { 4, 138, 512 }, { 5, 139, 512 }, { 4, 140, 512 }, { 5, 141, 512 }, { 5, 142, 512 }, { 6, 143, 512 }, + { 3, 144, 512 }, { 4, 145, 512 }, { 4, 146, 512 }, { 5, 147, 512 }, { 4, 148, 512 }, { 5, 149, 512 }, { 5, 150, 512 }, { 6, 151, 512 }, + { 4, 152, 512 }, { 5, 153, 512 }, { 5, 154, 512 }, { 6, 155, 512 }, { 5, 156, 512 }, { 6, 157, 512 }, { 6, 158, 512 }, { 7, 159, 512 }, + { 3, 160, 512 }, { 4, 161, 512 }, { 4, 162, 512 }, { 5, 163, 512 }, { 4, 164, 512 }, { 5, 165, 512 }, { 5, 166, 512 }, { 6, 167, 512 }, + { 4, 168, 512 }, { 5, 169, 512 }, { 5, 170, 512 }, { 6, 171, 512 }, { 5, 172, 512 }, { 6, 173, 512 }, { 6, 174, 512 }, { 7, 175, 512 }, + { 4, 176, 512 }, { 5, 177, 512 }, { 5, 178, 512 }, { 6, 179, 512 }, { 5, 180, 512 }, { 6, 181, 512 }, { 6, 182, 512 }, { 7, 183, 512 }, + { 5, 184, 512 }, { 6, 185, 512 }, { 6, 186, 512 }, { 7, 187, 512 }, { 6, 188, 512 }, { 7, 189, 512 }, { 7, 190, 512 }, { 8, 191, 512 }, + { 3, 192, 512 }, { 4, 193, 512 }, { 4, 194, 512 }, { 5, 195, 512 }, { 4, 196, 512 }, { 5, 197, 512 }, { 5, 198, 512 }, { 6, 199, 512 }, + { 4, 200, 512 }, { 5, 201, 512 }, { 5, 202, 512 }, { 6, 203, 512 }, { 5, 204, 512 }, { 6, 205, 512 }, { 6, 206, 512 }, { 7, 207, 512 }, + { 4, 208, 512 }, { 5, 209, 512 }, { 5, 210, 512 }, { 6, 211, 512 }, { 5, 212, 512 }, { 6, 213, 512 }, { 6, 214, 512 }, { 7, 215, 512 }, + { 5, 216, 512 }, { 6, 217, 512 }, { 6, 218, 512 }, { 7, 219, 512 }, { 6, 220, 512 }, { 7, 221, 512 }, { 7, 222, 512 }, { 8, 223, 512 }, + { 4, 224, 512 }, { 5, 225, 512 }, { 5, 226, 512 }, { 6, 227, 512 }, { 5, 228, 512 }, { 6, 229, 512 }, { 6, 230, 512 }, { 7, 231, 512 }, + { 5, 232, 512 }, { 6, 233, 512 }, { 6, 234, 512 }, { 7, 235, 512 }, { 6, 236, 512 }, { 7, 237, 512 }, { 7, 238, 512 }, { 8, 239, 512 }, + { 5, 240, 512 }, { 6, 241, 512 }, { 6, 242, 512 }, { 7, 243, 512 }, { 6, 244, 512 }, { 7, 245, 512 }, { 7, 246, 512 }, { 8, 247, 512 }, + { 6, 248, 512 }, { 7, 249, 512 }, { 7, 250, 512 }, { 8, 251, 512 }, { 7, 252, 512 }, { 8, 253, 512 }, { 8, 254, 512 }, { 9, 255, 512 }, + { 2, 256, 512 }, { 3, 257, 512 }, { 3, 258, 512 }, { 4, 259, 512 }, { 3, 260, 512 }, { 4, 261, 512 }, { 4, 262, 512 }, { 5, 263, 512 }, + { 3, 264, 512 }, { 4, 265, 512 }, { 4, 266, 512 }, { 5, 267, 512 }, { 4, 268, 512 }, { 5, 269, 512 }, { 5, 270, 512 }, { 6, 271, 512 }, + { 3, 272, 512 }, { 4, 273, 512 }, { 4, 274, 512 }, { 5, 275, 512 }, { 4, 276, 512 }, { 5, 277, 512 }, { 5, 278, 512 }, { 6, 279, 512 }, + { 4, 280, 512 }, { 5, 281, 512 }, { 5, 282, 512 }, { 6, 283, 512 }, { 5, 284, 512 }, { 6, 285, 512 }, { 6, 286, 512 }, { 7, 287, 512 }, + { 3, 288, 512 }, { 4, 289, 512 }, { 4, 290, 512 }, { 5, 291, 512 }, { 4, 292, 512 }, { 5, 293, 512 }, { 5, 294, 512 }, { 6, 295, 512 }, + { 4, 296, 512 }, { 5, 297, 512 }, { 5, 298, 512 }, { 6, 299, 512 }, { 5, 300, 512 }, { 6, 301, 512 }, { 6, 302, 512 }, { 7, 303, 512 }, + { 4, 304, 512 }, { 5, 305, 512 }, { 5, 306, 512 }, { 6, 307, 512 }, { 5, 308, 512 }, { 6, 309, 512 }, { 6, 310, 512 }, { 7, 311, 512 }, + { 5, 312, 512 }, { 6, 313, 512 }, { 6, 314, 512 }, { 7, 315, 512 }, { 6, 316, 512 }, { 7, 317, 512 }, { 7, 318, 512 }, { 8, 319, 512 }, + { 3, 320, 512 }, { 4, 321, 512 }, { 4, 322, 512 }, { 5, 323, 512 }, { 4, 324, 512 }, { 5, 325, 512 }, { 5, 326, 512 }, { 6, 327, 512 }, + { 4, 328, 512 }, { 5, 329, 512 }, { 5, 330, 512 }, { 6, 331, 512 }, { 5, 332, 512 }, { 6, 333, 512 }, { 6, 334, 512 }, { 7, 335, 512 }, + { 4, 336, 512 }, { 5, 337, 512 }, { 5, 338, 512 }, { 6, 339, 512 }, { 5, 340, 512 }, { 6, 341, 512 }, { 6, 342, 512 }, { 7, 343, 512 }, + { 5, 344, 512 }, { 6, 345, 512 }, { 6, 346, 512 }, { 7, 347, 512 }, { 6, 348, 512 }, { 7, 349, 512 }, { 7, 350, 512 }, { 8, 351, 512 }, + { 4, 352, 512 }, { 5, 353, 512 }, { 5, 354, 512 }, { 6, 355, 512 }, { 5, 356, 512 }, { 6, 357, 512 }, { 6, 358, 512 }, { 7, 359, 512 }, + { 5, 360, 512 }, { 6, 361, 512 }, { 6, 362, 512 }, { 7, 363, 512 }, { 6, 364, 512 }, { 7, 365, 512 }, { 7, 366, 512 }, { 8, 367, 512 }, + { 5, 368, 512 }, { 6, 369, 512 }, { 6, 370, 512 }, { 7, 371, 512 }, { 6, 372, 512 }, { 7, 373, 512 }, { 7, 374, 512 }, { 8, 375, 512 }, + { 6, 376, 512 }, { 7, 377, 512 }, { 7, 378, 512 }, { 8, 379, 512 }, { 7, 380, 512 }, { 8, 381, 512 }, { 8, 382, 512 }, { 9, 383, 512 }, + { 3, 384, 512 }, { 4, 385, 512 }, { 4, 386, 512 }, { 5, 387, 512 }, { 4, 388, 512 }, { 5, 389, 512 }, { 5, 390, 512 }, { 6, 391, 512 }, + { 4, 392, 512 }, { 5, 393, 512 }, { 5, 394, 512 }, { 6, 395, 512 }, { 5, 396, 512 }, { 6, 397, 512 }, { 6, 398, 512 }, { 7, 399, 512 }, + { 4, 400, 512 }, { 5, 401, 512 }, { 5, 402, 512 }, { 6, 403, 512 }, { 5, 404, 512 }, { 6, 405, 512 }, { 6, 406, 512 }, { 7, 407, 512 }, + { 5, 408, 512 }, { 6, 409, 512 }, { 6, 410, 512 }, { 7, 411, 512 }, { 6, 412, 512 }, { 7, 413, 512 }, { 7, 414, 512 }, { 8, 415, 512 }, + { 4, 416, 512 }, { 5, 417, 512 }, { 5, 418, 512 }, { 6, 419, 512 }, { 5, 420, 512 }, { 6, 421, 512 }, { 6, 422, 512 }, { 7, 423, 512 }, + { 5, 424, 512 }, { 6, 425, 512 }, { 6, 426, 512 }, { 7, 427, 512 }, { 6, 428, 512 }, { 7, 429, 512 }, { 7, 430, 512 }, { 8, 431, 512 }, + { 5, 432, 512 }, { 6, 433, 512 }, { 6, 434, 512 }, { 7, 435, 512 }, { 6, 436, 512 }, { 7, 437, 512 }, { 7, 438, 512 }, { 8, 439, 512 }, + { 6, 440, 512 }, { 7, 441, 512 }, { 7, 442, 512 }, { 8, 443, 512 }, { 7, 444, 512 }, { 8, 445, 512 }, { 8, 446, 512 }, { 9, 447, 512 }, + { 4, 448, 512 }, { 5, 449, 512 }, { 5, 450, 512 }, { 6, 451, 512 }, { 5, 452, 512 }, { 6, 453, 512 }, { 6, 454, 512 }, { 7, 455, 512 }, + { 5, 456, 512 }, { 6, 457, 512 }, { 6, 458, 512 }, { 7, 459, 512 }, { 6, 460, 512 }, { 7, 461, 512 }, { 7, 462, 512 }, { 8, 463, 512 }, + { 5, 464, 512 }, { 6, 465, 512 }, { 6, 466, 512 }, { 7, 467, 512 }, { 6, 468, 512 }, { 7, 469, 512 }, { 7, 470, 512 }, { 8, 471, 512 }, + { 6, 472, 512 }, { 7, 473, 512 }, { 7, 474, 512 }, { 8, 475, 512 }, { 7, 476, 512 }, { 8, 477, 512 }, { 8, 478, 512 }, { 9, 479, 512 }, + { 5, 480, 512 }, { 6, 481, 512 }, { 6, 482, 512 }, { 7, 483, 512 }, { 6, 484, 512 }, { 7, 485, 512 }, { 7, 486, 512 }, { 8, 487, 512 }, + { 6, 488, 512 }, { 7, 489, 512 }, { 7, 490, 512 }, { 8, 491, 512 }, { 7, 492, 512 }, { 8, 493, 512 }, { 8, 494, 512 }, { 9, 495, 512 }, + { 6, 496, 512 }, { 7, 497, 512 }, { 7, 498, 512 }, { 8, 499, 512 }, { 7, 500, 512 }, { 8, 501, 512 }, { 8, 502, 512 }, { 9, 503, 512 }, + { 7, 504, 512 }, { 8, 505, 512 }, { 8, 506, 512 }, { 9, 507, 512 }, { 8, 508, 512 }, { 9, 509, 512 }, { 9, 510, 512 }, { 10, 511, 512 }, +#if FP_LUT > 10 + { 1, 0, 0 }, { 2, 1, 1024 }, { 2, 2, 1024 }, { 3, 3, 1024 }, { 2, 4, 1024 }, { 3, 5, 1024 }, { 3, 6, 1024 }, { 4, 7, 1024 }, + { 2, 8, 1024 }, { 3, 9, 1024 }, { 3, 10, 1024 }, { 4, 11, 1024 }, { 3, 12, 1024 }, { 4, 13, 1024 }, { 4, 14, 1024 }, { 5, 15, 1024 }, + { 2, 16, 1024 }, { 3, 17, 1024 }, { 3, 18, 1024 }, { 4, 19, 1024 }, { 3, 20, 1024 }, { 4, 21, 1024 }, { 4, 22, 1024 }, { 5, 23, 1024 }, + { 3, 24, 1024 }, { 4, 25, 1024 }, { 4, 26, 1024 }, { 5, 27, 1024 }, { 4, 28, 1024 }, { 5, 29, 1024 }, { 5, 30, 1024 }, { 6, 31, 1024 }, + { 2, 32, 1024 }, { 3, 33, 1024 }, { 3, 34, 1024 }, { 4, 35, 1024 }, { 3, 36, 1024 }, { 4, 37, 1024 }, { 4, 38, 1024 }, { 5, 39, 1024 }, + { 3, 40, 1024 }, { 4, 41, 1024 }, { 4, 42, 1024 }, { 5, 43, 1024 }, { 4, 44, 1024 }, { 5, 45, 1024 }, { 5, 46, 1024 }, { 6, 47, 1024 }, + { 3, 48, 1024 }, { 4, 49, 1024 }, { 4, 50, 1024 }, { 5, 51, 1024 }, { 4, 52, 1024 }, { 5, 53, 1024 }, { 5, 54, 1024 }, { 6, 55, 1024 }, + { 4, 56, 1024 }, { 5, 57, 1024 }, { 5, 58, 1024 }, { 6, 59, 1024 }, { 5, 60, 1024 }, { 6, 61, 1024 }, { 6, 62, 1024 }, { 7, 63, 1024 }, + { 2, 64, 1024 }, { 3, 65, 1024 }, { 3, 66, 1024 }, { 4, 67, 1024 }, { 3, 68, 1024 }, { 4, 69, 1024 }, { 4, 70, 1024 }, { 5, 71, 1024 }, + { 3, 72, 1024 }, { 4, 73, 1024 }, { 4, 74, 1024 }, { 5, 75, 1024 }, { 4, 76, 1024 }, { 5, 77, 1024 }, { 5, 78, 1024 }, { 6, 79, 1024 }, + { 3, 80, 1024 }, { 4, 81, 1024 }, { 4, 82, 1024 }, { 5, 83, 1024 }, { 4, 84, 1024 }, { 5, 85, 1024 }, { 5, 86, 1024 }, { 6, 87, 1024 }, + { 4, 88, 1024 }, { 5, 89, 1024 }, { 5, 90, 1024 }, { 6, 91, 1024 }, { 5, 92, 1024 }, { 6, 93, 1024 }, { 6, 94, 1024 }, { 7, 95, 1024 }, + { 3, 96, 1024 }, { 4, 97, 1024 }, { 4, 98, 1024 }, { 5, 99, 1024 }, { 4, 100, 1024 }, { 5, 101, 1024 }, { 5, 102, 1024 }, { 6, 103, 1024 }, + { 4, 104, 1024 }, { 5, 105, 1024 }, { 5, 106, 1024 }, { 6, 107, 1024 }, { 5, 108, 1024 }, { 6, 109, 1024 }, { 6, 110, 1024 }, { 7, 111, 1024 }, + { 4, 112, 1024 }, { 5, 113, 1024 }, { 5, 114, 1024 }, { 6, 115, 1024 }, { 5, 116, 1024 }, { 6, 117, 1024 }, { 6, 118, 1024 }, { 7, 119, 1024 }, + { 5, 120, 1024 }, { 6, 121, 1024 }, { 6, 122, 1024 }, { 7, 123, 1024 }, { 6, 124, 1024 }, { 7, 125, 1024 }, { 7, 126, 1024 }, { 8, 127, 1024 }, + { 2, 128, 1024 }, { 3, 129, 1024 }, { 3, 130, 1024 }, { 4, 131, 1024 }, { 3, 132, 1024 }, { 4, 133, 1024 }, { 4, 134, 1024 }, { 5, 135, 1024 }, + { 3, 136, 1024 }, { 4, 137, 1024 }, { 4, 138, 1024 }, { 5, 139, 1024 }, { 4, 140, 1024 }, { 5, 141, 1024 }, { 5, 142, 1024 }, { 6, 143, 1024 }, + { 3, 144, 1024 }, { 4, 145, 1024 }, { 4, 146, 1024 }, { 5, 147, 1024 }, { 4, 148, 1024 }, { 5, 149, 1024 }, { 5, 150, 1024 }, { 6, 151, 1024 }, + { 4, 152, 1024 }, { 5, 153, 1024 }, { 5, 154, 1024 }, { 6, 155, 1024 }, { 5, 156, 1024 }, { 6, 157, 1024 }, { 6, 158, 1024 }, { 7, 159, 1024 }, + { 3, 160, 1024 }, { 4, 161, 1024 }, { 4, 162, 1024 }, { 5, 163, 1024 }, { 4, 164, 1024 }, { 5, 165, 1024 }, { 5, 166, 1024 }, { 6, 167, 1024 }, + { 4, 168, 1024 }, { 5, 169, 1024 }, { 5, 170, 1024 }, { 6, 171, 1024 }, { 5, 172, 1024 }, { 6, 173, 1024 }, { 6, 174, 1024 }, { 7, 175, 1024 }, + { 4, 176, 1024 }, { 5, 177, 1024 }, { 5, 178, 1024 }, { 6, 179, 1024 }, { 5, 180, 1024 }, { 6, 181, 1024 }, { 6, 182, 1024 }, { 7, 183, 1024 }, + { 5, 184, 1024 }, { 6, 185, 1024 }, { 6, 186, 1024 }, { 7, 187, 1024 }, { 6, 188, 1024 }, { 7, 189, 1024 }, { 7, 190, 1024 }, { 8, 191, 1024 }, + { 3, 192, 1024 }, { 4, 193, 1024 }, { 4, 194, 1024 }, { 5, 195, 1024 }, { 4, 196, 1024 }, { 5, 197, 1024 }, { 5, 198, 1024 }, { 6, 199, 1024 }, + { 4, 200, 1024 }, { 5, 201, 1024 }, { 5, 202, 1024 }, { 6, 203, 1024 }, { 5, 204, 1024 }, { 6, 205, 1024 }, { 6, 206, 1024 }, { 7, 207, 1024 }, + { 4, 208, 1024 }, { 5, 209, 1024 }, { 5, 210, 1024 }, { 6, 211, 1024 }, { 5, 212, 1024 }, { 6, 213, 1024 }, { 6, 214, 1024 }, { 7, 215, 1024 }, + { 5, 216, 1024 }, { 6, 217, 1024 }, { 6, 218, 1024 }, { 7, 219, 1024 }, { 6, 220, 1024 }, { 7, 221, 1024 }, { 7, 222, 1024 }, { 8, 223, 1024 }, + { 4, 224, 1024 }, { 5, 225, 1024 }, { 5, 226, 1024 }, { 6, 227, 1024 }, { 5, 228, 1024 }, { 6, 229, 1024 }, { 6, 230, 1024 }, { 7, 231, 1024 }, + { 5, 232, 1024 }, { 6, 233, 1024 }, { 6, 234, 1024 }, { 7, 235, 1024 }, { 6, 236, 1024 }, { 7, 237, 1024 }, { 7, 238, 1024 }, { 8, 239, 1024 }, + { 5, 240, 1024 }, { 6, 241, 1024 }, { 6, 242, 1024 }, { 7, 243, 1024 }, { 6, 244, 1024 }, { 7, 245, 1024 }, { 7, 246, 1024 }, { 8, 247, 1024 }, + { 6, 248, 1024 }, { 7, 249, 1024 }, { 7, 250, 1024 }, { 8, 251, 1024 }, { 7, 252, 1024 }, { 8, 253, 1024 }, { 8, 254, 1024 }, { 9, 255, 1024 }, + { 2, 256, 1024 }, { 3, 257, 1024 }, { 3, 258, 1024 }, { 4, 259, 1024 }, { 3, 260, 1024 }, { 4, 261, 1024 }, { 4, 262, 1024 }, { 5, 263, 1024 }, + { 3, 264, 1024 }, { 4, 265, 1024 }, { 4, 266, 1024 }, { 5, 267, 1024 }, { 4, 268, 1024 }, { 5, 269, 1024 }, { 5, 270, 1024 }, { 6, 271, 1024 }, + { 3, 272, 1024 }, { 4, 273, 1024 }, { 4, 274, 1024 }, { 5, 275, 1024 }, { 4, 276, 1024 }, { 5, 277, 1024 }, { 5, 278, 1024 }, { 6, 279, 1024 }, + { 4, 280, 1024 }, { 5, 281, 1024 }, { 5, 282, 1024 }, { 6, 283, 1024 }, { 5, 284, 1024 }, { 6, 285, 1024 }, { 6, 286, 1024 }, { 7, 287, 1024 }, + { 3, 288, 1024 }, { 4, 289, 1024 }, { 4, 290, 1024 }, { 5, 291, 1024 }, { 4, 292, 1024 }, { 5, 293, 1024 }, { 5, 294, 1024 }, { 6, 295, 1024 }, + { 4, 296, 1024 }, { 5, 297, 1024 }, { 5, 298, 1024 }, { 6, 299, 1024 }, { 5, 300, 1024 }, { 6, 301, 1024 }, { 6, 302, 1024 }, { 7, 303, 1024 }, + { 4, 304, 1024 }, { 5, 305, 1024 }, { 5, 306, 1024 }, { 6, 307, 1024 }, { 5, 308, 1024 }, { 6, 309, 1024 }, { 6, 310, 1024 }, { 7, 311, 1024 }, + { 5, 312, 1024 }, { 6, 313, 1024 }, { 6, 314, 1024 }, { 7, 315, 1024 }, { 6, 316, 1024 }, { 7, 317, 1024 }, { 7, 318, 1024 }, { 8, 319, 1024 }, + { 3, 320, 1024 }, { 4, 321, 1024 }, { 4, 322, 1024 }, { 5, 323, 1024 }, { 4, 324, 1024 }, { 5, 325, 1024 }, { 5, 326, 1024 }, { 6, 327, 1024 }, + { 4, 328, 1024 }, { 5, 329, 1024 }, { 5, 330, 1024 }, { 6, 331, 1024 }, { 5, 332, 1024 }, { 6, 333, 1024 }, { 6, 334, 1024 }, { 7, 335, 1024 }, + { 4, 336, 1024 }, { 5, 337, 1024 }, { 5, 338, 1024 }, { 6, 339, 1024 }, { 5, 340, 1024 }, { 6, 341, 1024 }, { 6, 342, 1024 }, { 7, 343, 1024 }, + { 5, 344, 1024 }, { 6, 345, 1024 }, { 6, 346, 1024 }, { 7, 347, 1024 }, { 6, 348, 1024 }, { 7, 349, 1024 }, { 7, 350, 1024 }, { 8, 351, 1024 }, + { 4, 352, 1024 }, { 5, 353, 1024 }, { 5, 354, 1024 }, { 6, 355, 1024 }, { 5, 356, 1024 }, { 6, 357, 1024 }, { 6, 358, 1024 }, { 7, 359, 1024 }, + { 5, 360, 1024 }, { 6, 361, 1024 }, { 6, 362, 1024 }, { 7, 363, 1024 }, { 6, 364, 1024 }, { 7, 365, 1024 }, { 7, 366, 1024 }, { 8, 367, 1024 }, + { 5, 368, 1024 }, { 6, 369, 1024 }, { 6, 370, 1024 }, { 7, 371, 1024 }, { 6, 372, 1024 }, { 7, 373, 1024 }, { 7, 374, 1024 }, { 8, 375, 1024 }, + { 6, 376, 1024 }, { 7, 377, 1024 }, { 7, 378, 1024 }, { 8, 379, 1024 }, { 7, 380, 1024 }, { 8, 381, 1024 }, { 8, 382, 1024 }, { 9, 383, 1024 }, + { 3, 384, 1024 }, { 4, 385, 1024 }, { 4, 386, 1024 }, { 5, 387, 1024 }, { 4, 388, 1024 }, { 5, 389, 1024 }, { 5, 390, 1024 }, { 6, 391, 1024 }, + { 4, 392, 1024 }, { 5, 393, 1024 }, { 5, 394, 1024 }, { 6, 395, 1024 }, { 5, 396, 1024 }, { 6, 397, 1024 }, { 6, 398, 1024 }, { 7, 399, 1024 }, + { 4, 400, 1024 }, { 5, 401, 1024 }, { 5, 402, 1024 }, { 6, 403, 1024 }, { 5, 404, 1024 }, { 6, 405, 1024 }, { 6, 406, 1024 }, { 7, 407, 1024 }, + { 5, 408, 1024 }, { 6, 409, 1024 }, { 6, 410, 1024 }, { 7, 411, 1024 }, { 6, 412, 1024 }, { 7, 413, 1024 }, { 7, 414, 1024 }, { 8, 415, 1024 }, + { 4, 416, 1024 }, { 5, 417, 1024 }, { 5, 418, 1024 }, { 6, 419, 1024 }, { 5, 420, 1024 }, { 6, 421, 1024 }, { 6, 422, 1024 }, { 7, 423, 1024 }, + { 5, 424, 1024 }, { 6, 425, 1024 }, { 6, 426, 1024 }, { 7, 427, 1024 }, { 6, 428, 1024 }, { 7, 429, 1024 }, { 7, 430, 1024 }, { 8, 431, 1024 }, + { 5, 432, 1024 }, { 6, 433, 1024 }, { 6, 434, 1024 }, { 7, 435, 1024 }, { 6, 436, 1024 }, { 7, 437, 1024 }, { 7, 438, 1024 }, { 8, 439, 1024 }, + { 6, 440, 1024 }, { 7, 441, 1024 }, { 7, 442, 1024 }, { 8, 443, 1024 }, { 7, 444, 1024 }, { 8, 445, 1024 }, { 8, 446, 1024 }, { 9, 447, 1024 }, + { 4, 448, 1024 }, { 5, 449, 1024 }, { 5, 450, 1024 }, { 6, 451, 1024 }, { 5, 452, 1024 }, { 6, 453, 1024 }, { 6, 454, 1024 }, { 7, 455, 1024 }, + { 5, 456, 1024 }, { 6, 457, 1024 }, { 6, 458, 1024 }, { 7, 459, 1024 }, { 6, 460, 1024 }, { 7, 461, 1024 }, { 7, 462, 1024 }, { 8, 463, 1024 }, + { 5, 464, 1024 }, { 6, 465, 1024 }, { 6, 466, 1024 }, { 7, 467, 1024 }, { 6, 468, 1024 }, { 7, 469, 1024 }, { 7, 470, 1024 }, { 8, 471, 1024 }, + { 6, 472, 1024 }, { 7, 473, 1024 }, { 7, 474, 1024 }, { 8, 475, 1024 }, { 7, 476, 1024 }, { 8, 477, 1024 }, { 8, 478, 1024 }, { 9, 479, 1024 }, + { 5, 480, 1024 }, { 6, 481, 1024 }, { 6, 482, 1024 }, { 7, 483, 1024 }, { 6, 484, 1024 }, { 7, 485, 1024 }, { 7, 486, 1024 }, { 8, 487, 1024 }, + { 6, 488, 1024 }, { 7, 489, 1024 }, { 7, 490, 1024 }, { 8, 491, 1024 }, { 7, 492, 1024 }, { 8, 493, 1024 }, { 8, 494, 1024 }, { 9, 495, 1024 }, + { 6, 496, 1024 }, { 7, 497, 1024 }, { 7, 498, 1024 }, { 8, 499, 1024 }, { 7, 500, 1024 }, { 8, 501, 1024 }, { 8, 502, 1024 }, { 9, 503, 1024 }, + { 7, 504, 1024 }, { 8, 505, 1024 }, { 8, 506, 1024 }, { 9, 507, 1024 }, { 8, 508, 1024 }, { 9, 509, 1024 }, { 9, 510, 1024 }, { 10, 511, 1024 }, + { 2, 512, 1024 }, { 3, 513, 1024 }, { 3, 514, 1024 }, { 4, 515, 1024 }, { 3, 516, 1024 }, { 4, 517, 1024 }, { 4, 518, 1024 }, { 5, 519, 1024 }, + { 3, 520, 1024 }, { 4, 521, 1024 }, { 4, 522, 1024 }, { 5, 523, 1024 }, { 4, 524, 1024 }, { 5, 525, 1024 }, { 5, 526, 1024 }, { 6, 527, 1024 }, + { 3, 528, 1024 }, { 4, 529, 1024 }, { 4, 530, 1024 }, { 5, 531, 1024 }, { 4, 532, 1024 }, { 5, 533, 1024 }, { 5, 534, 1024 }, { 6, 535, 1024 }, + { 4, 536, 1024 }, { 5, 537, 1024 }, { 5, 538, 1024 }, { 6, 539, 1024 }, { 5, 540, 1024 }, { 6, 541, 1024 }, { 6, 542, 1024 }, { 7, 543, 1024 }, + { 3, 544, 1024 }, { 4, 545, 1024 }, { 4, 546, 1024 }, { 5, 547, 1024 }, { 4, 548, 1024 }, { 5, 549, 1024 }, { 5, 550, 1024 }, { 6, 551, 1024 }, + { 4, 552, 1024 }, { 5, 553, 1024 }, { 5, 554, 1024 }, { 6, 555, 1024 }, { 5, 556, 1024 }, { 6, 557, 1024 }, { 6, 558, 1024 }, { 7, 559, 1024 }, + { 4, 560, 1024 }, { 5, 561, 1024 }, { 5, 562, 1024 }, { 6, 563, 1024 }, { 5, 564, 1024 }, { 6, 565, 1024 }, { 6, 566, 1024 }, { 7, 567, 1024 }, + { 5, 568, 1024 }, { 6, 569, 1024 }, { 6, 570, 1024 }, { 7, 571, 1024 }, { 6, 572, 1024 }, { 7, 573, 1024 }, { 7, 574, 1024 }, { 8, 575, 1024 }, + { 3, 576, 1024 }, { 4, 577, 1024 }, { 4, 578, 1024 }, { 5, 579, 1024 }, { 4, 580, 1024 }, { 5, 581, 1024 }, { 5, 582, 1024 }, { 6, 583, 1024 }, + { 4, 584, 1024 }, { 5, 585, 1024 }, { 5, 586, 1024 }, { 6, 587, 1024 }, { 5, 588, 1024 }, { 6, 589, 1024 }, { 6, 590, 1024 }, { 7, 591, 1024 }, + { 4, 592, 1024 }, { 5, 593, 1024 }, { 5, 594, 1024 }, { 6, 595, 1024 }, { 5, 596, 1024 }, { 6, 597, 1024 }, { 6, 598, 1024 }, { 7, 599, 1024 }, + { 5, 600, 1024 }, { 6, 601, 1024 }, { 6, 602, 1024 }, { 7, 603, 1024 }, { 6, 604, 1024 }, { 7, 605, 1024 }, { 7, 606, 1024 }, { 8, 607, 1024 }, + { 4, 608, 1024 }, { 5, 609, 1024 }, { 5, 610, 1024 }, { 6, 611, 1024 }, { 5, 612, 1024 }, { 6, 613, 1024 }, { 6, 614, 1024 }, { 7, 615, 1024 }, + { 5, 616, 1024 }, { 6, 617, 1024 }, { 6, 618, 1024 }, { 7, 619, 1024 }, { 6, 620, 1024 }, { 7, 621, 1024 }, { 7, 622, 1024 }, { 8, 623, 1024 }, + { 5, 624, 1024 }, { 6, 625, 1024 }, { 6, 626, 1024 }, { 7, 627, 1024 }, { 6, 628, 1024 }, { 7, 629, 1024 }, { 7, 630, 1024 }, { 8, 631, 1024 }, + { 6, 632, 1024 }, { 7, 633, 1024 }, { 7, 634, 1024 }, { 8, 635, 1024 }, { 7, 636, 1024 }, { 8, 637, 1024 }, { 8, 638, 1024 }, { 9, 639, 1024 }, + { 3, 640, 1024 }, { 4, 641, 1024 }, { 4, 642, 1024 }, { 5, 643, 1024 }, { 4, 644, 1024 }, { 5, 645, 1024 }, { 5, 646, 1024 }, { 6, 647, 1024 }, + { 4, 648, 1024 }, { 5, 649, 1024 }, { 5, 650, 1024 }, { 6, 651, 1024 }, { 5, 652, 1024 }, { 6, 653, 1024 }, { 6, 654, 1024 }, { 7, 655, 1024 }, + { 4, 656, 1024 }, { 5, 657, 1024 }, { 5, 658, 1024 }, { 6, 659, 1024 }, { 5, 660, 1024 }, { 6, 661, 1024 }, { 6, 662, 1024 }, { 7, 663, 1024 }, + { 5, 664, 1024 }, { 6, 665, 1024 }, { 6, 666, 1024 }, { 7, 667, 1024 }, { 6, 668, 1024 }, { 7, 669, 1024 }, { 7, 670, 1024 }, { 8, 671, 1024 }, + { 4, 672, 1024 }, { 5, 673, 1024 }, { 5, 674, 1024 }, { 6, 675, 1024 }, { 5, 676, 1024 }, { 6, 677, 1024 }, { 6, 678, 1024 }, { 7, 679, 1024 }, + { 5, 680, 1024 }, { 6, 681, 1024 }, { 6, 682, 1024 }, { 7, 683, 1024 }, { 6, 684, 1024 }, { 7, 685, 1024 }, { 7, 686, 1024 }, { 8, 687, 1024 }, + { 5, 688, 1024 }, { 6, 689, 1024 }, { 6, 690, 1024 }, { 7, 691, 1024 }, { 6, 692, 1024 }, { 7, 693, 1024 }, { 7, 694, 1024 }, { 8, 695, 1024 }, + { 6, 696, 1024 }, { 7, 697, 1024 }, { 7, 698, 1024 }, { 8, 699, 1024 }, { 7, 700, 1024 }, { 8, 701, 1024 }, { 8, 702, 1024 }, { 9, 703, 1024 }, + { 4, 704, 1024 }, { 5, 705, 1024 }, { 5, 706, 1024 }, { 6, 707, 1024 }, { 5, 708, 1024 }, { 6, 709, 1024 }, { 6, 710, 1024 }, { 7, 711, 1024 }, + { 5, 712, 1024 }, { 6, 713, 1024 }, { 6, 714, 1024 }, { 7, 715, 1024 }, { 6, 716, 1024 }, { 7, 717, 1024 }, { 7, 718, 1024 }, { 8, 719, 1024 }, + { 5, 720, 1024 }, { 6, 721, 1024 }, { 6, 722, 1024 }, { 7, 723, 1024 }, { 6, 724, 1024 }, { 7, 725, 1024 }, { 7, 726, 1024 }, { 8, 727, 1024 }, + { 6, 728, 1024 }, { 7, 729, 1024 }, { 7, 730, 1024 }, { 8, 731, 1024 }, { 7, 732, 1024 }, { 8, 733, 1024 }, { 8, 734, 1024 }, { 9, 735, 1024 }, + { 5, 736, 1024 }, { 6, 737, 1024 }, { 6, 738, 1024 }, { 7, 739, 1024 }, { 6, 740, 1024 }, { 7, 741, 1024 }, { 7, 742, 1024 }, { 8, 743, 1024 }, + { 6, 744, 1024 }, { 7, 745, 1024 }, { 7, 746, 1024 }, { 8, 747, 1024 }, { 7, 748, 1024 }, { 8, 749, 1024 }, { 8, 750, 1024 }, { 9, 751, 1024 }, + { 6, 752, 1024 }, { 7, 753, 1024 }, { 7, 754, 1024 }, { 8, 755, 1024 }, { 7, 756, 1024 }, { 8, 757, 1024 }, { 8, 758, 1024 }, { 9, 759, 1024 }, + { 7, 760, 1024 }, { 8, 761, 1024 }, { 8, 762, 1024 }, { 9, 763, 1024 }, { 8, 764, 1024 }, { 9, 765, 1024 }, { 9, 766, 1024 }, { 10, 767, 1024 }, + { 3, 768, 1024 }, { 4, 769, 1024 }, { 4, 770, 1024 }, { 5, 771, 1024 }, { 4, 772, 1024 }, { 5, 773, 1024 }, { 5, 774, 1024 }, { 6, 775, 1024 }, + { 4, 776, 1024 }, { 5, 777, 1024 }, { 5, 778, 1024 }, { 6, 779, 1024 }, { 5, 780, 1024 }, { 6, 781, 1024 }, { 6, 782, 1024 }, { 7, 783, 1024 }, + { 4, 784, 1024 }, { 5, 785, 1024 }, { 5, 786, 1024 }, { 6, 787, 1024 }, { 5, 788, 1024 }, { 6, 789, 1024 }, { 6, 790, 1024 }, { 7, 791, 1024 }, + { 5, 792, 1024 }, { 6, 793, 1024 }, { 6, 794, 1024 }, { 7, 795, 1024 }, { 6, 796, 1024 }, { 7, 797, 1024 }, { 7, 798, 1024 }, { 8, 799, 1024 }, + { 4, 800, 1024 }, { 5, 801, 1024 }, { 5, 802, 1024 }, { 6, 803, 1024 }, { 5, 804, 1024 }, { 6, 805, 1024 }, { 6, 806, 1024 }, { 7, 807, 1024 }, + { 5, 808, 1024 }, { 6, 809, 1024 }, { 6, 810, 1024 }, { 7, 811, 1024 }, { 6, 812, 1024 }, { 7, 813, 1024 }, { 7, 814, 1024 }, { 8, 815, 1024 }, + { 5, 816, 1024 }, { 6, 817, 1024 }, { 6, 818, 1024 }, { 7, 819, 1024 }, { 6, 820, 1024 }, { 7, 821, 1024 }, { 7, 822, 1024 }, { 8, 823, 1024 }, + { 6, 824, 1024 }, { 7, 825, 1024 }, { 7, 826, 1024 }, { 8, 827, 1024 }, { 7, 828, 1024 }, { 8, 829, 1024 }, { 8, 830, 1024 }, { 9, 831, 1024 }, + { 4, 832, 1024 }, { 5, 833, 1024 }, { 5, 834, 1024 }, { 6, 835, 1024 }, { 5, 836, 1024 }, { 6, 837, 1024 }, { 6, 838, 1024 }, { 7, 839, 1024 }, + { 5, 840, 1024 }, { 6, 841, 1024 }, { 6, 842, 1024 }, { 7, 843, 1024 }, { 6, 844, 1024 }, { 7, 845, 1024 }, { 7, 846, 1024 }, { 8, 847, 1024 }, + { 5, 848, 1024 }, { 6, 849, 1024 }, { 6, 850, 1024 }, { 7, 851, 1024 }, { 6, 852, 1024 }, { 7, 853, 1024 }, { 7, 854, 1024 }, { 8, 855, 1024 }, + { 6, 856, 1024 }, { 7, 857, 1024 }, { 7, 858, 1024 }, { 8, 859, 1024 }, { 7, 860, 1024 }, { 8, 861, 1024 }, { 8, 862, 1024 }, { 9, 863, 1024 }, + { 5, 864, 1024 }, { 6, 865, 1024 }, { 6, 866, 1024 }, { 7, 867, 1024 }, { 6, 868, 1024 }, { 7, 869, 1024 }, { 7, 870, 1024 }, { 8, 871, 1024 }, + { 6, 872, 1024 }, { 7, 873, 1024 }, { 7, 874, 1024 }, { 8, 875, 1024 }, { 7, 876, 1024 }, { 8, 877, 1024 }, { 8, 878, 1024 }, { 9, 879, 1024 }, + { 6, 880, 1024 }, { 7, 881, 1024 }, { 7, 882, 1024 }, { 8, 883, 1024 }, { 7, 884, 1024 }, { 8, 885, 1024 }, { 8, 886, 1024 }, { 9, 887, 1024 }, + { 7, 888, 1024 }, { 8, 889, 1024 }, { 8, 890, 1024 }, { 9, 891, 1024 }, { 8, 892, 1024 }, { 9, 893, 1024 }, { 9, 894, 1024 }, { 10, 895, 1024 }, + { 4, 896, 1024 }, { 5, 897, 1024 }, { 5, 898, 1024 }, { 6, 899, 1024 }, { 5, 900, 1024 }, { 6, 901, 1024 }, { 6, 902, 1024 }, { 7, 903, 1024 }, + { 5, 904, 1024 }, { 6, 905, 1024 }, { 6, 906, 1024 }, { 7, 907, 1024 }, { 6, 908, 1024 }, { 7, 909, 1024 }, { 7, 910, 1024 }, { 8, 911, 1024 }, + { 5, 912, 1024 }, { 6, 913, 1024 }, { 6, 914, 1024 }, { 7, 915, 1024 }, { 6, 916, 1024 }, { 7, 917, 1024 }, { 7, 918, 1024 }, { 8, 919, 1024 }, + { 6, 920, 1024 }, { 7, 921, 1024 }, { 7, 922, 1024 }, { 8, 923, 1024 }, { 7, 924, 1024 }, { 8, 925, 1024 }, { 8, 926, 1024 }, { 9, 927, 1024 }, + { 5, 928, 1024 }, { 6, 929, 1024 }, { 6, 930, 1024 }, { 7, 931, 1024 }, { 6, 932, 1024 }, { 7, 933, 1024 }, { 7, 934, 1024 }, { 8, 935, 1024 }, + { 6, 936, 1024 }, { 7, 937, 1024 }, { 7, 938, 1024 }, { 8, 939, 1024 }, { 7, 940, 1024 }, { 8, 941, 1024 }, { 8, 942, 1024 }, { 9, 943, 1024 }, + { 6, 944, 1024 }, { 7, 945, 1024 }, { 7, 946, 1024 }, { 8, 947, 1024 }, { 7, 948, 1024 }, { 8, 949, 1024 }, { 8, 950, 1024 }, { 9, 951, 1024 }, + { 7, 952, 1024 }, { 8, 953, 1024 }, { 8, 954, 1024 }, { 9, 955, 1024 }, { 8, 956, 1024 }, { 9, 957, 1024 }, { 9, 958, 1024 }, { 10, 959, 1024 }, + { 5, 960, 1024 }, { 6, 961, 1024 }, { 6, 962, 1024 }, { 7, 963, 1024 }, { 6, 964, 1024 }, { 7, 965, 1024 }, { 7, 966, 1024 }, { 8, 967, 1024 }, + { 6, 968, 1024 }, { 7, 969, 1024 }, { 7, 970, 1024 }, { 8, 971, 1024 }, { 7, 972, 1024 }, { 8, 973, 1024 }, { 8, 974, 1024 }, { 9, 975, 1024 }, + { 6, 976, 1024 }, { 7, 977, 1024 }, { 7, 978, 1024 }, { 8, 979, 1024 }, { 7, 980, 1024 }, { 8, 981, 1024 }, { 8, 982, 1024 }, { 9, 983, 1024 }, + { 7, 984, 1024 }, { 8, 985, 1024 }, { 8, 986, 1024 }, { 9, 987, 1024 }, { 8, 988, 1024 }, { 9, 989, 1024 }, { 9, 990, 1024 }, { 10, 991, 1024 }, + { 6, 992, 1024 }, { 7, 993, 1024 }, { 7, 994, 1024 }, { 8, 995, 1024 }, { 7, 996, 1024 }, { 8, 997, 1024 }, { 8, 998, 1024 }, { 9, 999, 1024 }, + { 7, 1000, 1024 }, { 8, 1001, 1024 }, { 8, 1002, 1024 }, { 9, 1003, 1024 }, { 8, 1004, 1024 }, { 9, 1005, 1024 }, { 9, 1006, 1024 }, { 10, 1007, 1024 }, + { 7, 1008, 1024 }, { 8, 1009, 1024 }, { 8, 1010, 1024 }, { 9, 1011, 1024 }, { 8, 1012, 1024 }, { 9, 1013, 1024 }, { 9, 1014, 1024 }, { 10, 1015, 1024 }, + { 8, 1016, 1024 }, { 9, 1017, 1024 }, { 9, 1018, 1024 }, { 10, 1019, 1024 }, { 9, 1020, 1024 }, { 10, 1021, 1024 }, { 10, 1022, 1024 }, { 11, 1023, 1024 }, +#if FP_LUT > 11 + { 1, 0, 0 }, { 2, 1, 2048 }, { 2, 2, 2048 }, { 3, 3, 2048 }, { 2, 4, 2048 }, { 3, 5, 2048 }, { 3, 6, 2048 }, { 4, 7, 2048 }, + { 2, 8, 2048 }, { 3, 9, 2048 }, { 3, 10, 2048 }, { 4, 11, 2048 }, { 3, 12, 2048 }, { 4, 13, 2048 }, { 4, 14, 2048 }, { 5, 15, 2048 }, + { 2, 16, 2048 }, { 3, 17, 2048 }, { 3, 18, 2048 }, { 4, 19, 2048 }, { 3, 20, 2048 }, { 4, 21, 2048 }, { 4, 22, 2048 }, { 5, 23, 2048 }, + { 3, 24, 2048 }, { 4, 25, 2048 }, { 4, 26, 2048 }, { 5, 27, 2048 }, { 4, 28, 2048 }, { 5, 29, 2048 }, { 5, 30, 2048 }, { 6, 31, 2048 }, + { 2, 32, 2048 }, { 3, 33, 2048 }, { 3, 34, 2048 }, { 4, 35, 2048 }, { 3, 36, 2048 }, { 4, 37, 2048 }, { 4, 38, 2048 }, { 5, 39, 2048 }, + { 3, 40, 2048 }, { 4, 41, 2048 }, { 4, 42, 2048 }, { 5, 43, 2048 }, { 4, 44, 2048 }, { 5, 45, 2048 }, { 5, 46, 2048 }, { 6, 47, 2048 }, + { 3, 48, 2048 }, { 4, 49, 2048 }, { 4, 50, 2048 }, { 5, 51, 2048 }, { 4, 52, 2048 }, { 5, 53, 2048 }, { 5, 54, 2048 }, { 6, 55, 2048 }, + { 4, 56, 2048 }, { 5, 57, 2048 }, { 5, 58, 2048 }, { 6, 59, 2048 }, { 5, 60, 2048 }, { 6, 61, 2048 }, { 6, 62, 2048 }, { 7, 63, 2048 }, + { 2, 64, 2048 }, { 3, 65, 2048 }, { 3, 66, 2048 }, { 4, 67, 2048 }, { 3, 68, 2048 }, { 4, 69, 2048 }, { 4, 70, 2048 }, { 5, 71, 2048 }, + { 3, 72, 2048 }, { 4, 73, 2048 }, { 4, 74, 2048 }, { 5, 75, 2048 }, { 4, 76, 2048 }, { 5, 77, 2048 }, { 5, 78, 2048 }, { 6, 79, 2048 }, + { 3, 80, 2048 }, { 4, 81, 2048 }, { 4, 82, 2048 }, { 5, 83, 2048 }, { 4, 84, 2048 }, { 5, 85, 2048 }, { 5, 86, 2048 }, { 6, 87, 2048 }, + { 4, 88, 2048 }, { 5, 89, 2048 }, { 5, 90, 2048 }, { 6, 91, 2048 }, { 5, 92, 2048 }, { 6, 93, 2048 }, { 6, 94, 2048 }, { 7, 95, 2048 }, + { 3, 96, 2048 }, { 4, 97, 2048 }, { 4, 98, 2048 }, { 5, 99, 2048 }, { 4, 100, 2048 }, { 5, 101, 2048 }, { 5, 102, 2048 }, { 6, 103, 2048 }, + { 4, 104, 2048 }, { 5, 105, 2048 }, { 5, 106, 2048 }, { 6, 107, 2048 }, { 5, 108, 2048 }, { 6, 109, 2048 }, { 6, 110, 2048 }, { 7, 111, 2048 }, + { 4, 112, 2048 }, { 5, 113, 2048 }, { 5, 114, 2048 }, { 6, 115, 2048 }, { 5, 116, 2048 }, { 6, 117, 2048 }, { 6, 118, 2048 }, { 7, 119, 2048 }, + { 5, 120, 2048 }, { 6, 121, 2048 }, { 6, 122, 2048 }, { 7, 123, 2048 }, { 6, 124, 2048 }, { 7, 125, 2048 }, { 7, 126, 2048 }, { 8, 127, 2048 }, + { 2, 128, 2048 }, { 3, 129, 2048 }, { 3, 130, 2048 }, { 4, 131, 2048 }, { 3, 132, 2048 }, { 4, 133, 2048 }, { 4, 134, 2048 }, { 5, 135, 2048 }, + { 3, 136, 2048 }, { 4, 137, 2048 }, { 4, 138, 2048 }, { 5, 139, 2048 }, { 4, 140, 2048 }, { 5, 141, 2048 }, { 5, 142, 2048 }, { 6, 143, 2048 }, + { 3, 144, 2048 }, { 4, 145, 2048 }, { 4, 146, 2048 }, { 5, 147, 2048 }, { 4, 148, 2048 }, { 5, 149, 2048 }, { 5, 150, 2048 }, { 6, 151, 2048 }, + { 4, 152, 2048 }, { 5, 153, 2048 }, { 5, 154, 2048 }, { 6, 155, 2048 }, { 5, 156, 2048 }, { 6, 157, 2048 }, { 6, 158, 2048 }, { 7, 159, 2048 }, + { 3, 160, 2048 }, { 4, 161, 2048 }, { 4, 162, 2048 }, { 5, 163, 2048 }, { 4, 164, 2048 }, { 5, 165, 2048 }, { 5, 166, 2048 }, { 6, 167, 2048 }, + { 4, 168, 2048 }, { 5, 169, 2048 }, { 5, 170, 2048 }, { 6, 171, 2048 }, { 5, 172, 2048 }, { 6, 173, 2048 }, { 6, 174, 2048 }, { 7, 175, 2048 }, + { 4, 176, 2048 }, { 5, 177, 2048 }, { 5, 178, 2048 }, { 6, 179, 2048 }, { 5, 180, 2048 }, { 6, 181, 2048 }, { 6, 182, 2048 }, { 7, 183, 2048 }, + { 5, 184, 2048 }, { 6, 185, 2048 }, { 6, 186, 2048 }, { 7, 187, 2048 }, { 6, 188, 2048 }, { 7, 189, 2048 }, { 7, 190, 2048 }, { 8, 191, 2048 }, + { 3, 192, 2048 }, { 4, 193, 2048 }, { 4, 194, 2048 }, { 5, 195, 2048 }, { 4, 196, 2048 }, { 5, 197, 2048 }, { 5, 198, 2048 }, { 6, 199, 2048 }, + { 4, 200, 2048 }, { 5, 201, 2048 }, { 5, 202, 2048 }, { 6, 203, 2048 }, { 5, 204, 2048 }, { 6, 205, 2048 }, { 6, 206, 2048 }, { 7, 207, 2048 }, + { 4, 208, 2048 }, { 5, 209, 2048 }, { 5, 210, 2048 }, { 6, 211, 2048 }, { 5, 212, 2048 }, { 6, 213, 2048 }, { 6, 214, 2048 }, { 7, 215, 2048 }, + { 5, 216, 2048 }, { 6, 217, 2048 }, { 6, 218, 2048 }, { 7, 219, 2048 }, { 6, 220, 2048 }, { 7, 221, 2048 }, { 7, 222, 2048 }, { 8, 223, 2048 }, + { 4, 224, 2048 }, { 5, 225, 2048 }, { 5, 226, 2048 }, { 6, 227, 2048 }, { 5, 228, 2048 }, { 6, 229, 2048 }, { 6, 230, 2048 }, { 7, 231, 2048 }, + { 5, 232, 2048 }, { 6, 233, 2048 }, { 6, 234, 2048 }, { 7, 235, 2048 }, { 6, 236, 2048 }, { 7, 237, 2048 }, { 7, 238, 2048 }, { 8, 239, 2048 }, + { 5, 240, 2048 }, { 6, 241, 2048 }, { 6, 242, 2048 }, { 7, 243, 2048 }, { 6, 244, 2048 }, { 7, 245, 2048 }, { 7, 246, 2048 }, { 8, 247, 2048 }, + { 6, 248, 2048 }, { 7, 249, 2048 }, { 7, 250, 2048 }, { 8, 251, 2048 }, { 7, 252, 2048 }, { 8, 253, 2048 }, { 8, 254, 2048 }, { 9, 255, 2048 }, + { 2, 256, 2048 }, { 3, 257, 2048 }, { 3, 258, 2048 }, { 4, 259, 2048 }, { 3, 260, 2048 }, { 4, 261, 2048 }, { 4, 262, 2048 }, { 5, 263, 2048 }, + { 3, 264, 2048 }, { 4, 265, 2048 }, { 4, 266, 2048 }, { 5, 267, 2048 }, { 4, 268, 2048 }, { 5, 269, 2048 }, { 5, 270, 2048 }, { 6, 271, 2048 }, + { 3, 272, 2048 }, { 4, 273, 2048 }, { 4, 274, 2048 }, { 5, 275, 2048 }, { 4, 276, 2048 }, { 5, 277, 2048 }, { 5, 278, 2048 }, { 6, 279, 2048 }, + { 4, 280, 2048 }, { 5, 281, 2048 }, { 5, 282, 2048 }, { 6, 283, 2048 }, { 5, 284, 2048 }, { 6, 285, 2048 }, { 6, 286, 2048 }, { 7, 287, 2048 }, + { 3, 288, 2048 }, { 4, 289, 2048 }, { 4, 290, 2048 }, { 5, 291, 2048 }, { 4, 292, 2048 }, { 5, 293, 2048 }, { 5, 294, 2048 }, { 6, 295, 2048 }, + { 4, 296, 2048 }, { 5, 297, 2048 }, { 5, 298, 2048 }, { 6, 299, 2048 }, { 5, 300, 2048 }, { 6, 301, 2048 }, { 6, 302, 2048 }, { 7, 303, 2048 }, + { 4, 304, 2048 }, { 5, 305, 2048 }, { 5, 306, 2048 }, { 6, 307, 2048 }, { 5, 308, 2048 }, { 6, 309, 2048 }, { 6, 310, 2048 }, { 7, 311, 2048 }, + { 5, 312, 2048 }, { 6, 313, 2048 }, { 6, 314, 2048 }, { 7, 315, 2048 }, { 6, 316, 2048 }, { 7, 317, 2048 }, { 7, 318, 2048 }, { 8, 319, 2048 }, + { 3, 320, 2048 }, { 4, 321, 2048 }, { 4, 322, 2048 }, { 5, 323, 2048 }, { 4, 324, 2048 }, { 5, 325, 2048 }, { 5, 326, 2048 }, { 6, 327, 2048 }, + { 4, 328, 2048 }, { 5, 329, 2048 }, { 5, 330, 2048 }, { 6, 331, 2048 }, { 5, 332, 2048 }, { 6, 333, 2048 }, { 6, 334, 2048 }, { 7, 335, 2048 }, + { 4, 336, 2048 }, { 5, 337, 2048 }, { 5, 338, 2048 }, { 6, 339, 2048 }, { 5, 340, 2048 }, { 6, 341, 2048 }, { 6, 342, 2048 }, { 7, 343, 2048 }, + { 5, 344, 2048 }, { 6, 345, 2048 }, { 6, 346, 2048 }, { 7, 347, 2048 }, { 6, 348, 2048 }, { 7, 349, 2048 }, { 7, 350, 2048 }, { 8, 351, 2048 }, + { 4, 352, 2048 }, { 5, 353, 2048 }, { 5, 354, 2048 }, { 6, 355, 2048 }, { 5, 356, 2048 }, { 6, 357, 2048 }, { 6, 358, 2048 }, { 7, 359, 2048 }, + { 5, 360, 2048 }, { 6, 361, 2048 }, { 6, 362, 2048 }, { 7, 363, 2048 }, { 6, 364, 2048 }, { 7, 365, 2048 }, { 7, 366, 2048 }, { 8, 367, 2048 }, + { 5, 368, 2048 }, { 6, 369, 2048 }, { 6, 370, 2048 }, { 7, 371, 2048 }, { 6, 372, 2048 }, { 7, 373, 2048 }, { 7, 374, 2048 }, { 8, 375, 2048 }, + { 6, 376, 2048 }, { 7, 377, 2048 }, { 7, 378, 2048 }, { 8, 379, 2048 }, { 7, 380, 2048 }, { 8, 381, 2048 }, { 8, 382, 2048 }, { 9, 383, 2048 }, + { 3, 384, 2048 }, { 4, 385, 2048 }, { 4, 386, 2048 }, { 5, 387, 2048 }, { 4, 388, 2048 }, { 5, 389, 2048 }, { 5, 390, 2048 }, { 6, 391, 2048 }, + { 4, 392, 2048 }, { 5, 393, 2048 }, { 5, 394, 2048 }, { 6, 395, 2048 }, { 5, 396, 2048 }, { 6, 397, 2048 }, { 6, 398, 2048 }, { 7, 399, 2048 }, + { 4, 400, 2048 }, { 5, 401, 2048 }, { 5, 402, 2048 }, { 6, 403, 2048 }, { 5, 404, 2048 }, { 6, 405, 2048 }, { 6, 406, 2048 }, { 7, 407, 2048 }, + { 5, 408, 2048 }, { 6, 409, 2048 }, { 6, 410, 2048 }, { 7, 411, 2048 }, { 6, 412, 2048 }, { 7, 413, 2048 }, { 7, 414, 2048 }, { 8, 415, 2048 }, + { 4, 416, 2048 }, { 5, 417, 2048 }, { 5, 418, 2048 }, { 6, 419, 2048 }, { 5, 420, 2048 }, { 6, 421, 2048 }, { 6, 422, 2048 }, { 7, 423, 2048 }, + { 5, 424, 2048 }, { 6, 425, 2048 }, { 6, 426, 2048 }, { 7, 427, 2048 }, { 6, 428, 2048 }, { 7, 429, 2048 }, { 7, 430, 2048 }, { 8, 431, 2048 }, + { 5, 432, 2048 }, { 6, 433, 2048 }, { 6, 434, 2048 }, { 7, 435, 2048 }, { 6, 436, 2048 }, { 7, 437, 2048 }, { 7, 438, 2048 }, { 8, 439, 2048 }, + { 6, 440, 2048 }, { 7, 441, 2048 }, { 7, 442, 2048 }, { 8, 443, 2048 }, { 7, 444, 2048 }, { 8, 445, 2048 }, { 8, 446, 2048 }, { 9, 447, 2048 }, + { 4, 448, 2048 }, { 5, 449, 2048 }, { 5, 450, 2048 }, { 6, 451, 2048 }, { 5, 452, 2048 }, { 6, 453, 2048 }, { 6, 454, 2048 }, { 7, 455, 2048 }, + { 5, 456, 2048 }, { 6, 457, 2048 }, { 6, 458, 2048 }, { 7, 459, 2048 }, { 6, 460, 2048 }, { 7, 461, 2048 }, { 7, 462, 2048 }, { 8, 463, 2048 }, + { 5, 464, 2048 }, { 6, 465, 2048 }, { 6, 466, 2048 }, { 7, 467, 2048 }, { 6, 468, 2048 }, { 7, 469, 2048 }, { 7, 470, 2048 }, { 8, 471, 2048 }, + { 6, 472, 2048 }, { 7, 473, 2048 }, { 7, 474, 2048 }, { 8, 475, 2048 }, { 7, 476, 2048 }, { 8, 477, 2048 }, { 8, 478, 2048 }, { 9, 479, 2048 }, + { 5, 480, 2048 }, { 6, 481, 2048 }, { 6, 482, 2048 }, { 7, 483, 2048 }, { 6, 484, 2048 }, { 7, 485, 2048 }, { 7, 486, 2048 }, { 8, 487, 2048 }, + { 6, 488, 2048 }, { 7, 489, 2048 }, { 7, 490, 2048 }, { 8, 491, 2048 }, { 7, 492, 2048 }, { 8, 493, 2048 }, { 8, 494, 2048 }, { 9, 495, 2048 }, + { 6, 496, 2048 }, { 7, 497, 2048 }, { 7, 498, 2048 }, { 8, 499, 2048 }, { 7, 500, 2048 }, { 8, 501, 2048 }, { 8, 502, 2048 }, { 9, 503, 2048 }, + { 7, 504, 2048 }, { 8, 505, 2048 }, { 8, 506, 2048 }, { 9, 507, 2048 }, { 8, 508, 2048 }, { 9, 509, 2048 }, { 9, 510, 2048 }, { 10, 511, 2048 }, + { 2, 512, 2048 }, { 3, 513, 2048 }, { 3, 514, 2048 }, { 4, 515, 2048 }, { 3, 516, 2048 }, { 4, 517, 2048 }, { 4, 518, 2048 }, { 5, 519, 2048 }, + { 3, 520, 2048 }, { 4, 521, 2048 }, { 4, 522, 2048 }, { 5, 523, 2048 }, { 4, 524, 2048 }, { 5, 525, 2048 }, { 5, 526, 2048 }, { 6, 527, 2048 }, + { 3, 528, 2048 }, { 4, 529, 2048 }, { 4, 530, 2048 }, { 5, 531, 2048 }, { 4, 532, 2048 }, { 5, 533, 2048 }, { 5, 534, 2048 }, { 6, 535, 2048 }, + { 4, 536, 2048 }, { 5, 537, 2048 }, { 5, 538, 2048 }, { 6, 539, 2048 }, { 5, 540, 2048 }, { 6, 541, 2048 }, { 6, 542, 2048 }, { 7, 543, 2048 }, + { 3, 544, 2048 }, { 4, 545, 2048 }, { 4, 546, 2048 }, { 5, 547, 2048 }, { 4, 548, 2048 }, { 5, 549, 2048 }, { 5, 550, 2048 }, { 6, 551, 2048 }, + { 4, 552, 2048 }, { 5, 553, 2048 }, { 5, 554, 2048 }, { 6, 555, 2048 }, { 5, 556, 2048 }, { 6, 557, 2048 }, { 6, 558, 2048 }, { 7, 559, 2048 }, + { 4, 560, 2048 }, { 5, 561, 2048 }, { 5, 562, 2048 }, { 6, 563, 2048 }, { 5, 564, 2048 }, { 6, 565, 2048 }, { 6, 566, 2048 }, { 7, 567, 2048 }, + { 5, 568, 2048 }, { 6, 569, 2048 }, { 6, 570, 2048 }, { 7, 571, 2048 }, { 6, 572, 2048 }, { 7, 573, 2048 }, { 7, 574, 2048 }, { 8, 575, 2048 }, + { 3, 576, 2048 }, { 4, 577, 2048 }, { 4, 578, 2048 }, { 5, 579, 2048 }, { 4, 580, 2048 }, { 5, 581, 2048 }, { 5, 582, 2048 }, { 6, 583, 2048 }, + { 4, 584, 2048 }, { 5, 585, 2048 }, { 5, 586, 2048 }, { 6, 587, 2048 }, { 5, 588, 2048 }, { 6, 589, 2048 }, { 6, 590, 2048 }, { 7, 591, 2048 }, + { 4, 592, 2048 }, { 5, 593, 2048 }, { 5, 594, 2048 }, { 6, 595, 2048 }, { 5, 596, 2048 }, { 6, 597, 2048 }, { 6, 598, 2048 }, { 7, 599, 2048 }, + { 5, 600, 2048 }, { 6, 601, 2048 }, { 6, 602, 2048 }, { 7, 603, 2048 }, { 6, 604, 2048 }, { 7, 605, 2048 }, { 7, 606, 2048 }, { 8, 607, 2048 }, + { 4, 608, 2048 }, { 5, 609, 2048 }, { 5, 610, 2048 }, { 6, 611, 2048 }, { 5, 612, 2048 }, { 6, 613, 2048 }, { 6, 614, 2048 }, { 7, 615, 2048 }, + { 5, 616, 2048 }, { 6, 617, 2048 }, { 6, 618, 2048 }, { 7, 619, 2048 }, { 6, 620, 2048 }, { 7, 621, 2048 }, { 7, 622, 2048 }, { 8, 623, 2048 }, + { 5, 624, 2048 }, { 6, 625, 2048 }, { 6, 626, 2048 }, { 7, 627, 2048 }, { 6, 628, 2048 }, { 7, 629, 2048 }, { 7, 630, 2048 }, { 8, 631, 2048 }, + { 6, 632, 2048 }, { 7, 633, 2048 }, { 7, 634, 2048 }, { 8, 635, 2048 }, { 7, 636, 2048 }, { 8, 637, 2048 }, { 8, 638, 2048 }, { 9, 639, 2048 }, + { 3, 640, 2048 }, { 4, 641, 2048 }, { 4, 642, 2048 }, { 5, 643, 2048 }, { 4, 644, 2048 }, { 5, 645, 2048 }, { 5, 646, 2048 }, { 6, 647, 2048 }, + { 4, 648, 2048 }, { 5, 649, 2048 }, { 5, 650, 2048 }, { 6, 651, 2048 }, { 5, 652, 2048 }, { 6, 653, 2048 }, { 6, 654, 2048 }, { 7, 655, 2048 }, + { 4, 656, 2048 }, { 5, 657, 2048 }, { 5, 658, 2048 }, { 6, 659, 2048 }, { 5, 660, 2048 }, { 6, 661, 2048 }, { 6, 662, 2048 }, { 7, 663, 2048 }, + { 5, 664, 2048 }, { 6, 665, 2048 }, { 6, 666, 2048 }, { 7, 667, 2048 }, { 6, 668, 2048 }, { 7, 669, 2048 }, { 7, 670, 2048 }, { 8, 671, 2048 }, + { 4, 672, 2048 }, { 5, 673, 2048 }, { 5, 674, 2048 }, { 6, 675, 2048 }, { 5, 676, 2048 }, { 6, 677, 2048 }, { 6, 678, 2048 }, { 7, 679, 2048 }, + { 5, 680, 2048 }, { 6, 681, 2048 }, { 6, 682, 2048 }, { 7, 683, 2048 }, { 6, 684, 2048 }, { 7, 685, 2048 }, { 7, 686, 2048 }, { 8, 687, 2048 }, + { 5, 688, 2048 }, { 6, 689, 2048 }, { 6, 690, 2048 }, { 7, 691, 2048 }, { 6, 692, 2048 }, { 7, 693, 2048 }, { 7, 694, 2048 }, { 8, 695, 2048 }, + { 6, 696, 2048 }, { 7, 697, 2048 }, { 7, 698, 2048 }, { 8, 699, 2048 }, { 7, 700, 2048 }, { 8, 701, 2048 }, { 8, 702, 2048 }, { 9, 703, 2048 }, + { 4, 704, 2048 }, { 5, 705, 2048 }, { 5, 706, 2048 }, { 6, 707, 2048 }, { 5, 708, 2048 }, { 6, 709, 2048 }, { 6, 710, 2048 }, { 7, 711, 2048 }, + { 5, 712, 2048 }, { 6, 713, 2048 }, { 6, 714, 2048 }, { 7, 715, 2048 }, { 6, 716, 2048 }, { 7, 717, 2048 }, { 7, 718, 2048 }, { 8, 719, 2048 }, + { 5, 720, 2048 }, { 6, 721, 2048 }, { 6, 722, 2048 }, { 7, 723, 2048 }, { 6, 724, 2048 }, { 7, 725, 2048 }, { 7, 726, 2048 }, { 8, 727, 2048 }, + { 6, 728, 2048 }, { 7, 729, 2048 }, { 7, 730, 2048 }, { 8, 731, 2048 }, { 7, 732, 2048 }, { 8, 733, 2048 }, { 8, 734, 2048 }, { 9, 735, 2048 }, + { 5, 736, 2048 }, { 6, 737, 2048 }, { 6, 738, 2048 }, { 7, 739, 2048 }, { 6, 740, 2048 }, { 7, 741, 2048 }, { 7, 742, 2048 }, { 8, 743, 2048 }, + { 6, 744, 2048 }, { 7, 745, 2048 }, { 7, 746, 2048 }, { 8, 747, 2048 }, { 7, 748, 2048 }, { 8, 749, 2048 }, { 8, 750, 2048 }, { 9, 751, 2048 }, + { 6, 752, 2048 }, { 7, 753, 2048 }, { 7, 754, 2048 }, { 8, 755, 2048 }, { 7, 756, 2048 }, { 8, 757, 2048 }, { 8, 758, 2048 }, { 9, 759, 2048 }, + { 7, 760, 2048 }, { 8, 761, 2048 }, { 8, 762, 2048 }, { 9, 763, 2048 }, { 8, 764, 2048 }, { 9, 765, 2048 }, { 9, 766, 2048 }, { 10, 767, 2048 }, + { 3, 768, 2048 }, { 4, 769, 2048 }, { 4, 770, 2048 }, { 5, 771, 2048 }, { 4, 772, 2048 }, { 5, 773, 2048 }, { 5, 774, 2048 }, { 6, 775, 2048 }, + { 4, 776, 2048 }, { 5, 777, 2048 }, { 5, 778, 2048 }, { 6, 779, 2048 }, { 5, 780, 2048 }, { 6, 781, 2048 }, { 6, 782, 2048 }, { 7, 783, 2048 }, + { 4, 784, 2048 }, { 5, 785, 2048 }, { 5, 786, 2048 }, { 6, 787, 2048 }, { 5, 788, 2048 }, { 6, 789, 2048 }, { 6, 790, 2048 }, { 7, 791, 2048 }, + { 5, 792, 2048 }, { 6, 793, 2048 }, { 6, 794, 2048 }, { 7, 795, 2048 }, { 6, 796, 2048 }, { 7, 797, 2048 }, { 7, 798, 2048 }, { 8, 799, 2048 }, + { 4, 800, 2048 }, { 5, 801, 2048 }, { 5, 802, 2048 }, { 6, 803, 2048 }, { 5, 804, 2048 }, { 6, 805, 2048 }, { 6, 806, 2048 }, { 7, 807, 2048 }, + { 5, 808, 2048 }, { 6, 809, 2048 }, { 6, 810, 2048 }, { 7, 811, 2048 }, { 6, 812, 2048 }, { 7, 813, 2048 }, { 7, 814, 2048 }, { 8, 815, 2048 }, + { 5, 816, 2048 }, { 6, 817, 2048 }, { 6, 818, 2048 }, { 7, 819, 2048 }, { 6, 820, 2048 }, { 7, 821, 2048 }, { 7, 822, 2048 }, { 8, 823, 2048 }, + { 6, 824, 2048 }, { 7, 825, 2048 }, { 7, 826, 2048 }, { 8, 827, 2048 }, { 7, 828, 2048 }, { 8, 829, 2048 }, { 8, 830, 2048 }, { 9, 831, 2048 }, + { 4, 832, 2048 }, { 5, 833, 2048 }, { 5, 834, 2048 }, { 6, 835, 2048 }, { 5, 836, 2048 }, { 6, 837, 2048 }, { 6, 838, 2048 }, { 7, 839, 2048 }, + { 5, 840, 2048 }, { 6, 841, 2048 }, { 6, 842, 2048 }, { 7, 843, 2048 }, { 6, 844, 2048 }, { 7, 845, 2048 }, { 7, 846, 2048 }, { 8, 847, 2048 }, + { 5, 848, 2048 }, { 6, 849, 2048 }, { 6, 850, 2048 }, { 7, 851, 2048 }, { 6, 852, 2048 }, { 7, 853, 2048 }, { 7, 854, 2048 }, { 8, 855, 2048 }, + { 6, 856, 2048 }, { 7, 857, 2048 }, { 7, 858, 2048 }, { 8, 859, 2048 }, { 7, 860, 2048 }, { 8, 861, 2048 }, { 8, 862, 2048 }, { 9, 863, 2048 }, + { 5, 864, 2048 }, { 6, 865, 2048 }, { 6, 866, 2048 }, { 7, 867, 2048 }, { 6, 868, 2048 }, { 7, 869, 2048 }, { 7, 870, 2048 }, { 8, 871, 2048 }, + { 6, 872, 2048 }, { 7, 873, 2048 }, { 7, 874, 2048 }, { 8, 875, 2048 }, { 7, 876, 2048 }, { 8, 877, 2048 }, { 8, 878, 2048 }, { 9, 879, 2048 }, + { 6, 880, 2048 }, { 7, 881, 2048 }, { 7, 882, 2048 }, { 8, 883, 2048 }, { 7, 884, 2048 }, { 8, 885, 2048 }, { 8, 886, 2048 }, { 9, 887, 2048 }, + { 7, 888, 2048 }, { 8, 889, 2048 }, { 8, 890, 2048 }, { 9, 891, 2048 }, { 8, 892, 2048 }, { 9, 893, 2048 }, { 9, 894, 2048 }, { 10, 895, 2048 }, + { 4, 896, 2048 }, { 5, 897, 2048 }, { 5, 898, 2048 }, { 6, 899, 2048 }, { 5, 900, 2048 }, { 6, 901, 2048 }, { 6, 902, 2048 }, { 7, 903, 2048 }, + { 5, 904, 2048 }, { 6, 905, 2048 }, { 6, 906, 2048 }, { 7, 907, 2048 }, { 6, 908, 2048 }, { 7, 909, 2048 }, { 7, 910, 2048 }, { 8, 911, 2048 }, + { 5, 912, 2048 }, { 6, 913, 2048 }, { 6, 914, 2048 }, { 7, 915, 2048 }, { 6, 916, 2048 }, { 7, 917, 2048 }, { 7, 918, 2048 }, { 8, 919, 2048 }, + { 6, 920, 2048 }, { 7, 921, 2048 }, { 7, 922, 2048 }, { 8, 923, 2048 }, { 7, 924, 2048 }, { 8, 925, 2048 }, { 8, 926, 2048 }, { 9, 927, 2048 }, + { 5, 928, 2048 }, { 6, 929, 2048 }, { 6, 930, 2048 }, { 7, 931, 2048 }, { 6, 932, 2048 }, { 7, 933, 2048 }, { 7, 934, 2048 }, { 8, 935, 2048 }, + { 6, 936, 2048 }, { 7, 937, 2048 }, { 7, 938, 2048 }, { 8, 939, 2048 }, { 7, 940, 2048 }, { 8, 941, 2048 }, { 8, 942, 2048 }, { 9, 943, 2048 }, + { 6, 944, 2048 }, { 7, 945, 2048 }, { 7, 946, 2048 }, { 8, 947, 2048 }, { 7, 948, 2048 }, { 8, 949, 2048 }, { 8, 950, 2048 }, { 9, 951, 2048 }, + { 7, 952, 2048 }, { 8, 953, 2048 }, { 8, 954, 2048 }, { 9, 955, 2048 }, { 8, 956, 2048 }, { 9, 957, 2048 }, { 9, 958, 2048 }, { 10, 959, 2048 }, + { 5, 960, 2048 }, { 6, 961, 2048 }, { 6, 962, 2048 }, { 7, 963, 2048 }, { 6, 964, 2048 }, { 7, 965, 2048 }, { 7, 966, 2048 }, { 8, 967, 2048 }, + { 6, 968, 2048 }, { 7, 969, 2048 }, { 7, 970, 2048 }, { 8, 971, 2048 }, { 7, 972, 2048 }, { 8, 973, 2048 }, { 8, 974, 2048 }, { 9, 975, 2048 }, + { 6, 976, 2048 }, { 7, 977, 2048 }, { 7, 978, 2048 }, { 8, 979, 2048 }, { 7, 980, 2048 }, { 8, 981, 2048 }, { 8, 982, 2048 }, { 9, 983, 2048 }, + { 7, 984, 2048 }, { 8, 985, 2048 }, { 8, 986, 2048 }, { 9, 987, 2048 }, { 8, 988, 2048 }, { 9, 989, 2048 }, { 9, 990, 2048 }, { 10, 991, 2048 }, + { 6, 992, 2048 }, { 7, 993, 2048 }, { 7, 994, 2048 }, { 8, 995, 2048 }, { 7, 996, 2048 }, { 8, 997, 2048 }, { 8, 998, 2048 }, { 9, 999, 2048 }, + { 7, 1000, 2048 }, { 8, 1001, 2048 }, { 8, 1002, 2048 }, { 9, 1003, 2048 }, { 8, 1004, 2048 }, { 9, 1005, 2048 }, { 9, 1006, 2048 }, { 10, 1007, 2048 }, + { 7, 1008, 2048 }, { 8, 1009, 2048 }, { 8, 1010, 2048 }, { 9, 1011, 2048 }, { 8, 1012, 2048 }, { 9, 1013, 2048 }, { 9, 1014, 2048 }, { 10, 1015, 2048 }, + { 8, 1016, 2048 }, { 9, 1017, 2048 }, { 9, 1018, 2048 }, { 10, 1019, 2048 }, { 9, 1020, 2048 }, { 10, 1021, 2048 }, { 10, 1022, 2048 }, { 11, 1023, 2048 }, + { 2, 1024, 2048 }, { 3, 1025, 2048 }, { 3, 1026, 2048 }, { 4, 1027, 2048 }, { 3, 1028, 2048 }, { 4, 1029, 2048 }, { 4, 1030, 2048 }, { 5, 1031, 2048 }, + { 3, 1032, 2048 }, { 4, 1033, 2048 }, { 4, 1034, 2048 }, { 5, 1035, 2048 }, { 4, 1036, 2048 }, { 5, 1037, 2048 }, { 5, 1038, 2048 }, { 6, 1039, 2048 }, + { 3, 1040, 2048 }, { 4, 1041, 2048 }, { 4, 1042, 2048 }, { 5, 1043, 2048 }, { 4, 1044, 2048 }, { 5, 1045, 2048 }, { 5, 1046, 2048 }, { 6, 1047, 2048 }, + { 4, 1048, 2048 }, { 5, 1049, 2048 }, { 5, 1050, 2048 }, { 6, 1051, 2048 }, { 5, 1052, 2048 }, { 6, 1053, 2048 }, { 6, 1054, 2048 }, { 7, 1055, 2048 }, + { 3, 1056, 2048 }, { 4, 1057, 2048 }, { 4, 1058, 2048 }, { 5, 1059, 2048 }, { 4, 1060, 2048 }, { 5, 1061, 2048 }, { 5, 1062, 2048 }, { 6, 1063, 2048 }, + { 4, 1064, 2048 }, { 5, 1065, 2048 }, { 5, 1066, 2048 }, { 6, 1067, 2048 }, { 5, 1068, 2048 }, { 6, 1069, 2048 }, { 6, 1070, 2048 }, { 7, 1071, 2048 }, + { 4, 1072, 2048 }, { 5, 1073, 2048 }, { 5, 1074, 2048 }, { 6, 1075, 2048 }, { 5, 1076, 2048 }, { 6, 1077, 2048 }, { 6, 1078, 2048 }, { 7, 1079, 2048 }, + { 5, 1080, 2048 }, { 6, 1081, 2048 }, { 6, 1082, 2048 }, { 7, 1083, 2048 }, { 6, 1084, 2048 }, { 7, 1085, 2048 }, { 7, 1086, 2048 }, { 8, 1087, 2048 }, + { 3, 1088, 2048 }, { 4, 1089, 2048 }, { 4, 1090, 2048 }, { 5, 1091, 2048 }, { 4, 1092, 2048 }, { 5, 1093, 2048 }, { 5, 1094, 2048 }, { 6, 1095, 2048 }, + { 4, 1096, 2048 }, { 5, 1097, 2048 }, { 5, 1098, 2048 }, { 6, 1099, 2048 }, { 5, 1100, 2048 }, { 6, 1101, 2048 }, { 6, 1102, 2048 }, { 7, 1103, 2048 }, + { 4, 1104, 2048 }, { 5, 1105, 2048 }, { 5, 1106, 2048 }, { 6, 1107, 2048 }, { 5, 1108, 2048 }, { 6, 1109, 2048 }, { 6, 1110, 2048 }, { 7, 1111, 2048 }, + { 5, 1112, 2048 }, { 6, 1113, 2048 }, { 6, 1114, 2048 }, { 7, 1115, 2048 }, { 6, 1116, 2048 }, { 7, 1117, 2048 }, { 7, 1118, 2048 }, { 8, 1119, 2048 }, + { 4, 1120, 2048 }, { 5, 1121, 2048 }, { 5, 1122, 2048 }, { 6, 1123, 2048 }, { 5, 1124, 2048 }, { 6, 1125, 2048 }, { 6, 1126, 2048 }, { 7, 1127, 2048 }, + { 5, 1128, 2048 }, { 6, 1129, 2048 }, { 6, 1130, 2048 }, { 7, 1131, 2048 }, { 6, 1132, 2048 }, { 7, 1133, 2048 }, { 7, 1134, 2048 }, { 8, 1135, 2048 }, + { 5, 1136, 2048 }, { 6, 1137, 2048 }, { 6, 1138, 2048 }, { 7, 1139, 2048 }, { 6, 1140, 2048 }, { 7, 1141, 2048 }, { 7, 1142, 2048 }, { 8, 1143, 2048 }, + { 6, 1144, 2048 }, { 7, 1145, 2048 }, { 7, 1146, 2048 }, { 8, 1147, 2048 }, { 7, 1148, 2048 }, { 8, 1149, 2048 }, { 8, 1150, 2048 }, { 9, 1151, 2048 }, + { 3, 1152, 2048 }, { 4, 1153, 2048 }, { 4, 1154, 2048 }, { 5, 1155, 2048 }, { 4, 1156, 2048 }, { 5, 1157, 2048 }, { 5, 1158, 2048 }, { 6, 1159, 2048 }, + { 4, 1160, 2048 }, { 5, 1161, 2048 }, { 5, 1162, 2048 }, { 6, 1163, 2048 }, { 5, 1164, 2048 }, { 6, 1165, 2048 }, { 6, 1166, 2048 }, { 7, 1167, 2048 }, + { 4, 1168, 2048 }, { 5, 1169, 2048 }, { 5, 1170, 2048 }, { 6, 1171, 2048 }, { 5, 1172, 2048 }, { 6, 1173, 2048 }, { 6, 1174, 2048 }, { 7, 1175, 2048 }, + { 5, 1176, 2048 }, { 6, 1177, 2048 }, { 6, 1178, 2048 }, { 7, 1179, 2048 }, { 6, 1180, 2048 }, { 7, 1181, 2048 }, { 7, 1182, 2048 }, { 8, 1183, 2048 }, + { 4, 1184, 2048 }, { 5, 1185, 2048 }, { 5, 1186, 2048 }, { 6, 1187, 2048 }, { 5, 1188, 2048 }, { 6, 1189, 2048 }, { 6, 1190, 2048 }, { 7, 1191, 2048 }, + { 5, 1192, 2048 }, { 6, 1193, 2048 }, { 6, 1194, 2048 }, { 7, 1195, 2048 }, { 6, 1196, 2048 }, { 7, 1197, 2048 }, { 7, 1198, 2048 }, { 8, 1199, 2048 }, + { 5, 1200, 2048 }, { 6, 1201, 2048 }, { 6, 1202, 2048 }, { 7, 1203, 2048 }, { 6, 1204, 2048 }, { 7, 1205, 2048 }, { 7, 1206, 2048 }, { 8, 1207, 2048 }, + { 6, 1208, 2048 }, { 7, 1209, 2048 }, { 7, 1210, 2048 }, { 8, 1211, 2048 }, { 7, 1212, 2048 }, { 8, 1213, 2048 }, { 8, 1214, 2048 }, { 9, 1215, 2048 }, + { 4, 1216, 2048 }, { 5, 1217, 2048 }, { 5, 1218, 2048 }, { 6, 1219, 2048 }, { 5, 1220, 2048 }, { 6, 1221, 2048 }, { 6, 1222, 2048 }, { 7, 1223, 2048 }, + { 5, 1224, 2048 }, { 6, 1225, 2048 }, { 6, 1226, 2048 }, { 7, 1227, 2048 }, { 6, 1228, 2048 }, { 7, 1229, 2048 }, { 7, 1230, 2048 }, { 8, 1231, 2048 }, + { 5, 1232, 2048 }, { 6, 1233, 2048 }, { 6, 1234, 2048 }, { 7, 1235, 2048 }, { 6, 1236, 2048 }, { 7, 1237, 2048 }, { 7, 1238, 2048 }, { 8, 1239, 2048 }, + { 6, 1240, 2048 }, { 7, 1241, 2048 }, { 7, 1242, 2048 }, { 8, 1243, 2048 }, { 7, 1244, 2048 }, { 8, 1245, 2048 }, { 8, 1246, 2048 }, { 9, 1247, 2048 }, + { 5, 1248, 2048 }, { 6, 1249, 2048 }, { 6, 1250, 2048 }, { 7, 1251, 2048 }, { 6, 1252, 2048 }, { 7, 1253, 2048 }, { 7, 1254, 2048 }, { 8, 1255, 2048 }, + { 6, 1256, 2048 }, { 7, 1257, 2048 }, { 7, 1258, 2048 }, { 8, 1259, 2048 }, { 7, 1260, 2048 }, { 8, 1261, 2048 }, { 8, 1262, 2048 }, { 9, 1263, 2048 }, + { 6, 1264, 2048 }, { 7, 1265, 2048 }, { 7, 1266, 2048 }, { 8, 1267, 2048 }, { 7, 1268, 2048 }, { 8, 1269, 2048 }, { 8, 1270, 2048 }, { 9, 1271, 2048 }, + { 7, 1272, 2048 }, { 8, 1273, 2048 }, { 8, 1274, 2048 }, { 9, 1275, 2048 }, { 8, 1276, 2048 }, { 9, 1277, 2048 }, { 9, 1278, 2048 }, { 10, 1279, 2048 }, + { 3, 1280, 2048 }, { 4, 1281, 2048 }, { 4, 1282, 2048 }, { 5, 1283, 2048 }, { 4, 1284, 2048 }, { 5, 1285, 2048 }, { 5, 1286, 2048 }, { 6, 1287, 2048 }, + { 4, 1288, 2048 }, { 5, 1289, 2048 }, { 5, 1290, 2048 }, { 6, 1291, 2048 }, { 5, 1292, 2048 }, { 6, 1293, 2048 }, { 6, 1294, 2048 }, { 7, 1295, 2048 }, + { 4, 1296, 2048 }, { 5, 1297, 2048 }, { 5, 1298, 2048 }, { 6, 1299, 2048 }, { 5, 1300, 2048 }, { 6, 1301, 2048 }, { 6, 1302, 2048 }, { 7, 1303, 2048 }, + { 5, 1304, 2048 }, { 6, 1305, 2048 }, { 6, 1306, 2048 }, { 7, 1307, 2048 }, { 6, 1308, 2048 }, { 7, 1309, 2048 }, { 7, 1310, 2048 }, { 8, 1311, 2048 }, + { 4, 1312, 2048 }, { 5, 1313, 2048 }, { 5, 1314, 2048 }, { 6, 1315, 2048 }, { 5, 1316, 2048 }, { 6, 1317, 2048 }, { 6, 1318, 2048 }, { 7, 1319, 2048 }, + { 5, 1320, 2048 }, { 6, 1321, 2048 }, { 6, 1322, 2048 }, { 7, 1323, 2048 }, { 6, 1324, 2048 }, { 7, 1325, 2048 }, { 7, 1326, 2048 }, { 8, 1327, 2048 }, + { 5, 1328, 2048 }, { 6, 1329, 2048 }, { 6, 1330, 2048 }, { 7, 1331, 2048 }, { 6, 1332, 2048 }, { 7, 1333, 2048 }, { 7, 1334, 2048 }, { 8, 1335, 2048 }, + { 6, 1336, 2048 }, { 7, 1337, 2048 }, { 7, 1338, 2048 }, { 8, 1339, 2048 }, { 7, 1340, 2048 }, { 8, 1341, 2048 }, { 8, 1342, 2048 }, { 9, 1343, 2048 }, + { 4, 1344, 2048 }, { 5, 1345, 2048 }, { 5, 1346, 2048 }, { 6, 1347, 2048 }, { 5, 1348, 2048 }, { 6, 1349, 2048 }, { 6, 1350, 2048 }, { 7, 1351, 2048 }, + { 5, 1352, 2048 }, { 6, 1353, 2048 }, { 6, 1354, 2048 }, { 7, 1355, 2048 }, { 6, 1356, 2048 }, { 7, 1357, 2048 }, { 7, 1358, 2048 }, { 8, 1359, 2048 }, + { 5, 1360, 2048 }, { 6, 1361, 2048 }, { 6, 1362, 2048 }, { 7, 1363, 2048 }, { 6, 1364, 2048 }, { 7, 1365, 2048 }, { 7, 1366, 2048 }, { 8, 1367, 2048 }, + { 6, 1368, 2048 }, { 7, 1369, 2048 }, { 7, 1370, 2048 }, { 8, 1371, 2048 }, { 7, 1372, 2048 }, { 8, 1373, 2048 }, { 8, 1374, 2048 }, { 9, 1375, 2048 }, + { 5, 1376, 2048 }, { 6, 1377, 2048 }, { 6, 1378, 2048 }, { 7, 1379, 2048 }, { 6, 1380, 2048 }, { 7, 1381, 2048 }, { 7, 1382, 2048 }, { 8, 1383, 2048 }, + { 6, 1384, 2048 }, { 7, 1385, 2048 }, { 7, 1386, 2048 }, { 8, 1387, 2048 }, { 7, 1388, 2048 }, { 8, 1389, 2048 }, { 8, 1390, 2048 }, { 9, 1391, 2048 }, + { 6, 1392, 2048 }, { 7, 1393, 2048 }, { 7, 1394, 2048 }, { 8, 1395, 2048 }, { 7, 1396, 2048 }, { 8, 1397, 2048 }, { 8, 1398, 2048 }, { 9, 1399, 2048 }, + { 7, 1400, 2048 }, { 8, 1401, 2048 }, { 8, 1402, 2048 }, { 9, 1403, 2048 }, { 8, 1404, 2048 }, { 9, 1405, 2048 }, { 9, 1406, 2048 }, { 10, 1407, 2048 }, + { 4, 1408, 2048 }, { 5, 1409, 2048 }, { 5, 1410, 2048 }, { 6, 1411, 2048 }, { 5, 1412, 2048 }, { 6, 1413, 2048 }, { 6, 1414, 2048 }, { 7, 1415, 2048 }, + { 5, 1416, 2048 }, { 6, 1417, 2048 }, { 6, 1418, 2048 }, { 7, 1419, 2048 }, { 6, 1420, 2048 }, { 7, 1421, 2048 }, { 7, 1422, 2048 }, { 8, 1423, 2048 }, + { 5, 1424, 2048 }, { 6, 1425, 2048 }, { 6, 1426, 2048 }, { 7, 1427, 2048 }, { 6, 1428, 2048 }, { 7, 1429, 2048 }, { 7, 1430, 2048 }, { 8, 1431, 2048 }, + { 6, 1432, 2048 }, { 7, 1433, 2048 }, { 7, 1434, 2048 }, { 8, 1435, 2048 }, { 7, 1436, 2048 }, { 8, 1437, 2048 }, { 8, 1438, 2048 }, { 9, 1439, 2048 }, + { 5, 1440, 2048 }, { 6, 1441, 2048 }, { 6, 1442, 2048 }, { 7, 1443, 2048 }, { 6, 1444, 2048 }, { 7, 1445, 2048 }, { 7, 1446, 2048 }, { 8, 1447, 2048 }, + { 6, 1448, 2048 }, { 7, 1449, 2048 }, { 7, 1450, 2048 }, { 8, 1451, 2048 }, { 7, 1452, 2048 }, { 8, 1453, 2048 }, { 8, 1454, 2048 }, { 9, 1455, 2048 }, + { 6, 1456, 2048 }, { 7, 1457, 2048 }, { 7, 1458, 2048 }, { 8, 1459, 2048 }, { 7, 1460, 2048 }, { 8, 1461, 2048 }, { 8, 1462, 2048 }, { 9, 1463, 2048 }, + { 7, 1464, 2048 }, { 8, 1465, 2048 }, { 8, 1466, 2048 }, { 9, 1467, 2048 }, { 8, 1468, 2048 }, { 9, 1469, 2048 }, { 9, 1470, 2048 }, { 10, 1471, 2048 }, + { 5, 1472, 2048 }, { 6, 1473, 2048 }, { 6, 1474, 2048 }, { 7, 1475, 2048 }, { 6, 1476, 2048 }, { 7, 1477, 2048 }, { 7, 1478, 2048 }, { 8, 1479, 2048 }, + { 6, 1480, 2048 }, { 7, 1481, 2048 }, { 7, 1482, 2048 }, { 8, 1483, 2048 }, { 7, 1484, 2048 }, { 8, 1485, 2048 }, { 8, 1486, 2048 }, { 9, 1487, 2048 }, + { 6, 1488, 2048 }, { 7, 1489, 2048 }, { 7, 1490, 2048 }, { 8, 1491, 2048 }, { 7, 1492, 2048 }, { 8, 1493, 2048 }, { 8, 1494, 2048 }, { 9, 1495, 2048 }, + { 7, 1496, 2048 }, { 8, 1497, 2048 }, { 8, 1498, 2048 }, { 9, 1499, 2048 }, { 8, 1500, 2048 }, { 9, 1501, 2048 }, { 9, 1502, 2048 }, { 10, 1503, 2048 }, + { 6, 1504, 2048 }, { 7, 1505, 2048 }, { 7, 1506, 2048 }, { 8, 1507, 2048 }, { 7, 1508, 2048 }, { 8, 1509, 2048 }, { 8, 1510, 2048 }, { 9, 1511, 2048 }, + { 7, 1512, 2048 }, { 8, 1513, 2048 }, { 8, 1514, 2048 }, { 9, 1515, 2048 }, { 8, 1516, 2048 }, { 9, 1517, 2048 }, { 9, 1518, 2048 }, { 10, 1519, 2048 }, + { 7, 1520, 2048 }, { 8, 1521, 2048 }, { 8, 1522, 2048 }, { 9, 1523, 2048 }, { 8, 1524, 2048 }, { 9, 1525, 2048 }, { 9, 1526, 2048 }, { 10, 1527, 2048 }, + { 8, 1528, 2048 }, { 9, 1529, 2048 }, { 9, 1530, 2048 }, { 10, 1531, 2048 }, { 9, 1532, 2048 }, { 10, 1533, 2048 }, { 10, 1534, 2048 }, { 11, 1535, 2048 }, + { 3, 1536, 2048 }, { 4, 1537, 2048 }, { 4, 1538, 2048 }, { 5, 1539, 2048 }, { 4, 1540, 2048 }, { 5, 1541, 2048 }, { 5, 1542, 2048 }, { 6, 1543, 2048 }, + { 4, 1544, 2048 }, { 5, 1545, 2048 }, { 5, 1546, 2048 }, { 6, 1547, 2048 }, { 5, 1548, 2048 }, { 6, 1549, 2048 }, { 6, 1550, 2048 }, { 7, 1551, 2048 }, + { 4, 1552, 2048 }, { 5, 1553, 2048 }, { 5, 1554, 2048 }, { 6, 1555, 2048 }, { 5, 1556, 2048 }, { 6, 1557, 2048 }, { 6, 1558, 2048 }, { 7, 1559, 2048 }, + { 5, 1560, 2048 }, { 6, 1561, 2048 }, { 6, 1562, 2048 }, { 7, 1563, 2048 }, { 6, 1564, 2048 }, { 7, 1565, 2048 }, { 7, 1566, 2048 }, { 8, 1567, 2048 }, + { 4, 1568, 2048 }, { 5, 1569, 2048 }, { 5, 1570, 2048 }, { 6, 1571, 2048 }, { 5, 1572, 2048 }, { 6, 1573, 2048 }, { 6, 1574, 2048 }, { 7, 1575, 2048 }, + { 5, 1576, 2048 }, { 6, 1577, 2048 }, { 6, 1578, 2048 }, { 7, 1579, 2048 }, { 6, 1580, 2048 }, { 7, 1581, 2048 }, { 7, 1582, 2048 }, { 8, 1583, 2048 }, + { 5, 1584, 2048 }, { 6, 1585, 2048 }, { 6, 1586, 2048 }, { 7, 1587, 2048 }, { 6, 1588, 2048 }, { 7, 1589, 2048 }, { 7, 1590, 2048 }, { 8, 1591, 2048 }, + { 6, 1592, 2048 }, { 7, 1593, 2048 }, { 7, 1594, 2048 }, { 8, 1595, 2048 }, { 7, 1596, 2048 }, { 8, 1597, 2048 }, { 8, 1598, 2048 }, { 9, 1599, 2048 }, + { 4, 1600, 2048 }, { 5, 1601, 2048 }, { 5, 1602, 2048 }, { 6, 1603, 2048 }, { 5, 1604, 2048 }, { 6, 1605, 2048 }, { 6, 1606, 2048 }, { 7, 1607, 2048 }, + { 5, 1608, 2048 }, { 6, 1609, 2048 }, { 6, 1610, 2048 }, { 7, 1611, 2048 }, { 6, 1612, 2048 }, { 7, 1613, 2048 }, { 7, 1614, 2048 }, { 8, 1615, 2048 }, + { 5, 1616, 2048 }, { 6, 1617, 2048 }, { 6, 1618, 2048 }, { 7, 1619, 2048 }, { 6, 1620, 2048 }, { 7, 1621, 2048 }, { 7, 1622, 2048 }, { 8, 1623, 2048 }, + { 6, 1624, 2048 }, { 7, 1625, 2048 }, { 7, 1626, 2048 }, { 8, 1627, 2048 }, { 7, 1628, 2048 }, { 8, 1629, 2048 }, { 8, 1630, 2048 }, { 9, 1631, 2048 }, + { 5, 1632, 2048 }, { 6, 1633, 2048 }, { 6, 1634, 2048 }, { 7, 1635, 2048 }, { 6, 1636, 2048 }, { 7, 1637, 2048 }, { 7, 1638, 2048 }, { 8, 1639, 2048 }, + { 6, 1640, 2048 }, { 7, 1641, 2048 }, { 7, 1642, 2048 }, { 8, 1643, 2048 }, { 7, 1644, 2048 }, { 8, 1645, 2048 }, { 8, 1646, 2048 }, { 9, 1647, 2048 }, + { 6, 1648, 2048 }, { 7, 1649, 2048 }, { 7, 1650, 2048 }, { 8, 1651, 2048 }, { 7, 1652, 2048 }, { 8, 1653, 2048 }, { 8, 1654, 2048 }, { 9, 1655, 2048 }, + { 7, 1656, 2048 }, { 8, 1657, 2048 }, { 8, 1658, 2048 }, { 9, 1659, 2048 }, { 8, 1660, 2048 }, { 9, 1661, 2048 }, { 9, 1662, 2048 }, { 10, 1663, 2048 }, + { 4, 1664, 2048 }, { 5, 1665, 2048 }, { 5, 1666, 2048 }, { 6, 1667, 2048 }, { 5, 1668, 2048 }, { 6, 1669, 2048 }, { 6, 1670, 2048 }, { 7, 1671, 2048 }, + { 5, 1672, 2048 }, { 6, 1673, 2048 }, { 6, 1674, 2048 }, { 7, 1675, 2048 }, { 6, 1676, 2048 }, { 7, 1677, 2048 }, { 7, 1678, 2048 }, { 8, 1679, 2048 }, + { 5, 1680, 2048 }, { 6, 1681, 2048 }, { 6, 1682, 2048 }, { 7, 1683, 2048 }, { 6, 1684, 2048 }, { 7, 1685, 2048 }, { 7, 1686, 2048 }, { 8, 1687, 2048 }, + { 6, 1688, 2048 }, { 7, 1689, 2048 }, { 7, 1690, 2048 }, { 8, 1691, 2048 }, { 7, 1692, 2048 }, { 8, 1693, 2048 }, { 8, 1694, 2048 }, { 9, 1695, 2048 }, + { 5, 1696, 2048 }, { 6, 1697, 2048 }, { 6, 1698, 2048 }, { 7, 1699, 2048 }, { 6, 1700, 2048 }, { 7, 1701, 2048 }, { 7, 1702, 2048 }, { 8, 1703, 2048 }, + { 6, 1704, 2048 }, { 7, 1705, 2048 }, { 7, 1706, 2048 }, { 8, 1707, 2048 }, { 7, 1708, 2048 }, { 8, 1709, 2048 }, { 8, 1710, 2048 }, { 9, 1711, 2048 }, + { 6, 1712, 2048 }, { 7, 1713, 2048 }, { 7, 1714, 2048 }, { 8, 1715, 2048 }, { 7, 1716, 2048 }, { 8, 1717, 2048 }, { 8, 1718, 2048 }, { 9, 1719, 2048 }, + { 7, 1720, 2048 }, { 8, 1721, 2048 }, { 8, 1722, 2048 }, { 9, 1723, 2048 }, { 8, 1724, 2048 }, { 9, 1725, 2048 }, { 9, 1726, 2048 }, { 10, 1727, 2048 }, + { 5, 1728, 2048 }, { 6, 1729, 2048 }, { 6, 1730, 2048 }, { 7, 1731, 2048 }, { 6, 1732, 2048 }, { 7, 1733, 2048 }, { 7, 1734, 2048 }, { 8, 1735, 2048 }, + { 6, 1736, 2048 }, { 7, 1737, 2048 }, { 7, 1738, 2048 }, { 8, 1739, 2048 }, { 7, 1740, 2048 }, { 8, 1741, 2048 }, { 8, 1742, 2048 }, { 9, 1743, 2048 }, + { 6, 1744, 2048 }, { 7, 1745, 2048 }, { 7, 1746, 2048 }, { 8, 1747, 2048 }, { 7, 1748, 2048 }, { 8, 1749, 2048 }, { 8, 1750, 2048 }, { 9, 1751, 2048 }, + { 7, 1752, 2048 }, { 8, 1753, 2048 }, { 8, 1754, 2048 }, { 9, 1755, 2048 }, { 8, 1756, 2048 }, { 9, 1757, 2048 }, { 9, 1758, 2048 }, { 10, 1759, 2048 }, + { 6, 1760, 2048 }, { 7, 1761, 2048 }, { 7, 1762, 2048 }, { 8, 1763, 2048 }, { 7, 1764, 2048 }, { 8, 1765, 2048 }, { 8, 1766, 2048 }, { 9, 1767, 2048 }, + { 7, 1768, 2048 }, { 8, 1769, 2048 }, { 8, 1770, 2048 }, { 9, 1771, 2048 }, { 8, 1772, 2048 }, { 9, 1773, 2048 }, { 9, 1774, 2048 }, { 10, 1775, 2048 }, + { 7, 1776, 2048 }, { 8, 1777, 2048 }, { 8, 1778, 2048 }, { 9, 1779, 2048 }, { 8, 1780, 2048 }, { 9, 1781, 2048 }, { 9, 1782, 2048 }, { 10, 1783, 2048 }, + { 8, 1784, 2048 }, { 9, 1785, 2048 }, { 9, 1786, 2048 }, { 10, 1787, 2048 }, { 9, 1788, 2048 }, { 10, 1789, 2048 }, { 10, 1790, 2048 }, { 11, 1791, 2048 }, + { 4, 1792, 2048 }, { 5, 1793, 2048 }, { 5, 1794, 2048 }, { 6, 1795, 2048 }, { 5, 1796, 2048 }, { 6, 1797, 2048 }, { 6, 1798, 2048 }, { 7, 1799, 2048 }, + { 5, 1800, 2048 }, { 6, 1801, 2048 }, { 6, 1802, 2048 }, { 7, 1803, 2048 }, { 6, 1804, 2048 }, { 7, 1805, 2048 }, { 7, 1806, 2048 }, { 8, 1807, 2048 }, + { 5, 1808, 2048 }, { 6, 1809, 2048 }, { 6, 1810, 2048 }, { 7, 1811, 2048 }, { 6, 1812, 2048 }, { 7, 1813, 2048 }, { 7, 1814, 2048 }, { 8, 1815, 2048 }, + { 6, 1816, 2048 }, { 7, 1817, 2048 }, { 7, 1818, 2048 }, { 8, 1819, 2048 }, { 7, 1820, 2048 }, { 8, 1821, 2048 }, { 8, 1822, 2048 }, { 9, 1823, 2048 }, + { 5, 1824, 2048 }, { 6, 1825, 2048 }, { 6, 1826, 2048 }, { 7, 1827, 2048 }, { 6, 1828, 2048 }, { 7, 1829, 2048 }, { 7, 1830, 2048 }, { 8, 1831, 2048 }, + { 6, 1832, 2048 }, { 7, 1833, 2048 }, { 7, 1834, 2048 }, { 8, 1835, 2048 }, { 7, 1836, 2048 }, { 8, 1837, 2048 }, { 8, 1838, 2048 }, { 9, 1839, 2048 }, + { 6, 1840, 2048 }, { 7, 1841, 2048 }, { 7, 1842, 2048 }, { 8, 1843, 2048 }, { 7, 1844, 2048 }, { 8, 1845, 2048 }, { 8, 1846, 2048 }, { 9, 1847, 2048 }, + { 7, 1848, 2048 }, { 8, 1849, 2048 }, { 8, 1850, 2048 }, { 9, 1851, 2048 }, { 8, 1852, 2048 }, { 9, 1853, 2048 }, { 9, 1854, 2048 }, { 10, 1855, 2048 }, + { 5, 1856, 2048 }, { 6, 1857, 2048 }, { 6, 1858, 2048 }, { 7, 1859, 2048 }, { 6, 1860, 2048 }, { 7, 1861, 2048 }, { 7, 1862, 2048 }, { 8, 1863, 2048 }, + { 6, 1864, 2048 }, { 7, 1865, 2048 }, { 7, 1866, 2048 }, { 8, 1867, 2048 }, { 7, 1868, 2048 }, { 8, 1869, 2048 }, { 8, 1870, 2048 }, { 9, 1871, 2048 }, + { 6, 1872, 2048 }, { 7, 1873, 2048 }, { 7, 1874, 2048 }, { 8, 1875, 2048 }, { 7, 1876, 2048 }, { 8, 1877, 2048 }, { 8, 1878, 2048 }, { 9, 1879, 2048 }, + { 7, 1880, 2048 }, { 8, 1881, 2048 }, { 8, 1882, 2048 }, { 9, 1883, 2048 }, { 8, 1884, 2048 }, { 9, 1885, 2048 }, { 9, 1886, 2048 }, { 10, 1887, 2048 }, + { 6, 1888, 2048 }, { 7, 1889, 2048 }, { 7, 1890, 2048 }, { 8, 1891, 2048 }, { 7, 1892, 2048 }, { 8, 1893, 2048 }, { 8, 1894, 2048 }, { 9, 1895, 2048 }, + { 7, 1896, 2048 }, { 8, 1897, 2048 }, { 8, 1898, 2048 }, { 9, 1899, 2048 }, { 8, 1900, 2048 }, { 9, 1901, 2048 }, { 9, 1902, 2048 }, { 10, 1903, 2048 }, + { 7, 1904, 2048 }, { 8, 1905, 2048 }, { 8, 1906, 2048 }, { 9, 1907, 2048 }, { 8, 1908, 2048 }, { 9, 1909, 2048 }, { 9, 1910, 2048 }, { 10, 1911, 2048 }, + { 8, 1912, 2048 }, { 9, 1913, 2048 }, { 9, 1914, 2048 }, { 10, 1915, 2048 }, { 9, 1916, 2048 }, { 10, 1917, 2048 }, { 10, 1918, 2048 }, { 11, 1919, 2048 }, + { 5, 1920, 2048 }, { 6, 1921, 2048 }, { 6, 1922, 2048 }, { 7, 1923, 2048 }, { 6, 1924, 2048 }, { 7, 1925, 2048 }, { 7, 1926, 2048 }, { 8, 1927, 2048 }, + { 6, 1928, 2048 }, { 7, 1929, 2048 }, { 7, 1930, 2048 }, { 8, 1931, 2048 }, { 7, 1932, 2048 }, { 8, 1933, 2048 }, { 8, 1934, 2048 }, { 9, 1935, 2048 }, + { 6, 1936, 2048 }, { 7, 1937, 2048 }, { 7, 1938, 2048 }, { 8, 1939, 2048 }, { 7, 1940, 2048 }, { 8, 1941, 2048 }, { 8, 1942, 2048 }, { 9, 1943, 2048 }, + { 7, 1944, 2048 }, { 8, 1945, 2048 }, { 8, 1946, 2048 }, { 9, 1947, 2048 }, { 8, 1948, 2048 }, { 9, 1949, 2048 }, { 9, 1950, 2048 }, { 10, 1951, 2048 }, + { 6, 1952, 2048 }, { 7, 1953, 2048 }, { 7, 1954, 2048 }, { 8, 1955, 2048 }, { 7, 1956, 2048 }, { 8, 1957, 2048 }, { 8, 1958, 2048 }, { 9, 1959, 2048 }, + { 7, 1960, 2048 }, { 8, 1961, 2048 }, { 8, 1962, 2048 }, { 9, 1963, 2048 }, { 8, 1964, 2048 }, { 9, 1965, 2048 }, { 9, 1966, 2048 }, { 10, 1967, 2048 }, + { 7, 1968, 2048 }, { 8, 1969, 2048 }, { 8, 1970, 2048 }, { 9, 1971, 2048 }, { 8, 1972, 2048 }, { 9, 1973, 2048 }, { 9, 1974, 2048 }, { 10, 1975, 2048 }, + { 8, 1976, 2048 }, { 9, 1977, 2048 }, { 9, 1978, 2048 }, { 10, 1979, 2048 }, { 9, 1980, 2048 }, { 10, 1981, 2048 }, { 10, 1982, 2048 }, { 11, 1983, 2048 }, + { 6, 1984, 2048 }, { 7, 1985, 2048 }, { 7, 1986, 2048 }, { 8, 1987, 2048 }, { 7, 1988, 2048 }, { 8, 1989, 2048 }, { 8, 1990, 2048 }, { 9, 1991, 2048 }, + { 7, 1992, 2048 }, { 8, 1993, 2048 }, { 8, 1994, 2048 }, { 9, 1995, 2048 }, { 8, 1996, 2048 }, { 9, 1997, 2048 }, { 9, 1998, 2048 }, { 10, 1999, 2048 }, + { 7, 2000, 2048 }, { 8, 2001, 2048 }, { 8, 2002, 2048 }, { 9, 2003, 2048 }, { 8, 2004, 2048 }, { 9, 2005, 2048 }, { 9, 2006, 2048 }, { 10, 2007, 2048 }, + { 8, 2008, 2048 }, { 9, 2009, 2048 }, { 9, 2010, 2048 }, { 10, 2011, 2048 }, { 9, 2012, 2048 }, { 10, 2013, 2048 }, { 10, 2014, 2048 }, { 11, 2015, 2048 }, + { 7, 2016, 2048 }, { 8, 2017, 2048 }, { 8, 2018, 2048 }, { 9, 2019, 2048 }, { 8, 2020, 2048 }, { 9, 2021, 2048 }, { 9, 2022, 2048 }, { 10, 2023, 2048 }, + { 8, 2024, 2048 }, { 9, 2025, 2048 }, { 9, 2026, 2048 }, { 10, 2027, 2048 }, { 9, 2028, 2048 }, { 10, 2029, 2048 }, { 10, 2030, 2048 }, { 11, 2031, 2048 }, + { 8, 2032, 2048 }, { 9, 2033, 2048 }, { 9, 2034, 2048 }, { 10, 2035, 2048 }, { 9, 2036, 2048 }, { 10, 2037, 2048 }, { 10, 2038, 2048 }, { 11, 2039, 2048 }, + { 9, 2040, 2048 }, { 10, 2041, 2048 }, { 10, 2042, 2048 }, { 11, 2043, 2048 }, { 10, 2044, 2048 }, { 11, 2045, 2048 }, { 11, 2046, 2048 }, { 12, 2047, 2048 }, +#endif +#endif +#endif +#endif +#endif +#endif +}; + +/* find a hole and free as required, return -1 if no hole found */ +static int find_hole(void) +{ + unsigned x; + int y, z; + for (z = -1, y = INT_MAX, x = 0; x < FP_ENTRIES; x++) { + if (fp_cache[x].lru_count < y && fp_cache[x].lock == 0) { + z = x; + y = fp_cache[x].lru_count; + } + } + + /* decrease all */ + for (x = 0; x < FP_ENTRIES; x++) { + if (fp_cache[x].lru_count > 3) { + --(fp_cache[x].lru_count); + } + } + + /* free entry z */ + if (z >= 0 && fp_cache[z].g) { + mp_clear(&fp_cache[z].mu); + ecc_del_point(fp_cache[z].g); + fp_cache[z].g = NULL; + for (x = 0; x < (1U<x, &g->x) == MP_EQ && + mp_cmp(&fp_cache[x].g->y, &g->y) == MP_EQ && + mp_cmp(&fp_cache[x].g->z, &g->z) == MP_EQ) { + break; + } + } + if (x == FP_ENTRIES) { + x = -1; + } + return x; +} + +/* add a new base to the cache */ +static int add_entry(int idx, ecc_point *g) +{ + unsigned x, y; + + /* allocate base and LUT */ + fp_cache[idx].g = ecc_new_point(); + if (fp_cache[idx].g == NULL) { + return GEN_MEM_ERR; + } + + /* copy x and y */ + if ((mp_copy(&g->x, &fp_cache[idx].g->x) != MP_OKAY) || + (mp_copy(&g->y, &fp_cache[idx].g->y) != MP_OKAY) || + (mp_copy(&g->z, &fp_cache[idx].g->z) != MP_OKAY)) { + ecc_del_point(fp_cache[idx].g); + fp_cache[idx].g = NULL; + return GEN_MEM_ERR; + } + + for (x = 0; x < (1U<x, mu, modulus, + &fp_cache[idx].LUT[1]->x) != MP_OKAY) || + (mp_mulmod(&fp_cache[idx].g->y, mu, modulus, + &fp_cache[idx].LUT[1]->y) != MP_OKAY) || + (mp_mulmod(&fp_cache[idx].g->z, mu, modulus, + &fp_cache[idx].LUT[1]->z) != MP_OKAY)) { + err = MP_MULMOD_E; + } + } + + /* make all single bit entries */ + for (x = 1; x < FP_LUT; x++) { + if (err != MP_OKAY) + break; + if ((mp_copy(&fp_cache[idx].LUT[1<<(x-1)]->x, + &fp_cache[idx].LUT[1<x) != MP_OKAY) || + (mp_copy(&fp_cache[idx].LUT[1<<(x-1)]->y, + &fp_cache[idx].LUT[1<y) != MP_OKAY) || + (mp_copy(&fp_cache[idx].LUT[1<<(x-1)]->z, + &fp_cache[idx].LUT[1<z) != MP_OKAY)){ + err = MP_INIT_E; + break; + } else { + + /* now double it bitlen/FP_LUT times */ + for (y = 0; y < lut_gap; y++) { + if ((err = ecc_projective_dbl_point(fp_cache[idx].LUT[1<z, modulus, *mp); + + /* invert it */ + if (err == MP_OKAY) + err = mp_invmod(&fp_cache[idx].LUT[x]->z, modulus, + &fp_cache[idx].LUT[x]->z); + + if (err == MP_OKAY) + /* now square it */ + err = mp_sqrmod(&fp_cache[idx].LUT[x]->z, modulus, &tmp); + + if (err == MP_OKAY) + /* fix x */ + err = mp_mulmod(&fp_cache[idx].LUT[x]->x, &tmp, modulus, + &fp_cache[idx].LUT[x]->x); + + if (err == MP_OKAY) + /* get 1/z^3 */ + err = mp_mulmod(&tmp, &fp_cache[idx].LUT[x]->z, modulus, &tmp); + + if (err == MP_OKAY) + /* fix y */ + err = mp_mulmod(&fp_cache[idx].LUT[x]->y, &tmp, modulus, + &fp_cache[idx].LUT[x]->y); + + if (err == MP_OKAY) + /* free z */ + mp_clear(&fp_cache[idx].LUT[x]->z); + } + mp_clear(&tmp); + + if (err == MP_OKAY) + return MP_OKAY; + + /* err cleanup */ + for (y = 0; y < (1U< mp_unsigned_bin_size(modulus)) { + mp_int order; + if (mp_init(&order) != MP_OKAY) { + mp_clear(&tk); + return MP_INIT_E; + } + + /* find order */ + y = mp_unsigned_bin_size(modulus); + for (x = 0; ecc_sets[x].size; x++) { + if (y <= (unsigned)ecc_sets[x].size) break; + } + + /* back off if we are on the 521 bit curve */ + if (y == 66) --x; + + if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) { + mp_clear(&order); + mp_clear(&tk); + return err; + } + + /* k must be less than modulus */ + if (mp_cmp(k, &order) != MP_LT) { + if ((err = mp_mod(k, &order, &tk)) != MP_OKAY) { + mp_clear(&tk); + mp_clear(&order); + return err; + } + } else { + mp_copy(k, &tk); + } + mp_clear(&order); + } else { + mp_copy(k, &tk); + } + + /* get bitlen and round up to next multiple of FP_LUT */ + bitlen = mp_unsigned_bin_size(modulus) << 3; + x = bitlen % FP_LUT; + if (x) { + bitlen += FP_LUT - x; + } + lut_gap = bitlen / FP_LUT; + + /* get the k value */ + if (mp_unsigned_bin_size(&tk) > (int)(KB_SIZE - 2)) { + mp_clear(&tk); + return BUFFER_E; + } + + /* store k */ +#ifdef CYASSL_SMALL_STACK + kb = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (kb == NULL) + return MEMORY_E; +#endif + + XMEMSET(kb, 0, KB_SIZE); + if ((err = mp_to_unsigned_bin(&tk, kb)) != MP_OKAY) { + mp_clear(&tk); + } + else { + /* let's reverse kb so it's little endian */ + x = 0; + y = mp_unsigned_bin_size(&tk) - 1; + mp_clear(&tk); + + while ((unsigned)x < y) { + z = kb[x]; kb[x] = kb[y]; kb[y] = z; + ++x; --y; + } + + /* at this point we can start, yipee */ + first = 1; + for (x = lut_gap-1; x >= 0; x--) { + /* extract FP_LUT bits from kb spread out by lut_gap bits and offset + by x bits from the start */ + bitpos = x; + for (y = z = 0; y < FP_LUT; y++) { + z |= ((kb[bitpos>>3] >> (bitpos&7)) & 1) << y; + bitpos += lut_gap; /* it's y*lut_gap + x, but here we can avoid + the mult in each loop */ + } + + /* double if not first */ + if (!first) { + if ((err = ecc_projective_dbl_point(R, R, modulus, + mp)) != MP_OKAY) { + break; + } + } + + /* add if not first, otherwise copy */ + if (!first && z) { + if ((err = ecc_projective_add_point(R, fp_cache[idx].LUT[z], R, + modulus, mp)) != MP_OKAY) { + break; + } + } else if (z) { + if ((mp_copy(&fp_cache[idx].LUT[z]->x, &R->x) != MP_OKAY) || + (mp_copy(&fp_cache[idx].LUT[z]->y, &R->y) != MP_OKAY) || + (mp_copy(&fp_cache[idx].mu, &R->z) != MP_OKAY)) { + err = GEN_MEM_ERR; + break; + } + first = 0; + } + } + } + + if (err == MP_OKAY) { + z = 0; + XMEMSET(kb, 0, KB_SIZE); + /* map R back from projective space */ + if (map) { + err = ecc_map(R, modulus, mp); + } else { + err = MP_OKAY; + } + } + +#ifdef CYASSL_SMALL_STACK + XFREE(kb, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + +#undef KB_SIZE + + return err; +} + +#ifdef ECC_SHAMIR +/* perform a fixed point ECC mulmod */ +static int accel_fp_mul2add(int idx1, int idx2, + mp_int* kA, mp_int* kB, + ecc_point *R, mp_int* modulus, mp_digit* mp) +{ +#define KB_SIZE 128 + +#ifdef CYASSL_SMALL_STACK + unsigned char* kb[2]; +#else + unsigned char kb[2][128]; +#endif + int x; + unsigned y, z, err, bitlen, bitpos, lut_gap, first, zA, zB; + mp_int tka; + mp_int tkb; + mp_int order; + + if (mp_init_multi(&tka, &tkb, 0, 0, 0, 0) != MP_OKAY) + return MP_INIT_E; + + /* if it's smaller than modulus we fine */ + if (mp_unsigned_bin_size(kA) > mp_unsigned_bin_size(modulus)) { + /* find order */ + y = mp_unsigned_bin_size(modulus); + for (x = 0; ecc_sets[x].size; x++) { + if (y <= (unsigned)ecc_sets[x].size) break; + } + + /* back off if we are on the 521 bit curve */ + if (y == 66) --x; + + if ((err = mp_init(&order)) != MP_OKAY) { + mp_clear(&tkb); + mp_clear(&tka); + return err; + } + if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) { + mp_clear(&tkb); + mp_clear(&tka); + mp_clear(&order); + return err; + } + + /* kA must be less than modulus */ + if (mp_cmp(kA, &order) != MP_LT) { + if ((err = mp_mod(kA, &order, &tka)) != MP_OKAY) { + mp_clear(&tkb); + mp_clear(&tka); + mp_clear(&order); + return err; + } + } else { + mp_copy(kA, &tka); + } + mp_clear(&order); + } else { + mp_copy(kA, &tka); + } + + /* if it's smaller than modulus we fine */ + if (mp_unsigned_bin_size(kB) > mp_unsigned_bin_size(modulus)) { + /* find order */ + y = mp_unsigned_bin_size(modulus); + for (x = 0; ecc_sets[x].size; x++) { + if (y <= (unsigned)ecc_sets[x].size) break; + } + + /* back off if we are on the 521 bit curve */ + if (y == 66) --x; + + if ((err = mp_init(&order)) != MP_OKAY) { + mp_clear(&tkb); + mp_clear(&tka); + return err; + } + if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) { + mp_clear(&tkb); + mp_clear(&tka); + mp_clear(&order); + return err; + } + + /* kB must be less than modulus */ + if (mp_cmp(kB, &order) != MP_LT) { + if ((err = mp_mod(kB, &order, &tkb)) != MP_OKAY) { + mp_clear(&tkb); + mp_clear(&tka); + mp_clear(&order); + return err; + } + } else { + mp_copy(kB, &tkb); + } + mp_clear(&order); + } else { + mp_copy(kB, &tkb); + } + + /* get bitlen and round up to next multiple of FP_LUT */ + bitlen = mp_unsigned_bin_size(modulus) << 3; + x = bitlen % FP_LUT; + if (x) { + bitlen += FP_LUT - x; + } + lut_gap = bitlen / FP_LUT; + + /* get the k value */ + if ((mp_unsigned_bin_size(&tka) > (int)(KB_SIZE - 2)) || + (mp_unsigned_bin_size(&tkb) > (int)(KB_SIZE - 2)) ) { + mp_clear(&tka); + mp_clear(&tkb); + return BUFFER_E; + } + + /* store k */ +#ifdef CYASSL_SMALL_STACK + kb[0] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (kb[0] == NULL) + return MEMORY_E; +#endif + + XMEMSET(kb[0], 0, KB_SIZE); + if ((err = mp_to_unsigned_bin(&tka, kb[0])) != MP_OKAY) { + mp_clear(&tka); + mp_clear(&tkb); + XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER); + return err; + } + + /* let's reverse kb so it's little endian */ + x = 0; + y = mp_unsigned_bin_size(&tka) - 1; + mp_clear(&tka); + while ((unsigned)x < y) { + z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z; + ++x; --y; + } + + /* store b */ +#ifdef CYASSL_SMALL_STACK + kb[1] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (kb[1] == NULL) { + XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + XMEMSET(kb[1], 0, KB_SIZE); + if ((err = mp_to_unsigned_bin(&tkb, kb[1])) != MP_OKAY) { + mp_clear(&tkb); + } + else { + x = 0; + y = mp_unsigned_bin_size(&tkb) - 1; + mp_clear(&tkb); + while ((unsigned)x < y) { + z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z; + ++x; --y; + } + + /* at this point we can start, yipee */ + first = 1; + for (x = lut_gap-1; x >= 0; x--) { + /* extract FP_LUT bits from kb spread out by lut_gap bits and + offset by x bits from the start */ + bitpos = x; + for (y = zA = zB = 0; y < FP_LUT; y++) { + zA |= ((kb[0][bitpos>>3] >> (bitpos&7)) & 1) << y; + zB |= ((kb[1][bitpos>>3] >> (bitpos&7)) & 1) << y; + bitpos += lut_gap; /* it's y*lut_gap + x, but here we can avoid + the mult in each loop */ + } + + /* double if not first */ + if (!first) { + if ((err = ecc_projective_dbl_point(R, R, modulus, + mp)) != MP_OKAY) { + break; + } + } + + /* add if not first, otherwise copy */ + if (!first) { + if (zA) { + if ((err = ecc_projective_add_point(R, fp_cache[idx1].LUT[zA], + R, modulus, mp)) != MP_OKAY) { + break; + } + } + if (zB) { + if ((err = ecc_projective_add_point(R, fp_cache[idx2].LUT[zB], + R, modulus, mp)) != MP_OKAY) { + break; + } + } + } else { + if (zA) { + if ((mp_copy(&fp_cache[idx1].LUT[zA]->x, &R->x) != MP_OKAY) || + (mp_copy(&fp_cache[idx1].LUT[zA]->y, &R->y) != MP_OKAY) || + (mp_copy(&fp_cache[idx1].mu, &R->z) != MP_OKAY)) { + err = GEN_MEM_ERR; + break; + } + first = 0; + } + if (zB && first == 0) { + if (zB) { + if ((err = ecc_projective_add_point(R, + fp_cache[idx2].LUT[zB], R, modulus, mp)) != MP_OKAY){ + break; + } + } + } else if (zB && first == 1) { + if ((mp_copy(&fp_cache[idx2].LUT[zB]->x, &R->x) != MP_OKAY) || + (mp_copy(&fp_cache[idx2].LUT[zB]->y, &R->y) != MP_OKAY) || + (mp_copy(&fp_cache[idx2].mu, &R->z) != MP_OKAY)) { + err = GEN_MEM_ERR; + break; + } + first = 0; + } + } + } + } + + XMEMSET(kb[0], 0, KB_SIZE); + XMEMSET(kb[1], 0, KB_SIZE); + +#ifdef CYASSL_SMALL_STACK + XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(kb[1], NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + +#undef KB_SIZE + + return ecc_map(R, modulus, mp); +} + +/** ECC Fixed Point mulmod global + Computes kA*A + kB*B = C using Shamir's Trick + A First point to multiply + kA What to multiple A by + B Second point to multiply + kB What to multiple B by + C [out] Destination point (can overlap with A or B) + modulus Modulus for curve + return MP_OKAY on success +*/ +int ecc_mul2add(ecc_point* A, mp_int* kA, + ecc_point* B, mp_int* kB, + ecc_point* C, mp_int* modulus) +{ + int idx1 = -1, idx2 = -1, err = MP_OKAY, mpInit = 0; + mp_digit mp; + mp_int mu; + + err = mp_init(&mu); + if (err != MP_OKAY) + return err; + +#ifndef HAVE_THREAD_LS + if (initMutex == 0) { + InitMutex(&ecc_fp_lock); + initMutex = 1; + } + if (LockMutex(&ecc_fp_lock) != 0) + return BAD_MUTEX_E; +#endif /* HAVE_THREAD_LS */ + + /* find point */ + idx1 = find_base(A); + + /* no entry? */ + if (idx1 == -1) { + /* find hole and add it */ + if ((idx1 = find_hole()) >= 0) { + err = add_entry(idx1, A); + } + } + if (err == MP_OKAY && idx1 != -1) { + /* increment LRU */ + ++(fp_cache[idx1].lru_count); + } + + if (err == MP_OKAY) + /* find point */ + idx2 = find_base(B); + + if (err == MP_OKAY) { + /* no entry? */ + if (idx2 == -1) { + /* find hole and add it */ + if ((idx2 = find_hole()) >= 0) + err = add_entry(idx2, B); + } + } + + if (err == MP_OKAY && idx2 != -1) { + /* increment LRU */ + ++(fp_cache[idx2].lru_count); + } + + if (err == MP_OKAY) { + /* if it's 2 build the LUT, if it's higher just use the LUT */ + if (idx1 >= 0 && fp_cache[idx1].lru_count == 2) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + + if (err == MP_OKAY) { + mpInit = 1; + err = mp_montgomery_calc_normalization(&mu, modulus); + } + + if (err == MP_OKAY) + /* build the LUT */ + err = build_lut(idx1, modulus, &mp, &mu); + } + } + + if (err == MP_OKAY) { + /* if it's 2 build the LUT, if it's higher just use the LUT */ + if (idx2 >= 0 && fp_cache[idx2].lru_count == 2) { + if (mpInit == 0) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + if (err == MP_OKAY) { + mpInit = 1; + err = mp_montgomery_calc_normalization(&mu, modulus); + } + } + + if (err == MP_OKAY) + /* build the LUT */ + err = build_lut(idx2, modulus, &mp, &mu); + } + } + + + if (err == MP_OKAY) { + if (idx1 >=0 && idx2 >= 0 && fp_cache[idx1].lru_count >= 2 && + fp_cache[idx2].lru_count >= 2) { + if (mpInit == 0) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + } + if (err == MP_OKAY) + err = accel_fp_mul2add(idx1, idx2, kA, kB, C, modulus, &mp); + } else { + err = normal_ecc_mul2add(A, kA, B, kB, C, modulus); + } + } + +#ifndef HAVE_THREAD_LS + UnLockMutex(&ecc_fp_lock); +#endif /* HAVE_THREAD_LS */ + mp_clear(&mu); + + return err; +} +#endif + +/** ECC Fixed Point mulmod global + k The multiplicand + G Base point to multiply + R [out] Destination of product + modulus The modulus for the curve + map [boolean] If non-zero maps the point back to affine co-ordinates, + otherwise it's left in jacobian-montgomery form + return MP_OKAY if successful +*/ +int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, + int map) +{ + int idx, err = MP_OKAY; + mp_digit mp; + mp_int mu; + int mpSetup = 0; + + if (mp_init(&mu) != MP_OKAY) + return MP_INIT_E; + +#ifndef HAVE_THREAD_LS + if (initMutex == 0) { + InitMutex(&ecc_fp_lock); + initMutex = 1; + } + + if (LockMutex(&ecc_fp_lock) != 0) + return BAD_MUTEX_E; +#endif /* HAVE_THREAD_LS */ + + /* find point */ + idx = find_base(G); + + /* no entry? */ + if (idx == -1) { + /* find hole and add it */ + idx = find_hole(); + + if (idx >= 0) + err = add_entry(idx, G); + } + if (err == MP_OKAY && idx != -1) { + /* increment LRU */ + ++(fp_cache[idx].lru_count); + } + + + if (err == MP_OKAY) { + /* if it's 2 build the LUT, if it's higher just use the LUT */ + if (idx >= 0 && fp_cache[idx].lru_count == 2) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + + if (err == MP_OKAY) { + /* compute mu */ + mpSetup = 1; + err = mp_montgomery_calc_normalization(&mu, modulus); + } + + if (err == MP_OKAY) + /* build the LUT */ + err = build_lut(idx, modulus, &mp, &mu); + } + } + + if (err == MP_OKAY) { + if (idx >= 0 && fp_cache[idx].lru_count >= 2) { + if (mpSetup == 0) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + } + if (err == MP_OKAY) + err = accel_fp_mul(idx, k, R, modulus, &mp, map); + } else { + err = normal_ecc_mulmod(k, G, R, modulus, map); + } + } + +#ifndef HAVE_THREAD_LS + UnLockMutex(&ecc_fp_lock); +#endif /* HAVE_THREAD_LS */ + mp_clear(&mu); + + return err; +} + +/* helper function for freeing the cache ... + must be called with the cache mutex locked */ +static void wc_ecc_fp_free_cache(void) +{ + unsigned x, y; + for (x = 0; x < FP_ENTRIES; x++) { + if (fp_cache[x].g != NULL) { + for (y = 0; y < (1U<protocol == 0) + return NULL; + + if (ctx->protocol == REQ_RESP_CLIENT) { + if (ctx->cliSt == ecCLI_INIT) { + ctx->cliSt = ecCLI_SALT_GET; + return ctx->clientSalt; + } + else { + ctx->cliSt = ecCLI_BAD_STATE; + return NULL; + } + } + else if (ctx->protocol == REQ_RESP_SERVER) { + if (ctx->srvSt == ecSRV_INIT) { + ctx->srvSt = ecSRV_SALT_GET; + return ctx->serverSalt; + } + else { + ctx->srvSt = ecSRV_BAD_STATE; + return NULL; + } + } + + return NULL; +} + + +/* optional set info, can be called before or after set_peer_salt */ +int wc_ecc_ctx_set_info(ecEncCtx* ctx, const byte* info, int sz) +{ + if (ctx == NULL || info == 0 || sz < 0) + return BAD_FUNC_ARG; + + ctx->kdfInfo = info; + ctx->kdfInfoSz = sz; + + return 0; +} + + +static const char* exchange_info = "Secure Message Exchange"; + +int wc_ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt) +{ + byte tmp[EXCHANGE_SALT_SZ/2]; + int halfSz = EXCHANGE_SALT_SZ/2; + + if (ctx == NULL || ctx->protocol == 0 || salt == NULL) + return BAD_FUNC_ARG; + + if (ctx->protocol == REQ_RESP_CLIENT) { + XMEMCPY(ctx->serverSalt, salt, EXCHANGE_SALT_SZ); + if (ctx->cliSt == ecCLI_SALT_GET) + ctx->cliSt = ecCLI_SALT_SET; + else { + ctx->cliSt = ecCLI_BAD_STATE; + return BAD_ENC_STATE_E; + } + } + else { + XMEMCPY(ctx->clientSalt, salt, EXCHANGE_SALT_SZ); + if (ctx->srvSt == ecSRV_SALT_GET) + ctx->srvSt = ecSRV_SALT_SET; + else { + ctx->srvSt = ecSRV_BAD_STATE; + return BAD_ENC_STATE_E; + } + } + + /* mix half and half */ + /* tmp stores 2nd half of client before overwrite */ + XMEMCPY(tmp, ctx->clientSalt + halfSz, halfSz); + XMEMCPY(ctx->clientSalt + halfSz, ctx->serverSalt, halfSz); + XMEMCPY(ctx->serverSalt, tmp, halfSz); + + ctx->kdfSalt = ctx->clientSalt; + ctx->kdfSaltSz = EXCHANGE_SALT_SZ; + + ctx->macSalt = ctx->serverSalt; + ctx->macSaltSz = EXCHANGE_SALT_SZ; + + if (ctx->kdfInfo == NULL) { + /* default info */ + ctx->kdfInfo = (const byte*)exchange_info; + ctx->kdfInfoSz = EXCHANGE_INFO_SZ; + } + + return 0; +} + + +static int ecc_ctx_set_salt(ecEncCtx* ctx, int flags, RNG* rng) +{ + byte* saltBuffer = NULL; + + if (ctx == NULL || rng == NULL || flags == 0) + return BAD_FUNC_ARG; + + saltBuffer = (flags == REQ_RESP_CLIENT) ? ctx->clientSalt : ctx->serverSalt; + + return RNG_GenerateBlock(rng, saltBuffer, EXCHANGE_SALT_SZ); +} + + +static void ecc_ctx_init(ecEncCtx* ctx, int flags) +{ + if (ctx) { + XMEMSET(ctx, 0, sizeof(ecEncCtx)); + + ctx->encAlgo = ecAES_128_CBC; + ctx->kdfAlgo = ecHKDF_SHA256; + ctx->macAlgo = ecHMAC_SHA256; + ctx->protocol = (byte)flags; + + if (flags == REQ_RESP_CLIENT) + ctx->cliSt = ecCLI_INIT; + if (flags == REQ_RESP_SERVER) + ctx->srvSt = ecSRV_INIT; + } +} + + +/* allow ecc context reset so user doesn't have to init/free for resue */ +int wc_ecc_ctx_reset(ecEncCtx* ctx, RNG* rng) +{ + if (ctx == NULL || rng == NULL) + return BAD_FUNC_ARG; + + ecc_ctx_init(ctx, ctx->protocol); + return ecc_ctx_set_salt(ctx, ctx->protocol, rng); +} + + +/* alloc/init and set defaults, return new Context */ +ecEncCtx* wc_ecc_ctx_new(int flags, RNG* rng) +{ + int ret = 0; + ecEncCtx* ctx = (ecEncCtx*)XMALLOC(sizeof(ecEncCtx), 0, DYNAMIC_TYPE_ECC); + + if (ctx) + ctx->protocol = (byte)flags; + + ret = wc_ecc_ctx_reset(ctx, rng); + if (ret != 0) { + wc_ecc_ctx_free(ctx); + ctx = NULL; + } + + return ctx; +} + + +/* free any resources, clear any keys */ +void wc_ecc_ctx_free(ecEncCtx* ctx) +{ + if (ctx) { + XMEMSET(ctx, 0, sizeof(ecEncCtx)); + XFREE(ctx, 0, DYNAMIC_TYPE_ECC); + } +} + + +static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz, + int* keysLen, word32* digestSz, word32* blockSz) +{ + if (ctx) { + switch (ctx->encAlgo) { + case ecAES_128_CBC: + *encKeySz = KEY_SIZE_128; + *ivSz = IV_SIZE_64; + *blockSz = AES_BLOCK_SIZE; + break; + default: + return BAD_FUNC_ARG; + } + + switch (ctx->macAlgo) { + case ecHMAC_SHA256: + *digestSz = SHA256_DIGEST_SIZE; + break; + default: + return BAD_FUNC_ARG; + } + } else + return BAD_FUNC_ARG; + + *keysLen = *encKeySz + *ivSz + *digestSz; + + return 0; +} + + +/* ecc encrypt with shared secret run through kdf + ctx holds non default algos and inputs + msgSz should be the right size for encAlgo, i.e., already padded + return 0 on success */ +int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, + word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx) +{ + int ret; + word32 blockSz; + word32 digestSz; + ecEncCtx localCtx; +#ifdef CYASSL_SMALL_STACK + byte* sharedSecret; + byte* keys; +#else + byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */ + byte keys[ECC_BUFSIZE]; /* max size */ +#endif + word32 sharedSz = ECC_MAXSIZE; + int keysLen; + int encKeySz; + int ivSz; + int offset = 0; /* keys offset if doing msg exchange */ + byte* encKey; + byte* encIv; + byte* macKey; + + if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL || + outSz == NULL) + return BAD_FUNC_ARG; + + if (ctx == NULL) { /* use defaults */ + ecc_ctx_init(&localCtx, 0); + ctx = &localCtx; + } + + ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz, + &blockSz); + if (ret != 0) + return ret; + + if (ctx->protocol == REQ_RESP_SERVER) { + offset = keysLen; + keysLen *= 2; + + if (ctx->srvSt != ecSRV_RECV_REQ) + return BAD_ENC_STATE_E; + + ctx->srvSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */ + } + else if (ctx->protocol == REQ_RESP_CLIENT) { + if (ctx->cliSt != ecCLI_SALT_SET) + return BAD_ENC_STATE_E; + + ctx->cliSt = ecCLI_SENT_REQ; /* only do this once */ + } + + if (keysLen > ECC_BUFSIZE) /* keys size */ + return BUFFER_E; + + if ( (msgSz%blockSz) != 0) + return BAD_PADDING_E; + + if (*outSz < (msgSz + digestSz)) + return BUFFER_E; + +#ifdef CYASSL_SMALL_STACK + sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sharedSecret == NULL) + return MEMORY_E; + + keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (keys == NULL) { + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); + + if (ret == 0) { + switch (ctx->kdfAlgo) { + case ecHKDF_SHA256 : + ret = HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt, + ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz, + keys, keysLen); + break; + + default: + ret = BAD_FUNC_ARG; + break; + } + } + + if (ret == 0) { + encKey = keys + offset; + encIv = encKey + encKeySz; + macKey = encKey + encKeySz + ivSz; + + switch (ctx->encAlgo) { + case ecAES_128_CBC: + { + Aes aes; + ret = AesSetKey(&aes, encKey, KEY_SIZE_128, encIv, + AES_ENCRYPTION); + if (ret != 0) + break; + ret = AesCbcEncrypt(&aes, out, msg, msgSz); + } + break; + + default: + ret = BAD_FUNC_ARG; + break; + } + } + + if (ret == 0) { + switch (ctx->macAlgo) { + case ecHMAC_SHA256: + { + Hmac hmac; + ret = HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE); + if (ret != 0) + break; + ret = HmacUpdate(&hmac, out, msgSz); + if (ret != 0) + break; + ret = HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz); + if (ret != 0) + break; + ret = HmacFinal(&hmac, out+msgSz); + } + break; + + default: + ret = BAD_FUNC_ARG; + break; + } + } + + if (ret == 0) + *outSz = msgSz + digestSz; + +#ifdef CYASSL_SMALL_STACK + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(keys, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +/* ecc decrypt with shared secret run through kdf + ctx holds non default algos and inputs + return 0 on success */ +int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, + word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx) +{ + int ret; + word32 blockSz; + word32 digestSz; + ecEncCtx localCtx; +#ifdef CYASSL_SMALL_STACK + byte* sharedSecret; + byte* keys; +#else + byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */ + byte keys[ECC_BUFSIZE]; /* max size */ +#endif + word32 sharedSz = ECC_MAXSIZE; + int keysLen; + int encKeySz; + int ivSz; + int offset = 0; /* in case using msg exchange */ + byte* encKey; + byte* encIv; + byte* macKey; + + if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL || + outSz == NULL) + return BAD_FUNC_ARG; + + if (ctx == NULL) { /* use defaults */ + ecc_ctx_init(&localCtx, 0); + ctx = &localCtx; + } + + ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz, + &blockSz); + if (ret != 0) + return ret; + + if (ctx->protocol == REQ_RESP_CLIENT) { + offset = keysLen; + keysLen *= 2; + + if (ctx->cliSt != ecCLI_SENT_REQ) + return BAD_ENC_STATE_E; + + ctx->cliSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */ + } + else if (ctx->protocol == REQ_RESP_SERVER) { + if (ctx->srvSt != ecSRV_SALT_SET) + return BAD_ENC_STATE_E; + + ctx->srvSt = ecSRV_RECV_REQ; /* only do this once */ + } + + if (keysLen > ECC_BUFSIZE) /* keys size */ + return BUFFER_E; + + if ( ((msgSz-digestSz) % blockSz) != 0) + return BAD_PADDING_E; + + if (*outSz < (msgSz - digestSz)) + return BUFFER_E; + +#ifdef CYASSL_SMALL_STACK + sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sharedSecret == NULL) + return MEMORY_E; + + keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (keys == NULL) { + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); + + if (ret == 0) { + switch (ctx->kdfAlgo) { + case ecHKDF_SHA256 : + ret = HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt, + ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz, + keys, keysLen); + break; + + default: + ret = BAD_FUNC_ARG; + break; + } + } + + if (ret == 0) { + encKey = keys + offset; + encIv = encKey + encKeySz; + macKey = encKey + encKeySz + ivSz; + + switch (ctx->macAlgo) { + case ecHMAC_SHA256: + { + byte verify[SHA256_DIGEST_SIZE]; + Hmac hmac; + ret = HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE); + if (ret != 0) + break; + ret = HmacUpdate(&hmac, msg, msgSz-digestSz); + if (ret != 0) + break; + ret = HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz); + if (ret != 0) + break; + ret = HmacFinal(&hmac, verify); + if (ret != 0) + break; + if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0) + ret = -1; + } + break; + + default: + ret = BAD_FUNC_ARG; + break; + } + } + + if (ret == 0) { + switch (ctx->encAlgo) { + case ecAES_128_CBC: + { + Aes aes; + ret = AesSetKey(&aes, encKey, KEY_SIZE_128, encIv, + AES_DECRYPTION); + if (ret != 0) + break; + ret = AesCbcDecrypt(&aes, out, msg, msgSz-digestSz); + } + break; + + default: + ret = BAD_FUNC_ARG; + break; + } + } + + if (ret == 0) + *outSz = msgSz - digestSz; + +#ifdef CYASSL_SMALL_STACK + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(keys, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +#endif /* HAVE_ECC_ENCRYPT */ + + +#ifdef HAVE_COMP_KEY + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int mp_jacobi(mp_int* a, mp_int* p, int* c) +{ + mp_int a1, p1; + int k, s, r, res; + mp_digit residue; + + /* if p <= 0 return MP_VAL */ + if (mp_cmp_d(p, 0) != MP_GT) { + return MP_VAL; + } + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2**k */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&p1)) != MP_OKAY) { + mp_clear(&a1); + return res; + } + + /* divide out larger power of two */ + k = mp_cnt_lsb(&a1); + res = mp_div_2d(&a1, k, &a1, NULL); + + if (res == MP_OKAY) { + /* step 4. if e is even set s=1 */ + if ((k & 1) == 0) { + s = 1; + } else { + /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ + residue = p->dp[0] & 7; + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + s = -s; + } + } + + if (res == MP_OKAY) { + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + res = mp_mod (p, &a1, &p1); + if (res == MP_OKAY) + res = mp_jacobi (&p1, &a1, &r); + + if (res == MP_OKAY) + *c = s * r; + } + } + + /* done */ + mp_clear (&p1); + mp_clear (&a1); + + return res; +} + + +int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) +{ + int res, legendre, done = 0; + mp_int t1, C, Q, S, Z, M, T, R, two; + mp_digit i; + + /* first handle the simple cases */ + if (mp_cmp_d(n, 0) == MP_EQ) { + mp_zero(ret); + return MP_OKAY; + } + if (mp_cmp_d(prime, 2) == MP_EQ) return MP_VAL; /* prime must be odd */ + /* TAO removed + if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY) return res; + if (legendre == -1) return MP_VAL; */ /* quadratic non-residue mod prime */ + + if ((res = mp_init_multi(&t1, &C, &Q, &S, &Z, &M)) != MP_OKAY) + return res; + + if ((res = mp_init_multi(&T, &R, &two, NULL, NULL, NULL)) + != MP_OKAY) { + mp_clear(&t1); mp_clear(&C); mp_clear(&Q); mp_clear(&S); mp_clear(&Z); + mp_clear(&M); + return res; + } + + /* SPECIAL CASE: if prime mod 4 == 3 + * compute directly: res = n^(prime+1)/4 mod prime + * Handbook of Applied Cryptography algorithm 3.36 + */ + res = mp_mod_d(prime, 4, &i); + if (res == MP_OKAY && i == 3) { + res = mp_add_d(prime, 1, &t1); + + if (res == MP_OKAY) + res = mp_div_2(&t1, &t1); + if (res == MP_OKAY) + res = mp_div_2(&t1, &t1); + if (res == MP_OKAY) + res = mp_exptmod(n, &t1, prime, ret); + + done = 1; + } + + /* NOW: TonelliShanks algorithm */ + + if (res == MP_OKAY && done == 0) { + + /* factor out powers of 2 from prime-1, defining Q and S + * as: prime-1 = Q*2^S */ + res = mp_copy(prime, &Q); + if (res == MP_OKAY) + res = mp_sub_d(&Q, 1, &Q); + /* Q = prime - 1 */ + if (res == MP_OKAY) + mp_zero(&S); + /* S = 0 */ + while (res == MP_OKAY && mp_iseven(&Q)) { + res = mp_div_2(&Q, &Q); + /* Q = Q / 2 */ + if (res == MP_OKAY) + res = mp_add_d(&S, 1, &S); + /* S = S + 1 */ + } + + /* find a Z such that the Legendre symbol (Z|prime) == -1 */ + if (res == MP_OKAY) + res = mp_set_int(&Z, 2); + /* Z = 2 */ + while (res == MP_OKAY) { + res = mp_jacobi(&Z, prime, &legendre); + if (res == MP_OKAY && legendre == -1) + break; + if (res == MP_OKAY) + res = mp_add_d(&Z, 1, &Z); + /* Z = Z + 1 */ + } + + if (res == MP_OKAY) + res = mp_exptmod(&Z, &Q, prime, &C); + /* C = Z ^ Q mod prime */ + if (res == MP_OKAY) + res = mp_add_d(&Q, 1, &t1); + if (res == MP_OKAY) + res = mp_div_2(&t1, &t1); + /* t1 = (Q + 1) / 2 */ + if (res == MP_OKAY) + res = mp_exptmod(n, &t1, prime, &R); + /* R = n ^ ((Q + 1) / 2) mod prime */ + if (res == MP_OKAY) + res = mp_exptmod(n, &Q, prime, &T); + /* T = n ^ Q mod prime */ + if (res == MP_OKAY) + res = mp_copy(&S, &M); + /* M = S */ + if (res == MP_OKAY) + res = mp_set_int(&two, 2); + + while (res == MP_OKAY && done == 0) { + res = mp_copy(&T, &t1); + i = 0; + while (res == MP_OKAY) { + if (mp_cmp_d(&t1, 1) == MP_EQ) + break; + res = mp_exptmod(&t1, &two, prime, &t1); + if (res == MP_OKAY) + i++; + } + if (res == MP_OKAY && i == 0) { + mp_copy(&R, ret); + res = MP_OKAY; + done = 1; + } + + if (done == 0) { + if (res == MP_OKAY) + res = mp_sub_d(&M, i, &t1); + if (res == MP_OKAY) + res = mp_sub_d(&t1, 1, &t1); + if (res == MP_OKAY) + res = mp_exptmod(&two, &t1, prime, &t1); + /* t1 = 2 ^ (M - i - 1) */ + if (res == MP_OKAY) + res = mp_exptmod(&C, &t1, prime, &t1); + /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ + if (res == MP_OKAY) + res = mp_sqrmod(&t1, prime, &C); + /* C = (t1 * t1) mod prime */ + if (res == MP_OKAY) + res = mp_mulmod(&R, &t1, prime, &R); + /* R = (R * t1) mod prime */ + if (res == MP_OKAY) + res = mp_mulmod(&T, &C, prime, &T); + /* T = (T * C) mod prime */ + if (res == MP_OKAY) + mp_set(&M, i); + /* M = i */ + } + } + } + + /* done */ + mp_clear(&t1); + mp_clear(&C); + mp_clear(&Q); + mp_clear(&S); + mp_clear(&Z); + mp_clear(&M); + mp_clear(&T); + mp_clear(&R); + mp_clear(&two); + + return res; +} + + +/* export public ECC key in ANSI X9.63 format compressed */ +int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen) +{ + word32 numlen; + int ret = MP_OKAY; + + if (key == NULL || out == NULL || outLen == NULL) + return ECC_BAD_ARG_E; + + if (ecc_is_valid_idx(key->idx) == 0) { + return ECC_BAD_ARG_E; + } + numlen = key->dp->size; + + if (*outLen < (1 + numlen)) { + *outLen = 1 + numlen; + return BUFFER_E; + } + + /* store first byte */ + out[0] = mp_isodd(&key->pubkey.y) ? 0x03 : 0x02; + + /* pad and store x */ + XMEMSET(out+1, 0, numlen); + ret = mp_to_unsigned_bin(&key->pubkey.x, + out+1 + (numlen - mp_unsigned_bin_size(&key->pubkey.x))); + *outLen = 1 + numlen; + return ret; +} + + +/* d = a - b (mod c) */ +int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + + return res; +} + + +#endif /* HAVE_COMP_KEY */ + +#endif /* HAVE_ECC */ diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c new file mode 100644 index 000000000..84c90e927 --- /dev/null +++ b/wolfcrypt/src/error.c @@ -0,0 +1,325 @@ +/* error.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 +#endif + +#include + +#include + +#ifdef _MSC_VER + /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */ + #pragma warning(disable: 4996) +#endif + +const char* CTaoCryptGetErrorString(int error) +{ +#ifdef NO_ERROR_STRINGS + + (void)error; + return "no support for error strings built in"; + +#else + + switch (error) { + + case OPEN_RAN_E : + return "opening random device error"; + + case READ_RAN_E : + return "reading random device error"; + + case WINCRYPT_E : + return "windows crypt init error"; + + case CRYPTGEN_E : + return "windows crypt generation error"; + + case RAN_BLOCK_E : + return "random device read would block error"; + + case BAD_MUTEX_E : + return "Bad mutex, operation failed"; + + case MP_INIT_E : + return "mp_init error state"; + + case MP_READ_E : + return "mp_read error state"; + + case MP_EXPTMOD_E : + return "mp_exptmod error state"; + + case MP_TO_E : + return "mp_to_xxx error state, can't convert"; + + case MP_SUB_E : + return "mp_sub error state, can't subtract"; + + case MP_ADD_E : + return "mp_add error state, can't add"; + + case MP_MUL_E : + return "mp_mul error state, can't multiply"; + + case MP_MULMOD_E : + return "mp_mulmod error state, can't multiply mod"; + + case MP_MOD_E : + return "mp_mod error state, can't mod"; + + case MP_INVMOD_E : + return "mp_invmod error state, can't inv mod"; + + case MP_CMP_E : + return "mp_cmp error state"; + + case MP_ZERO_E : + return "mp zero result, not expected"; + + case MEMORY_E : + return "out of memory error"; + + case RSA_WRONG_TYPE_E : + return "RSA wrong block type for RSA function"; + + case RSA_BUFFER_E : + return "RSA buffer error, output too small or input too big"; + + case BUFFER_E : + return "Buffer error, output too small or input too big"; + + case ALGO_ID_E : + return "Setting Cert AlogID error"; + + case PUBLIC_KEY_E : + return "Setting Cert Public Key error"; + + case DATE_E : + return "Setting Cert Date validity error"; + + case SUBJECT_E : + return "Setting Cert Subject name error"; + + case ISSUER_E : + return "Setting Cert Issuer name error"; + + case CA_TRUE_E : + return "Setting basic constraint CA true error"; + + case EXTENSIONS_E : + return "Setting extensions error"; + + case ASN_PARSE_E : + return "ASN parsing error, invalid input"; + + case ASN_VERSION_E : + return "ASN version error, invalid number"; + + case ASN_GETINT_E : + return "ASN get big int error, invalid data"; + + case ASN_RSA_KEY_E : + return "ASN key init error, invalid input"; + + case ASN_OBJECT_ID_E : + return "ASN object id error, invalid id"; + + case ASN_TAG_NULL_E : + return "ASN tag error, not null"; + + case ASN_EXPECT_0_E : + return "ASN expect error, not zero"; + + case ASN_BITSTR_E : + return "ASN bit string error, wrong id"; + + case ASN_UNKNOWN_OID_E : + return "ASN oid error, unknown sum id"; + + case ASN_DATE_SZ_E : + return "ASN date error, bad size"; + + case ASN_BEFORE_DATE_E : + return "ASN date error, current date before"; + + case ASN_AFTER_DATE_E : + return "ASN date error, current date after"; + + case ASN_SIG_OID_E : + return "ASN signature error, mismatched oid"; + + case ASN_TIME_E : + return "ASN time error, unkown time type"; + + case ASN_INPUT_E : + return "ASN input error, not enough data"; + + case ASN_SIG_CONFIRM_E : + return "ASN sig error, confirm failure"; + + case ASN_SIG_HASH_E : + return "ASN sig error, unsupported hash type"; + + case ASN_SIG_KEY_E : + return "ASN sig error, unsupported key type"; + + case ASN_DH_KEY_E : + return "ASN key init error, invalid input"; + + case ASN_NTRU_KEY_E : + return "ASN NTRU key decode error, invalid input"; + + case ASN_CRIT_EXT_E: + return "X.509 Critical extension ignored"; + + case ECC_BAD_ARG_E : + return "ECC input argument wrong type, invalid input"; + + case ASN_ECC_KEY_E : + return "ECC ASN1 bad key data, invalid input"; + + case ECC_CURVE_OID_E : + return "ECC curve sum OID unsupported, invalid input"; + + case BAD_FUNC_ARG : + return "Bad function argument"; + + case NOT_COMPILED_IN : + return "Feature not compiled in"; + + case UNICODE_SIZE_E : + return "Unicode password too big"; + + case NO_PASSWORD : + return "No password provided by user"; + + case ALT_NAME_E : + return "Alt Name problem, too big"; + + case AES_GCM_AUTH_E: + return "AES-GCM Authentication check fail"; + + case AES_CCM_AUTH_E: + return "AES-CCM Authentication check fail"; + + case CAVIUM_INIT_E: + return "Cavium Init type error"; + + case COMPRESS_INIT_E: + return "Compress Init error"; + + case COMPRESS_E: + return "Compress error"; + + case DECOMPRESS_INIT_E: + return "DeCompress Init error"; + + case DECOMPRESS_E: + return "DeCompress error"; + + case BAD_ALIGN_E: + return "Bad alignment error, no alloc help"; + + case ASN_NO_SIGNER_E : + return "ASN no signer error to confirm failure"; + + case ASN_CRL_CONFIRM_E : + return "ASN CRL sig error, confirm failure"; + + case ASN_CRL_NO_SIGNER_E : + return "ASN CRL no signer error to confirm failure"; + + case ASN_OCSP_CONFIRM_E : + return "ASN OCSP sig error, confirm failure"; + + case BAD_ENC_STATE_E: + return "Bad ecc encrypt state operation"; + + case BAD_PADDING_E: + return "Bad padding, message wrong length"; + + case REQ_ATTRIBUTE_E: + return "Setting cert request attributes error"; + + case PKCS7_OID_E: + return "PKCS#7 error: mismatched OID value"; + + case PKCS7_RECIP_E: + return "PKCS#7 error: no matching recipient found"; + + case FIPS_NOT_ALLOWED_E: + return "FIPS mode not allowed error"; + + case ASN_NAME_INVALID_E: + return "Name Constraint error"; + + case RNG_FAILURE_E: + return "Random Number Generator failed"; + + case HMAC_MIN_KEYLEN_E: + return "FIPS Mode HMAC Minimum Key Length error"; + + case RSA_PAD_E: + return "Rsa Padding error"; + + case LENGTH_ONLY_E: + return "Output length only set, not for other use error"; + + case IN_CORE_FIPS_E: + return "In Core Integrity check FIPS error"; + + case AES_KAT_FIPS_E: + return "AES Known Answer Test check FIPS error"; + + case DES3_KAT_FIPS_E: + return "DES3 Known Answer Test check FIPS error"; + + case HMAC_KAT_FIPS_E: + return "HMAC Known Answer Test check FIPS error"; + + case RSA_KAT_FIPS_E: + return "RSA Known Answer Test check FIPS error"; + + case DRBG_KAT_FIPS_E: + return "DRBG Known Answer Test check FIPS error"; + + case DRBG_CONT_FIPS_E: + return "DRBG Continuous Test FIPS error"; + + case AESGCM_KAT_FIPS_E: + return "AESGCM Known Answer Test check FIPS error"; + + default: + return "unknown error number"; + + } + +#endif /* NO_ERROR_STRINGS */ + +} + +void CTaoCryptErrorString(int error, char* buffer) +{ + XSTRNCPY(buffer, CTaoCryptGetErrorString(error), CYASSL_MAX_ERROR_SZ); +} diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 0073dd87f..2863d7fde 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -24,10 +24,12 @@ #include #endif -#include +#include #ifndef NO_HMAC +#include + #ifdef __cplusplus extern "C" { #endif @@ -67,7 +69,7 @@ int wc_HmacFinal(Hmac* hmac, byte* out) int wc_wolfSSL_GetHmacMaxSize(void) { - return CyaSSL_GetHmacMaxSize(void); + return CyaSSL_GetHmacMaxSize(); } #ifdef HAVE_HKDF diff --git a/wolfcrypt/src/logging.c b/wolfcrypt/src/logging.c new file mode 100644 index 000000000..5c17f591d --- /dev/null +++ b/wolfcrypt/src/logging.c @@ -0,0 +1,162 @@ +/* logging.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 +#endif + +#include + +/* submitted by eof */ + +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + CYASSL_API int CyaSSL_Debugging_ON(void); + CYASSL_API void CyaSSL_Debugging_OFF(void); +#ifdef __cplusplus + } +#endif + + +#ifdef DEBUG_CYASSL + +/* Set these to default values initially. */ +static CyaSSL_Logging_cb log_function = 0; +static int loggingEnabled = 0; + +#endif /* DEBUG_CYASSL */ + + +int CyaSSL_SetLoggingCb(CyaSSL_Logging_cb f) +{ +#ifdef DEBUG_CYASSL + int res = 0; + + if (f) + log_function = f; + else + res = BAD_FUNC_ARG; + + return res; +#else + (void)f; + return NOT_COMPILED_IN; +#endif +} + + +int CyaSSL_Debugging_ON(void) +{ +#ifdef DEBUG_CYASSL + loggingEnabled = 1; + return 0; +#else + return NOT_COMPILED_IN; +#endif +} + + +void CyaSSL_Debugging_OFF(void) +{ +#ifdef DEBUG_CYASSL + loggingEnabled = 0; +#endif +} + + +#ifdef DEBUG_CYASSL + +#ifdef FREESCALE_MQX + #include +#else + #include /* for default printf stuff */ +#endif + +#ifdef THREADX + int dc_log_printf(char*, ...); +#endif + +static void cyassl_log(const int logLevel, const char *const logMessage) +{ + if (log_function) + log_function(logLevel, logMessage); + else { + if (loggingEnabled) { +#ifdef THREADX + dc_log_printf("%s\n", logMessage); +#elif defined(MICRIUM) + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + NetSecure_TraceOut((CPU_CHAR *)logMessage); + #endif +#elif defined(CYASSL_MDK_ARM) + fflush(stdout) ; + printf("%s\n", logMessage); + fflush(stdout) ; +#else + fprintf(stderr, "%s\n", logMessage); +#endif + } + } +} + + +void CYASSL_MSG(const char* msg) +{ + if (loggingEnabled) + cyassl_log(INFO_LOG , msg); +} + + +void CYASSL_ENTER(const char* msg) +{ + if (loggingEnabled) { + char buffer[80]; + sprintf(buffer, "CyaSSL Entering %s", msg); + cyassl_log(ENTER_LOG , buffer); + } +} + + +void CYASSL_LEAVE(const char* msg, int ret) +{ + if (loggingEnabled) { + char buffer[80]; + sprintf(buffer, "CyaSSL Leaving %s, return %d", msg, ret); + cyassl_log(LEAVE_LOG , buffer); + } +} + + +void CYASSL_ERROR(int error) +{ + if (loggingEnabled) { + char buffer[80]; + sprintf(buffer, "CyaSSL error occured, error = %d", error); + cyassl_log(ERROR_LOG , buffer); + } +} + +#endif /* DEBUG_CYASSL */ diff --git a/wolfcrypt/src/memory.c b/wolfcrypt/src/memory.c new file mode 100644 index 000000000..f477fba59 --- /dev/null +++ b/wolfcrypt/src/memory.c @@ -0,0 +1,183 @@ +/* memory.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 +#endif + +#include + +#ifdef USE_CYASSL_MEMORY + +#include +#include + +#ifdef CYASSL_MALLOC_CHECK + #include +#endif + +/* Set these to default values initially. */ +static wolfSSL_Malloc_cb malloc_function = 0; +static wolfSSL_Free_cb free_function = 0; +static wolfSSL_Realloc_cb realloc_function = 0; + +int wolfSSL_SetAllocators(CyaSSL_Malloc_cb mf, + wolfSSL_Free_cb ff, + wolfSSL_Realloc_cb rf) +{ + int res = 0; + + if (mf) + malloc_function = mf; + else + res = BAD_FUNC_ARG; + + if (ff) + free_function = ff; + else + res = BAD_FUNC_ARG; + + if (rf) + realloc_function = rf; + else + res = BAD_FUNC_ARG; + + return res; +} + + +void* wolfSSL_Malloc(size_t size) +{ + void* res = 0; + + if (malloc_function) + res = malloc_function(size); + else + res = malloc(size); + + #ifdef CYASSL_MALLOC_CHECK + if (res == NULL) + puts("wolfSSL_malloc failed"); + #endif + + return res; +} + +void wolfSSL_Free(void *ptr) +{ + if (free_function) + free_function(ptr); + else + free(ptr); +} + +void* wolfSSL_Realloc(void *ptr, size_t size) +{ + void* res = 0; + + if (realloc_function) + res = realloc_function(ptr, size); + else + res = realloc(ptr, size); + + return res; +} + +#endif /* USE_CYASSL_MEMORY */ + + +#ifdef HAVE_IO_POOL + +/* Example for user io pool, shared build may need definitions in lib proper */ + +#include +#include + +#ifndef HAVE_THREAD_LS + #error "Oops, simple I/O pool example needs thread local storage" +#endif + + +/* allow simple per thread in and out pools */ +/* use 17k size sense max record size is 16k plus overhead */ +static THREAD_LS_T byte pool_in[17*1024]; +static THREAD_LS_T byte pool_out[17*1024]; + + +void* XMALLOC(size_t n, void* heap, int type) +{ + (void)heap; + + if (type == DYNAMIC_TYPE_IN_BUFFER) { + if (n < sizeof(pool_in)) + return pool_in; + else + return NULL; + } + + if (type == DYNAMIC_TYPE_OUT_BUFFER) { + if (n < sizeof(pool_out)) + return pool_out; + else + return NULL; + } + + return malloc(n); +} + +void* XREALLOC(void *p, size_t n, void* heap, int type) +{ + (void)heap; + + if (type == DYNAMIC_TYPE_IN_BUFFER) { + if (n < sizeof(pool_in)) + return pool_in; + else + return NULL; + } + + if (type == DYNAMIC_TYPE_OUT_BUFFER) { + if (n < sizeof(pool_out)) + return pool_out; + else + return NULL; + } + + return realloc(p, n); +} + + +/* unit api calls, let's make sure visisble with CYASSL_API */ +CYASSL_API void XFREE(void *p, void* heap, int type) +{ + (void)heap; + + if (type == DYNAMIC_TYPE_IN_BUFFER) + return; /* do nothing, static pool */ + + if (type == DYNAMIC_TYPE_OUT_BUFFER) + return; /* do nothing, static pool */ + + free(p); +} + +#endif /* HAVE_IO_POOL */ + diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index caf5a6439..5d579a1e2 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -35,7 +35,7 @@ #define FIPS_NO_WRAPPERS #endif -#include +#include #include #ifdef __cplusplus diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index dadec2a6b..fcf79a44a 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -23,10 +23,12 @@ #include #endif -#include +#include #ifndef NO_RSA +#include + #ifdef __cplusplus extern "C" { @@ -66,7 +68,7 @@ int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, - word32 outLen, RsaKey* key, RNG* rng); + word32 outLen, RsaKey* key, RNG* rng) { return RsaSSL_Sign(in, inLen, out, outLen, key, rng); } diff --git a/wolfcrypt/src/sha.c b/wolfcrypt/src/sha.c new file mode 100644 index 000000000..825f8efad --- /dev/null +++ b/wolfcrypt/src/sha.c @@ -0,0 +1,428 @@ +/* sha.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 +#endif + +#include + +#if !defined(NO_SHA) + +#ifdef CYASSL_PIC32MZ_HASH +#define InitSha InitSha_sw +#define ShaUpdate ShaUpdate_sw +#define ShaFinal ShaFinal_sw +#endif + +#ifdef HAVE_FIPS + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #include +#endif + +#ifdef FREESCALE_MMCAU + #include "cau_api.h" + #define XTRANSFORM(S,B) cau_sha1_hash_n((B), 1, ((S))->digest) +#else + #define XTRANSFORM(S,B) Transform((S)) +#endif + + +#ifdef STM32F2_HASH + /* + * STM32F2 hardware SHA1 support through the STM32F2 standard peripheral + * library. Documentation located in STM32F2xx Standard Peripheral Library + * document (See note in README). + */ + #include "stm32f2xx.h" + #include "stm32f2xx_hash.h" + + int InitSha(Sha* sha) + { + /* STM32F2 struct notes: + * sha->buffer = first 4 bytes used to hold partial block if needed + * sha->buffLen = num bytes currently stored in sha->buffer + * sha->loLen = num bytes that have been written to STM32 FIFO + */ + XMEMSET(sha->buffer, 0, SHA_REG_SIZE); + sha->buffLen = 0; + sha->loLen = 0; + + /* initialize HASH peripheral */ + HASH_DeInit(); + + /* configure algo used, algo mode, datatype */ + HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE); + HASH->CR |= (HASH_AlgoSelection_SHA1 | HASH_AlgoMode_HASH + | HASH_DataType_8b); + + /* reset HASH processor */ + HASH->CR |= HASH_CR_INIT; + + return 0; + } + + int ShaUpdate(Sha* sha, const byte* data, word32 len) + { + word32 i = 0; + word32 fill = 0; + word32 diff = 0; + + /* if saved partial block is available */ + if (sha->buffLen) { + fill = 4 - sha->buffLen; + + /* if enough data to fill, fill and push to FIFO */ + if (fill <= len) { + XMEMCPY((byte*)sha->buffer + sha->buffLen, data, fill); + HASH_DataIn(*(uint32_t*)sha->buffer); + + data += fill; + len -= fill; + sha->loLen += 4; + sha->buffLen = 0; + } else { + /* append partial to existing stored block */ + XMEMCPY((byte*)sha->buffer + sha->buffLen, data, len); + sha->buffLen += len; + return; + } + } + + /* write input block in the IN FIFO */ + for(i = 0; i < len; i += 4) + { + diff = len - i; + if ( diff < 4) { + /* store incomplete last block, not yet in FIFO */ + XMEMSET(sha->buffer, 0, SHA_REG_SIZE); + XMEMCPY((byte*)sha->buffer, data, diff); + sha->buffLen = diff; + } else { + HASH_DataIn(*(uint32_t*)data); + data+=4; + } + } + + /* keep track of total data length thus far */ + sha->loLen += (len - sha->buffLen); + + return 0; + } + + int ShaFinal(Sha* sha, byte* hash) + { + __IO uint16_t nbvalidbitsdata = 0; + + /* finish reading any trailing bytes into FIFO */ + if (sha->buffLen) { + HASH_DataIn(*(uint32_t*)sha->buffer); + sha->loLen += sha->buffLen; + } + + /* calculate number of valid bits in last word of input data */ + nbvalidbitsdata = 8 * (sha->loLen % SHA_REG_SIZE); + + /* configure number of valid bits in last word of the data */ + HASH_SetLastWordValidBitsNbr(nbvalidbitsdata); + + /* start HASH processor */ + HASH_StartDigest(); + + /* wait until Busy flag == RESET */ + while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {} + + /* read message digest */ + sha->digest[0] = HASH->HR[0]; + sha->digest[1] = HASH->HR[1]; + sha->digest[2] = HASH->HR[2]; + sha->digest[3] = HASH->HR[3]; + sha->digest[4] = HASH->HR[4]; + + ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE); + + XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE); + + return InitSha(sha); /* reset state */ + } + +#else /* CTaoCrypt software implementation */ + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +int InitSha(Sha* sha) +{ + #ifdef FREESCALE_MMCAU + cau_sha1_initialize_output(sha->digest); + #else + sha->digest[0] = 0x67452301L; + sha->digest[1] = 0xEFCDAB89L; + sha->digest[2] = 0x98BADCFEL; + sha->digest[3] = 0x10325476L; + sha->digest[4] = 0xC3D2E1F0L; + #endif + + sha->buffLen = 0; + sha->loLen = 0; + sha->hiLen = 0; + + return 0; +} + +#ifndef FREESCALE_MMCAU + +#define blk0(i) (W[i] = sha->buffer[i]) +#define blk1(i) (W[(i)&15] = \ + rotlFixed(W[((i)+13)&15]^W[((i)+8)&15]^W[((i)+2)&15]^W[(i)&15],1)) + +#define f1(x,y,z) ((z)^((x) &((y)^(z)))) +#define f2(x,y,z) ((x)^(y)^(z)) +#define f3(x,y,z) (((x)&(y))|((z)&((x)|(y)))) +#define f4(x,y,z) ((x)^(y)^(z)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) (z)+= f1((w),(x),(y)) + blk0((i)) + 0x5A827999+ \ + rotlFixed((v),5); (w) = rotlFixed((w),30); +#define R1(v,w,x,y,z,i) (z)+= f1((w),(x),(y)) + blk1((i)) + 0x5A827999+ \ + rotlFixed((v),5); (w) = rotlFixed((w),30); +#define R2(v,w,x,y,z,i) (z)+= f2((w),(x),(y)) + blk1((i)) + 0x6ED9EBA1+ \ + rotlFixed((v),5); (w) = rotlFixed((w),30); +#define R3(v,w,x,y,z,i) (z)+= f3((w),(x),(y)) + blk1((i)) + 0x8F1BBCDC+ \ + rotlFixed((v),5); (w) = rotlFixed((w),30); +#define R4(v,w,x,y,z,i) (z)+= f4((w),(x),(y)) + blk1((i)) + 0xCA62C1D6+ \ + rotlFixed((v),5); (w) = rotlFixed((w),30); + +static void Transform(Sha* sha) +{ + word32 W[SHA_BLOCK_SIZE / sizeof(word32)]; + + /* Copy context->state[] to working vars */ + word32 a = sha->digest[0]; + word32 b = sha->digest[1]; + word32 c = sha->digest[2]; + word32 d = sha->digest[3]; + word32 e = sha->digest[4]; + +#ifdef USE_SLOW_SHA + word32 t, i; + + for (i = 0; i < 16; i++) { + R0(a, b, c, d, e, i); + t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 20; i++) { + R1(a, b, c, d, e, i); + t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 40; i++) { + R2(a, b, c, d, e, i); + t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 60; i++) { + R3(a, b, c, d, e, i); + t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 80; i++) { + R4(a, b, c, d, e, i); + t = e; e = d; d = c; c = b; b = a; a = t; + } +#else + /* nearly 1 K bigger in code size but 25% faster */ + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); +#endif + + /* Add the working vars back into digest state[] */ + sha->digest[0] += a; + sha->digest[1] += b; + sha->digest[2] += c; + sha->digest[3] += d; + sha->digest[4] += e; +} + +#endif /* FREESCALE_MMCAU */ + + +static INLINE void AddLength(Sha* sha, word32 len) +{ + word32 tmp = sha->loLen; + if ( (sha->loLen += len) < tmp) + sha->hiLen++; /* carry low to high */ +} + + +int ShaUpdate(Sha* sha, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)sha->buffer; + + while (len) { + word32 add = min(len, SHA_BLOCK_SIZE - sha->buffLen); + XMEMCPY(&local[sha->buffLen], data, add); + + sha->buffLen += add; + data += add; + len -= add; + + if (sha->buffLen == SHA_BLOCK_SIZE) { + #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU) + ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE); + #endif + XTRANSFORM(sha, local); + AddLength(sha, SHA_BLOCK_SIZE); + sha->buffLen = 0; + } + } + + return 0; +} + + +int ShaFinal(Sha* sha, byte* hash) +{ + byte* local = (byte*)sha->buffer; + + AddLength(sha, sha->buffLen); /* before adding pads */ + + local[sha->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (sha->buffLen > SHA_PAD_SIZE) { + XMEMSET(&local[sha->buffLen], 0, SHA_BLOCK_SIZE - sha->buffLen); + sha->buffLen += SHA_BLOCK_SIZE - sha->buffLen; + + #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU) + ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE); + #endif + XTRANSFORM(sha, local); + sha->buffLen = 0; + } + XMEMSET(&local[sha->buffLen], 0, SHA_PAD_SIZE - sha->buffLen); + + /* put lengths in bits */ + sha->hiLen = (sha->loLen >> (8*sizeof(sha->loLen) - 3)) + + (sha->hiLen << 3); + sha->loLen = sha->loLen << 3; + + /* store lengths */ + #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU) + ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[SHA_PAD_SIZE], &sha->hiLen, sizeof(word32)); + XMEMCPY(&local[SHA_PAD_SIZE + sizeof(word32)], &sha->loLen, sizeof(word32)); + + #ifdef FREESCALE_MMCAU + /* Kinetis requires only these bytes reversed */ + ByteReverseWords(&sha->buffer[SHA_PAD_SIZE/sizeof(word32)], + &sha->buffer[SHA_PAD_SIZE/sizeof(word32)], + 2 * sizeof(word32)); + #endif + + XTRANSFORM(sha, local); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE); + #endif + XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE); + + return InitSha(sha); /* reset state */ +} + +#endif /* STM32F2_HASH */ + + +int ShaHash(const byte* data, word32 len, byte* hash) +{ + int ret = 0; +#ifdef CYASSL_SMALL_STACK + Sha* sha; +#else + Sha sha[1]; +#endif + +#ifdef CYASSL_SMALL_STACK + sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sha == NULL) + return MEMORY_E; +#endif + + if ((ret = InitSha(sha)) != 0) { + CYASSL_MSG("InitSha failed"); + } + else { + ShaUpdate(sha, data, len); + ShaFinal(sha, hash); + } + +#ifdef CYASSL_SMALL_STACK + XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#endif /* NO_SHA */ diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c new file mode 100644 index 000000000..dea0601c0 --- /dev/null +++ b/wolfcrypt/src/sha256.c @@ -0,0 +1,322 @@ +/* sha256.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 + */ + + +/* code submitted by raphael.huck@efixo.com */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#if !defined(NO_SHA256) + +#ifdef CYASSL_PIC32MZ_HASH +#define InitSha256 InitSha256_sw +#define Sha256Update Sha256Update_sw +#define Sha256Final Sha256Final_sw +#endif + +#ifdef HAVE_FIPS + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #include +#endif + +#ifdef FREESCALE_MMCAU + #include "cau_api.h" +#endif + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +int InitSha256(Sha256* sha256) +{ + #ifdef FREESCALE_MMCAU + cau_sha256_initialize_output(sha256->digest); + #else + sha256->digest[0] = 0x6A09E667L; + sha256->digest[1] = 0xBB67AE85L; + sha256->digest[2] = 0x3C6EF372L; + sha256->digest[3] = 0xA54FF53AL; + sha256->digest[4] = 0x510E527FL; + sha256->digest[5] = 0x9B05688CL; + sha256->digest[6] = 0x1F83D9ABL; + sha256->digest[7] = 0x5BE0CD19L; + #endif + + sha256->buffLen = 0; + sha256->loLen = 0; + sha256->hiLen = 0; + + return 0; +} + +#ifdef FREESCALE_MMCAU + #define XTRANSFORM(S,B) Transform((S), (B)) + +static int Transform(Sha256* sha256, byte* buf) +{ + cau_sha256_hash_n(buf, 1, sha256->digest); + + return 0; +} + +#else + #define XTRANSFORM(S,B) Transform((S)) + +static const word32 K[64] = { + 0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL, + 0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L, + 0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L, + 0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL, + 0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L, + 0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L, + 0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL, + 0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L, + 0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L, + 0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L, + 0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL, + 0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L, + 0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L +}; + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) ((((x) | (y)) & (z)) | ((x) & (y))) +#define S(x, n) rotrFixed(x, n) +#define R(x, n) (((x)&0xFFFFFFFFU)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = (h) + Sigma1((e)) + Ch((e), (f), (g)) + K[(i)] + W[(i)]; \ + t1 = Sigma0((a)) + Maj((a), (b), (c)); \ + (d) += t0; \ + (h) = t0 + t1; + + +static int Transform(Sha256* sha256) +{ + word32 S[8], t0, t1; + int i; + +#ifdef CYASSL_SMALL_STACK + word32* W; + + W = (word32*) XMALLOC(sizeof(word32) * 64, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (W == NULL) + return MEMORY_E; +#else + word32 W[64]; +#endif + + /* Copy context->state[] to working vars */ + for (i = 0; i < 8; i++) + S[i] = sha256->digest[i]; + + for (i = 0; i < 16; i++) + W[i] = sha256->buffer[i]; + + for (i = 16; i < 64; i++) + W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16]; + + for (i = 0; i < 64; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + /* Add the working vars back into digest state[] */ + for (i = 0; i < 8; i++) { + sha256->digest[i] += S[i]; + } + +#ifdef CYASSL_SMALL_STACK + XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return 0; +} + +#endif /* FREESCALE_MMCAU */ + + +static INLINE void AddLength(Sha256* sha256, word32 len) +{ + word32 tmp = sha256->loLen; + if ( (sha256->loLen += len) < tmp) + sha256->hiLen++; /* carry low to high */ +} + + +int Sha256Update(Sha256* sha256, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)sha256->buffer; + + while (len) { + word32 add = min(len, SHA256_BLOCK_SIZE - sha256->buffLen); + XMEMCPY(&local[sha256->buffLen], data, add); + + sha256->buffLen += add; + data += add; + len -= add; + + if (sha256->buffLen == SHA256_BLOCK_SIZE) { + int ret; + + #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU) + ByteReverseWords(sha256->buffer, sha256->buffer, + SHA256_BLOCK_SIZE); + #endif + + ret = XTRANSFORM(sha256, local); + if (ret != 0) + return ret; + + AddLength(sha256, SHA256_BLOCK_SIZE); + sha256->buffLen = 0; + } + } + + return 0; +} + + +int Sha256Final(Sha256* sha256, byte* hash) +{ + byte* local = (byte*)sha256->buffer; + int ret; + + AddLength(sha256, sha256->buffLen); /* before adding pads */ + + local[sha256->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (sha256->buffLen > SHA256_PAD_SIZE) { + XMEMSET(&local[sha256->buffLen], 0, SHA256_BLOCK_SIZE - sha256->buffLen); + sha256->buffLen += SHA256_BLOCK_SIZE - sha256->buffLen; + + #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU) + ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE); + #endif + + ret = XTRANSFORM(sha256, local); + if (ret != 0) + return ret; + + sha256->buffLen = 0; + } + XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen); + + /* put lengths in bits */ + sha256->hiLen = (sha256->loLen >> (8*sizeof(sha256->loLen) - 3)) + + (sha256->hiLen << 3); + sha256->loLen = sha256->loLen << 3; + + /* store lengths */ + #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU) + ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32)); + XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen, + sizeof(word32)); + + #ifdef FREESCALE_MMCAU + /* Kinetis requires only these bytes reversed */ + ByteReverseWords(&sha256->buffer[SHA256_PAD_SIZE/sizeof(word32)], + &sha256->buffer[SHA256_PAD_SIZE/sizeof(word32)], + 2 * sizeof(word32)); + #endif + + ret = XTRANSFORM(sha256, local); + if (ret != 0) + return ret; + + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE); + #endif + XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE); + + return InitSha256(sha256); /* reset state */ +} + + +int Sha256Hash(const byte* data, word32 len, byte* hash) +{ + int ret = 0; +#ifdef CYASSL_SMALL_STACK + Sha256* sha256; +#else + Sha256 sha256[1]; +#endif + +#ifdef CYASSL_SMALL_STACK + sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sha256 == NULL) + return MEMORY_E; +#endif + + if ((ret = InitSha256(sha256)) != 0) { + CYASSL_MSG("InitSha256 failed"); + } + else if ((ret = Sha256Update(sha256, data, len)) != 0) { + CYASSL_MSG("Sha256Update failed"); + } + else if ((ret = Sha256Final(sha256, hash)) != 0) { + CYASSL_MSG("Sha256Final failed"); + } + +#ifdef CYASSL_SMALL_STACK + XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + + +#endif /* NO_SHA256 */ + diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c new file mode 100644 index 000000000..44e3676c1 --- /dev/null +++ b/wolfcrypt/src/tfm.c @@ -0,0 +1,2538 @@ +/* tfm.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 + */ + + +/* + * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca, + * http://math.libtomcrypt.com + */ + +/** + * Edited by Moisés Guimarães (moisesguimaraesm@gmail.com) + * to fit CyaSSL's needs. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +/* in case user set USE_FAST_MATH there */ +#include + +#ifdef USE_FAST_MATH + +#include +#include /* will define asm MACROS or C ones */ + + +/* math settings check */ +word32 CheckRunTimeSettings(void) +{ + return CTC_SETTINGS; +} + + +/* math settings size check */ +word32 CheckRunTimeFastMath(void) +{ + return FP_SIZE; +} + + +/* Functions */ + +void fp_add(fp_int *a, fp_int *b, fp_int *c) +{ + int sa, sb; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + s_fp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (fp_cmp_mag (a, b) == FP_LT) { + c->sign = sb; + s_fp_sub (b, a, c); + } else { + c->sign = sa; + s_fp_sub (a, b, c); + } + } +} + +/* unsigned addition */ +void s_fp_add(fp_int *a, fp_int *b, fp_int *c) +{ + int x, y, oldused; + register fp_word t; + + y = MAX(a->used, b->used); + oldused = MIN(c->used, FP_SIZE); /* help static analysis w/ largest size */ + c->used = y; + + t = 0; + for (x = 0; x < y; x++) { + t += ((fp_word)a->dp[x]) + ((fp_word)b->dp[x]); + c->dp[x] = (fp_digit)t; + t >>= DIGIT_BIT; + } + if (t != 0 && x < FP_SIZE) { + c->dp[c->used++] = (fp_digit)t; + ++x; + } + + c->used = x; + for (; x < oldused; x++) { + c->dp[x] = 0; + } + fp_clamp(c); +} + +/* c = a - b */ +void fp_sub(fp_int *a, fp_int *b, fp_int *c) +{ + int sa, sb; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + s_fp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (fp_cmp_mag (a, b) != FP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + s_fp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == FP_ZPOS) ? FP_NEG : FP_ZPOS; + /* The second has a larger magnitude */ + s_fp_sub (b, a, c); + } + } +} + +/* unsigned subtraction ||a|| >= ||b|| ALWAYS! */ +void s_fp_sub(fp_int *a, fp_int *b, fp_int *c) +{ + int x, oldbused, oldused; + fp_word t; + + oldused = c->used; + oldbused = b->used; + c->used = a->used; + t = 0; + for (x = 0; x < oldbused; x++) { + t = ((fp_word)a->dp[x]) - (((fp_word)b->dp[x]) + t); + c->dp[x] = (fp_digit)t; + t = (t >> DIGIT_BIT)&1; + } + for (; x < a->used; x++) { + t = ((fp_word)a->dp[x]) - t; + c->dp[x] = (fp_digit)t; + t = (t >> DIGIT_BIT)&1; + } + for (; x < oldused; x++) { + c->dp[x] = 0; + } + fp_clamp(c); +} + +/* c = a * b */ +void fp_mul(fp_int *A, fp_int *B, fp_int *C) +{ + int y, yy; + + y = MAX(A->used, B->used); + yy = MIN(A->used, B->used); + + /* call generic if we're out of range */ + if (y + yy > FP_SIZE) { + fp_mul_comba(A, B, C); + return ; + } + + /* pick a comba (unrolled 4/8/16/32 x or rolled) based on the size + of the largest input. We also want to avoid doing excess mults if the + inputs are not close to the next power of two. That is, for example, + if say y=17 then we would do (32-17)^2 = 225 unneeded multiplications + */ + +#ifdef TFM_MUL3 + if (y <= 3) { + fp_mul_comba3(A,B,C); + return; + } +#endif +#ifdef TFM_MUL4 + if (y == 4) { + fp_mul_comba4(A,B,C); + return; + } +#endif +#ifdef TFM_MUL6 + if (y <= 6) { + fp_mul_comba6(A,B,C); + return; + } +#endif +#ifdef TFM_MUL7 + if (y == 7) { + fp_mul_comba7(A,B,C); + return; + } +#endif +#ifdef TFM_MUL8 + if (y == 8) { + fp_mul_comba8(A,B,C); + return; + } +#endif +#ifdef TFM_MUL9 + if (y == 9) { + fp_mul_comba9(A,B,C); + return; + } +#endif +#ifdef TFM_MUL12 + if (y <= 12) { + fp_mul_comba12(A,B,C); + return; + } +#endif +#ifdef TFM_MUL17 + if (y <= 17) { + fp_mul_comba17(A,B,C); + return; + } +#endif + +#ifdef TFM_SMALL_SET + if (y <= 16) { + fp_mul_comba_small(A,B,C); + return; + } +#endif +#if defined(TFM_MUL20) + if (y <= 20) { + fp_mul_comba20(A,B,C); + return; + } +#endif +#if defined(TFM_MUL24) + if (yy >= 16 && y <= 24) { + fp_mul_comba24(A,B,C); + return; + } +#endif +#if defined(TFM_MUL28) + if (yy >= 20 && y <= 28) { + fp_mul_comba28(A,B,C); + return; + } +#endif +#if defined(TFM_MUL32) + if (yy >= 24 && y <= 32) { + fp_mul_comba32(A,B,C); + return; + } +#endif +#if defined(TFM_MUL48) + if (yy >= 40 && y <= 48) { + fp_mul_comba48(A,B,C); + return; + } +#endif +#if defined(TFM_MUL64) + if (yy >= 56 && y <= 64) { + fp_mul_comba64(A,B,C); + return; + } +#endif + fp_mul_comba(A,B,C); +} + +void fp_mul_2(fp_int * a, fp_int * b) +{ + int x, oldused; + + oldused = b->used; + b->used = a->used; + + { + register fp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((fp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((fp_digit)1)) | r); + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0 && b->used != (FP_SIZE-1)) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; +} + +/* c = a * b */ +void fp_mul_d(fp_int *a, fp_digit b, fp_int *c) +{ + fp_word w; + int x, oldused; + + oldused = c->used; + c->used = a->used; + c->sign = a->sign; + w = 0; + for (x = 0; x < a->used; x++) { + w = ((fp_word)a->dp[x]) * ((fp_word)b) + w; + c->dp[x] = (fp_digit)w; + w = w >> DIGIT_BIT; + } + if (w != 0 && (a->used != FP_SIZE)) { + c->dp[c->used++] = (fp_digit) w; + ++x; + } + for (; x < oldused; x++) { + c->dp[x] = 0; + } + fp_clamp(c); +} + +/* c = a * 2**d */ +void fp_mul_2d(fp_int *a, int b, fp_int *c) +{ + fp_digit carry, carrytmp, shift; + int x; + + /* copy it */ + fp_copy(a, c); + + /* handle whole digits */ + if (b >= DIGIT_BIT) { + fp_lshd(c, b/DIGIT_BIT); + } + b %= DIGIT_BIT; + + /* shift the digits */ + if (b != 0) { + carry = 0; + shift = DIGIT_BIT - b; + for (x = 0; x < c->used; x++) { + carrytmp = c->dp[x] >> shift; + c->dp[x] = (c->dp[x] << b) + carry; + carry = carrytmp; + } + /* store last carry if room */ + if (carry && x < FP_SIZE) { + c->dp[c->used++] = carry; + } + } + fp_clamp(c); +} + +/* generic PxQ multiplier */ +void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C) +{ + int ix, iy, iz, tx, ty, pa; + fp_digit c0, c1, c2, *tmpx, *tmpy; + fp_int tmp, *dst; + + COMBA_START; + COMBA_CLEAR; + + /* get size of output and trim */ + pa = A->used + B->used; + if (pa >= FP_SIZE) { + pa = FP_SIZE-1; + } + + if (A == C || B == C) { + fp_zero(&tmp); + dst = &tmp; + } else { + fp_zero(C); + dst = C; + } + + for (ix = 0; ix < pa; ix++) { + /* get offsets into the two bignums */ + ty = MIN(ix, B->used-1); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = A->dp + tx; + tmpy = B->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(A->used-tx, ty+1); + + /* execute loop */ + COMBA_FORWARD; + for (iz = 0; iz < iy; ++iz) { + /* TAO change COMBA_ADD back to MULADD */ + MULADD(*tmpx++, *tmpy--); + } + + /* store term */ + COMBA_STORE(dst->dp[ix]); + } + COMBA_FINI; + + dst->used = pa; + dst->sign = A->sign ^ B->sign; + fp_clamp(dst); + fp_copy(dst, C); +} + +/* a/b => cb + d == a */ +int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d) +{ + fp_int q, x, y, t1, t2; + int n, t, i, norm, neg; + + /* is divisor zero ? */ + if (fp_iszero (b) == 1) { + return FP_VAL; + } + + /* if a < b then q=0, r = a */ + if (fp_cmp_mag (a, b) == FP_LT) { + if (d != NULL) { + fp_copy (a, d); + } + if (c != NULL) { + fp_zero (c); + } + return FP_OKAY; + } + + fp_init(&q); + q.used = a->used + 2; + + fp_init(&t1); + fp_init(&t2); + fp_init_copy(&x, a); + fp_init_copy(&y, b); + + /* fix the sign */ + neg = (a->sign == b->sign) ? FP_ZPOS : FP_NEG; + x.sign = y.sign = FP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = fp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + fp_mul_2d (&x, norm, &x); + fp_mul_2d (&y, norm, &y); + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + fp_lshd (&y, n - t); /* y = y*b**{n-t} */ + + while (fp_cmp (&x, &y) != FP_LT) { + ++(q.dp[n - t]); + fp_sub (&x, &y, &x); + } + + /* reset y by shifting it back down */ + fp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = (fp_digit) ((((fp_word)1) << DIGIT_BIT) - 1); + } else { + fp_word tmp; + tmp = ((fp_word) x.dp[i]) << ((fp_word) DIGIT_BIT); + tmp |= ((fp_word) x.dp[i - 1]); + tmp /= ((fp_word)y.dp[t]); + q.dp[i - t - 1] = (fp_digit) (tmp); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1); + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1); + + /* find left hand */ + fp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + fp_mul_d (&t1, q.dp[i - t - 1], &t1); + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (fp_cmp_mag(&t1, &t2) == FP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + fp_mul_d (&y, q.dp[i - t - 1], &t1); + fp_lshd (&t1, i - t - 1); + fp_sub (&x, &t1, &x); + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == FP_NEG) { + fp_copy (&y, &t1); + fp_lshd (&t1, i - t - 1); + fp_add (&x, &t1, &x); + q.dp[i - t - 1] = q.dp[i - t - 1] - 1; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? FP_ZPOS : a->sign; + + if (c != NULL) { + fp_clamp (&q); + fp_copy (&q, c); + c->sign = neg; + } + + if (d != NULL) { + fp_div_2d (&x, norm, &x, NULL); + +/* the following is a kludge, essentially we were seeing the right remainder but + with excess digits that should have been zero + */ + for (i = b->used; i < x.used; i++) { + x.dp[i] = 0; + } + fp_clamp(&x); + fp_copy (&x, d); + } + + return FP_OKAY; +} + +/* b = a/2 */ +void fp_div_2(fp_int * a, fp_int * b) +{ + int x, oldused; + + oldused = b->used; + b->used = a->used; + { + register fp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + fp_clamp (b); +} + +/* c = a / 2**b */ +void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d) +{ + int D; + fp_int t; + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + fp_copy (a, c); + if (d != NULL) { + fp_zero (d); + } + return; + } + + fp_init(&t); + + /* get the remainder */ + if (d != NULL) { + fp_mod_2d (a, b, &t); + } + + /* copy */ + fp_copy(a, c); + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + fp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (b % DIGIT_BIT); + if (D != 0) { + fp_rshb(c, D); + } + fp_clamp (c); + if (d != NULL) { + fp_copy (&t, d); + } +} + +/* c = a mod b, 0 <= c < b */ +int fp_mod(fp_int *a, fp_int *b, fp_int *c) +{ + fp_int t; + int err; + + fp_zero(&t); + if ((err = fp_div(a, b, NULL, &t)) != FP_OKAY) { + return err; + } + if (t.sign != b->sign) { + fp_add(&t, b, c); + } else { + fp_copy(&t, c); + } + return FP_OKAY; +} + +/* c = a mod 2**d */ +void fp_mod_2d(fp_int *a, int b, fp_int *c) +{ + int x; + + /* zero if count less than or equal to zero */ + if (b <= 0) { + fp_zero(c); + return; + } + + /* get copy of input */ + fp_copy(a, c); + + /* if 2**d is larger than we just return */ + if (b >= (DIGIT_BIT * a->used)) { + return; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= ~((fp_digit)0) >> (DIGIT_BIT - b); + fp_clamp (c); +} + +static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c) +{ + fp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == FP_NEG || fp_iszero(b) == 1) { + return FP_VAL; + } + + /* init temps */ + fp_init(&x); fp_init(&y); + fp_init(&u); fp_init(&v); + fp_init(&A); fp_init(&B); + fp_init(&C); fp_init(&D); + + /* x = a, y = b */ + if ((res = fp_mod(a, b, &x)) != FP_OKAY) { + return res; + } + fp_copy(b, &y); + + /* 2. [modified] if x,y are both even then return an error! */ + if (fp_iseven (&x) == 1 && fp_iseven (&y) == 1) { + return FP_VAL; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + fp_copy (&x, &u); + fp_copy (&y, &v); + fp_set (&A, 1); + fp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (fp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + fp_div_2 (&u, &u); + + /* 4.2 if A or B is odd then */ + if (fp_isodd (&A) == 1 || fp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + fp_add (&A, &y, &A); + fp_sub (&B, &x, &B); + } + /* A = A/2, B = B/2 */ + fp_div_2 (&A, &A); + fp_div_2 (&B, &B); + } + + /* 5. while v is even do */ + while (fp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + fp_div_2 (&v, &v); + + /* 5.2 if C or D is odd then */ + if (fp_isodd (&C) == 1 || fp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + fp_add (&C, &y, &C); + fp_sub (&D, &x, &D); + } + /* C = C/2, D = D/2 */ + fp_div_2 (&C, &C); + fp_div_2 (&D, &D); + } + + /* 6. if u >= v then */ + if (fp_cmp (&u, &v) != FP_LT) { + /* u = u - v, A = A - C, B = B - D */ + fp_sub (&u, &v, &u); + fp_sub (&A, &C, &A); + fp_sub (&B, &D, &B); + } else { + /* v - v - u, C = C - A, D = D - B */ + fp_sub (&v, &u, &v); + fp_sub (&C, &A, &C); + fp_sub (&D, &B, &D); + } + + /* if not zero goto step 4 */ + if (fp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (fp_cmp_d (&v, 1) != FP_EQ) { + return FP_VAL; + } + + /* if its too low */ + while (fp_cmp_d(&C, 0) == FP_LT) { + fp_add(&C, b, &C); + } + + /* too big */ + while (fp_cmp_mag(&C, b) != FP_LT) { + fp_sub(&C, b, &C); + } + + /* C is now the inverse */ + fp_copy(&C, c); + return FP_OKAY; +} + +/* c = 1/a (mod b) for odd b only */ +int fp_invmod(fp_int *a, fp_int *b, fp_int *c) +{ + fp_int x, y, u, v, B, D; + int neg; + + /* 2. [modified] b must be odd */ + if (fp_iseven (b) == FP_YES) { + return fp_invmod_slow(a,b,c); + } + + /* init all our temps */ + fp_init(&x); fp_init(&y); + fp_init(&u); fp_init(&v); + fp_init(&B); fp_init(&D); + + /* x == modulus, y == value to invert */ + fp_copy(b, &x); + + /* we need y = |a| */ + fp_abs(a, &y); + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + fp_copy(&x, &u); + fp_copy(&y, &v); + fp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (fp_iseven (&u) == FP_YES) { + /* 4.1 u = u/2 */ + fp_div_2 (&u, &u); + + /* 4.2 if B is odd then */ + if (fp_isodd (&B) == FP_YES) { + fp_sub (&B, &x, &B); + } + /* B = B/2 */ + fp_div_2 (&B, &B); + } + + /* 5. while v is even do */ + while (fp_iseven (&v) == FP_YES) { + /* 5.1 v = v/2 */ + fp_div_2 (&v, &v); + + /* 5.2 if D is odd then */ + if (fp_isodd (&D) == FP_YES) { + /* D = (D-x)/2 */ + fp_sub (&D, &x, &D); + } + /* D = D/2 */ + fp_div_2 (&D, &D); + } + + /* 6. if u >= v then */ + if (fp_cmp (&u, &v) != FP_LT) { + /* u = u - v, B = B - D */ + fp_sub (&u, &v, &u); + fp_sub (&B, &D, &B); + } else { + /* v - v - u, D = D - B */ + fp_sub (&v, &u, &v); + fp_sub (&D, &B, &D); + } + + /* if not zero goto step 4 */ + if (fp_iszero (&u) == FP_NO) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (fp_cmp_d (&v, 1) != FP_EQ) { + return FP_VAL; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == FP_NEG) { + fp_add (&D, b, &D); + } + fp_copy (&D, c); + c->sign = neg; + return FP_OKAY; +} + +/* d = a * b (mod c) */ +int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d) +{ + fp_int tmp; + fp_zero(&tmp); + fp_mul(a, b, &tmp); + return fp_mod(&tmp, c, d); +} + +#ifdef TFM_TIMING_RESISTANT + +/* timing resistant montgomery ladder based exptmod + + Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder", Cryptographic Hardware and Embedded Systems, CHES 2002 +*/ +static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) +{ + fp_int R[2]; + fp_digit buf, mp; + int err, bitcnt, digidx, y; + + /* now setup montgomery */ + if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) { + return err; + } + + fp_init(&R[0]); + fp_init(&R[1]); + + /* now we need R mod m */ + fp_montgomery_calc_normalization (&R[0], P); + + /* now set R[0][1] to G * R mod m */ + if (fp_cmp_mag(P, G) != FP_GT) { + /* G > P so we reduce it first */ + fp_mod(G, P, &R[1]); + } else { + fp_copy(G, &R[1]); + } + fp_mulmod (&R[1], &R[0], P, &R[1]); + + /* for j = t-1 downto 0 do + r_!k = R0*R1; r_k = r_k^2 + */ + + /* set initial mode and bit cnt */ + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (int)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (fp_digit)1; + + /* do ops */ + fp_mul(&R[0], &R[1], &R[y^1]); fp_montgomery_reduce(&R[y^1], P, mp); + fp_sqr(&R[y], &R[y]); fp_montgomery_reduce(&R[y], P, mp); + } + + fp_montgomery_reduce(&R[0], P, mp); + fp_copy(&R[0], Y); + return FP_OKAY; +} + +#else + +/* y = g**x (mod b) + * Some restrictions... x must be positive and < b + */ +static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) +{ + fp_int M[64], res; + fp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* find window size */ + x = fp_count_bits (X); + if (x <= 21) { + winsize = 1; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else { + winsize = 6; + } + + /* init M array */ + XMEMSET(M, 0, sizeof(M)); + + /* now setup montgomery */ + if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) { + return err; + } + + /* setup result */ + fp_init(&res); + + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G^x mod P + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + /* now we need R mod m */ + fp_montgomery_calc_normalization (&res, P); + + /* now set M[1] to G * R mod m */ + if (fp_cmp_mag(P, G) != FP_GT) { + /* G > P so we reduce it first */ + fp_mod(G, P, &M[1]); + } else { + fp_copy(G, &M[1]); + } + fp_mulmod (&M[1], &res, P, &M[1]); + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + fp_copy (&M[1], &M[1 << (winsize - 1)]); + for (x = 0; x < (winsize - 1); x++) { + fp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)]); + fp_montgomery_reduce (&M[1 << (winsize - 1)], P, mp); + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + fp_mul(&M[x - 1], &M[1], &M[x]); + fp_montgomery_reduce(&M[x], P, mp); + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (int)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (fp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + fp_sqr(&res, &res); + fp_montgomery_reduce(&res, P, mp); + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + fp_sqr(&res, &res); + fp_montgomery_reduce(&res, P, mp); + } + + /* then multiply */ + fp_mul(&res, &M[bitbuf], &res); + fp_montgomery_reduce(&res, P, mp); + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + fp_sqr(&res, &res); + fp_montgomery_reduce(&res, P, mp); + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + fp_mul(&res, &M[1], &res); + fp_montgomery_reduce(&res, P, mp); + } + } + } + + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + fp_montgomery_reduce(&res, P, mp); + + /* swap res with Y */ + fp_copy (&res, Y); + return FP_OKAY; +} + +#endif + +int fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) +{ + /* prevent overflows */ + if (P->used > (FP_SIZE/2)) { + return FP_VAL; + } + + if (X->sign == FP_NEG) { +#ifndef POSITIVE_EXP_ONLY /* reduce stack if assume no negatives */ + int err; + fp_int tmp; + + /* yes, copy G and invmod it */ + fp_copy(G, &tmp); + if ((err = fp_invmod(&tmp, P, &tmp)) != FP_OKAY) { + return err; + } + X->sign = FP_ZPOS; + err = _fp_exptmod(&tmp, X, P, Y); + if (X != Y) { + X->sign = FP_NEG; + } + return err; +#else + return FP_VAL; +#endif + } + else { + /* Positive exponent so just exptmod */ + return _fp_exptmod(G, X, P, Y); + } +} + +/* computes a = 2**b */ +void fp_2expt(fp_int *a, int b) +{ + int z; + + /* zero a as per default */ + fp_zero (a); + + if (b < 0) { + return; + } + + z = b / DIGIT_BIT; + if (z >= FP_SIZE) { + return; + } + + /* set the used count of where the bit will go */ + a->used = z + 1; + + /* put the single bit in its place */ + a->dp[z] = ((fp_digit)1) << (b % DIGIT_BIT); +} + +/* b = a*a */ +void fp_sqr(fp_int *A, fp_int *B) +{ + int y = A->used; + + /* call generic if we're out of range */ + if (y + y > FP_SIZE) { + fp_sqr_comba(A, B); + return ; + } + +#if defined(TFM_SQR3) + if (y <= 3) { + fp_sqr_comba3(A,B); + return; + } +#endif +#if defined(TFM_SQR4) + if (y == 4) { + fp_sqr_comba4(A,B); + return; + } +#endif +#if defined(TFM_SQR6) + if (y <= 6) { + fp_sqr_comba6(A,B); + return; + } +#endif +#if defined(TFM_SQR7) + if (y == 7) { + fp_sqr_comba7(A,B); + return; + } +#endif +#if defined(TFM_SQR8) + if (y == 8) { + fp_sqr_comba8(A,B); + return; + } +#endif +#if defined(TFM_SQR9) + if (y == 9) { + fp_sqr_comba9(A,B); + return; + } +#endif +#if defined(TFM_SQR12) + if (y <= 12) { + fp_sqr_comba12(A,B); + return; + } +#endif +#if defined(TFM_SQR17) + if (y <= 17) { + fp_sqr_comba17(A,B); + return; + } +#endif +#if defined(TFM_SMALL_SET) + if (y <= 16) { + fp_sqr_comba_small(A,B); + return; + } +#endif +#if defined(TFM_SQR20) + if (y <= 20) { + fp_sqr_comba20(A,B); + return; + } +#endif +#if defined(TFM_SQR24) + if (y <= 24) { + fp_sqr_comba24(A,B); + return; + } +#endif +#if defined(TFM_SQR28) + if (y <= 28) { + fp_sqr_comba28(A,B); + return; + } +#endif +#if defined(TFM_SQR32) + if (y <= 32) { + fp_sqr_comba32(A,B); + return; + } +#endif +#if defined(TFM_SQR48) + if (y <= 48) { + fp_sqr_comba48(A,B); + return; + } +#endif +#if defined(TFM_SQR64) + if (y <= 64) { + fp_sqr_comba64(A,B); + return; + } +#endif + fp_sqr_comba(A, B); +} + +/* generic comba squarer */ +void fp_sqr_comba(fp_int *A, fp_int *B) +{ + int pa, ix, iz; + fp_digit c0, c1, c2; + fp_int tmp, *dst; +#ifdef TFM_ISO + fp_word tt; +#endif + + /* get size of output and trim */ + pa = A->used + A->used; + if (pa >= FP_SIZE) { + pa = FP_SIZE-1; + } + + /* number of output digits to produce */ + COMBA_START; + COMBA_CLEAR; + + if (A == B) { + fp_zero(&tmp); + dst = &tmp; + } else { + fp_zero(B); + dst = B; + } + + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + fp_digit *tmpy, *tmpx; + + /* get offsets into the two bignums */ + ty = MIN(A->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = A->dp + tx; + tmpy = A->dp + ty; + + /* this is the number of times the loop will iterrate, + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(A->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach + * at a rate of 2x and we have to round because + * odd cases need to be executed + */ + iy = MIN(iy, (ty-tx+1)>>1); + + /* forward carries */ + COMBA_FORWARD; + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + SQRADD2(*tmpx++, *tmpy--); + } + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + /* TAO change COMBA_ADD back to SQRADD */ + SQRADD(A->dp[ix>>1], A->dp[ix>>1]); + } + + /* store it */ + COMBA_STORE(dst->dp[ix]); + } + + COMBA_FINI; + + /* setup dest */ + dst->used = pa; + fp_clamp (dst); + if (dst != B) { + fp_copy(dst, B); + } +} + +int fp_cmp(fp_int *a, fp_int *b) +{ + if (a->sign == FP_NEG && b->sign == FP_ZPOS) { + return FP_LT; + } else if (a->sign == FP_ZPOS && b->sign == FP_NEG) { + return FP_GT; + } else { + /* compare digits */ + if (a->sign == FP_NEG) { + /* if negative compare opposite direction */ + return fp_cmp_mag(b, a); + } else { + return fp_cmp_mag(a, b); + } + } +} + +/* compare against a single digit */ +int fp_cmp_d(fp_int *a, fp_digit b) +{ + /* compare based on sign */ + if ((b && a->used == 0) || a->sign == FP_NEG) { + return FP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return FP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return FP_GT; + } else if (a->dp[0] < b) { + return FP_LT; + } else { + return FP_EQ; + } + +} + +int fp_cmp_mag(fp_int *a, fp_int *b) +{ + int x; + + if (a->used > b->used) { + return FP_GT; + } else if (a->used < b->used) { + return FP_LT; + } else { + for (x = a->used - 1; x >= 0; x--) { + if (a->dp[x] > b->dp[x]) { + return FP_GT; + } else if (a->dp[x] < b->dp[x]) { + return FP_LT; + } + } + } + return FP_EQ; +} + +/* setups the montgomery reduction */ +int fp_montgomery_setup(fp_int *a, fp_digit *rho) +{ + fp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = a->dp[0]; + + if ((b & 1) == 0) { + return FP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#ifdef FP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (fp_digit) (((fp_word) 1 << ((fp_word) DIGIT_BIT)) - ((fp_word)x)); + + return FP_OKAY; +} + +/* computes a = B**n mod b without division or multiplication useful for + * normalizing numbers in a Montgomery system. + */ +void fp_montgomery_calc_normalization(fp_int *a, fp_int *b) +{ + int x, bits; + + /* how many bits of last digit does b use */ + bits = fp_count_bits (b) % DIGIT_BIT; + if (!bits) bits = DIGIT_BIT; + + /* compute A = B^(n-1) * 2^(bits-1) */ + if (b->used > 1) { + fp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1); + } else { + fp_set(a, 1); + bits = 1; + } + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + fp_mul_2 (a, a); + if (fp_cmp_mag (a, b) != FP_LT) { + s_fp_sub (a, b, a); + } + } +} + + +#ifdef TFM_SMALL_MONT_SET + #include "fp_mont_small.i" +#endif + +/* computes x/R == x (mod N) via Montgomery Reduction */ +void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +{ + fp_digit c[FP_SIZE], *_c, *tmpm, mu = 0; + int oldused, x, y, pa; + + /* bail if too large */ + if (m->used > (FP_SIZE/2)) { + (void)mu; /* shut up compiler */ + return; + } + +#ifdef TFM_SMALL_MONT_SET + if (m->used <= 16) { + fp_montgomery_reduce_small(a, m, mp); + return; + } +#endif + + + /* now zero the buff */ + XMEMSET(c, 0, sizeof c); + pa = m->used; + + /* copy the input */ + oldused = a->used; + for (x = 0; x < oldused; x++) { + c[x] = a->dp[x]; + } + MONT_START; + + for (x = 0; x < pa; x++) { + fp_digit cy = 0; + /* get Mu for this round */ + LOOP_START; + _c = c + x; + tmpm = m->dp; + y = 0; + #if (defined(TFM_SSE2) || defined(TFM_X86_64)) + for (; y < (pa & ~7); y += 8) { + INNERMUL8; + _c += 8; + tmpm += 8; + } + #endif + + for (; y < pa; y++) { + INNERMUL; + ++_c; + } + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + } + + /* now copy out */ + _c = c + pa; + tmpm = a->dp; + for (x = 0; x < pa+1; x++) { + *tmpm++ = *_c++; + } + + for (; x < oldused; x++) { + *tmpm++ = 0; + } + + MONT_FINI; + + a->used = pa+1; + fp_clamp(a); + + /* if A >= m then A = A - m */ + if (fp_cmp_mag (a, m) != FP_LT) { + s_fp_sub (a, m, a); + } +} + +void fp_read_unsigned_bin(fp_int *a, unsigned char *b, int c) +{ + /* zero the int */ + fp_zero (a); + + /* If we know the endianness of this architecture, and we're using + 32-bit fp_digits, we can optimize this */ +#if (defined(LITTLE_ENDIAN_ORDER) || defined(BIG_ENDIAN_ORDER)) && defined(FP_32BIT) + /* But not for both simultaneously */ +#if defined(LITTLE_ENDIAN_ORDER) && defined(BIG_ENDIAN_ORDER) +#error Both LITTLE_ENDIAN_ORDER and BIG_ENDIAN_ORDER defined. +#endif + { + unsigned char *pd = (unsigned char *)a->dp; + + if ((unsigned)c > (FP_SIZE * sizeof(fp_digit))) { + int excess = c - (FP_SIZE * sizeof(fp_digit)); + c -= excess; + b += excess; + } + a->used = (c + sizeof(fp_digit) - 1)/sizeof(fp_digit); + /* read the bytes in */ +#ifdef BIG_ENDIAN_ORDER + { + /* Use Duff's device to unroll the loop. */ + int idx = (c - 1) & ~3; + switch (c % 4) { + case 0: do { pd[idx+0] = *b++; + case 3: pd[idx+1] = *b++; + case 2: pd[idx+2] = *b++; + case 1: pd[idx+3] = *b++; + idx -= 4; + } while ((c -= 4) > 0); + } + } +#else + for (c -= 1; c >= 0; c -= 1) { + pd[c] = *b++; + } +#endif + } +#else + /* read the bytes in */ + for (; c > 0; c--) { + fp_mul_2d (a, 8, a); + a->dp[0] |= *b++; + a->used += 1; + } +#endif + fp_clamp (a); +} + +void fp_to_unsigned_bin(fp_int *a, unsigned char *b) +{ + int x; + fp_int t; + + fp_init_copy(&t, a); + + x = 0; + while (fp_iszero (&t) == FP_NO) { + b[x++] = (unsigned char) (t.dp[0] & 255); + fp_div_2d (&t, 8, &t, NULL); + } + fp_reverse (b, x); +} + +int fp_unsigned_bin_size(fp_int *a) +{ + int size = fp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +void fp_set(fp_int *a, fp_digit b) +{ + fp_zero(a); + a->dp[0] = b; + a->used = a->dp[0] ? 1 : 0; +} + +int fp_count_bits (fp_int * a) +{ + int r; + fp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((fp_digit) 0)) { + ++r; + q >>= ((fp_digit) 1); + } + return r; +} + +int fp_leading_bit(fp_int *a) +{ + int bit = 0; + + if (a->used != 0) { + fp_digit q = a->dp[a->used - 1]; + int qSz = sizeof(fp_digit); + + while (qSz > 0) { + if ((unsigned char)q != 0) + bit = (q & 0x80) != 0; + q >>= 8; + qSz--; + } + } + + return bit; +} + +void fp_lshd(fp_int *a, int x) +{ + int y; + + /* move up and truncate as required */ + y = MIN(a->used + x - 1, (int)(FP_SIZE-1)); + + /* store new size */ + a->used = y + 1; + + /* move digits */ + for (; y >= x; y--) { + a->dp[y] = a->dp[y-x]; + } + + /* zero lower digits */ + for (; y >= 0; y--) { + a->dp[y] = 0; + } + + /* clamp digits */ + fp_clamp(a); +} + + +/* right shift by bit count */ +void fp_rshb(fp_int *c, int x) +{ + register fp_digit *tmpc, mask, shift; + fp_digit r, rr; + fp_digit D = x; + + /* mask */ + mask = (((fp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } +} + + +void fp_rshd(fp_int *a, int x) +{ + int y; + + /* too many digits just zero and return */ + if (x >= a->used) { + fp_zero(a); + return; + } + + /* shift */ + for (y = 0; y < a->used - x; y++) { + a->dp[y] = a->dp[y+x]; + } + + /* zero rest */ + for (; y < a->used; y++) { + a->dp[y] = 0; + } + + /* decrement count */ + a->used -= x; + fp_clamp(a); +} + +/* reverse an array, used for radix code */ +void fp_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + + +/* c = a - b */ +void fp_sub_d(fp_int *a, fp_digit b, fp_int *c) +{ + fp_int tmp; + fp_set(&tmp, b); + fp_sub(a, &tmp, c); +} + + +/* CyaSSL callers from normal lib */ + +/* init a new mp_int */ +int mp_init (mp_int * a) +{ + if (a) + fp_init(a); + return MP_OKAY; +} + +/* clear one (frees) */ +void mp_clear (mp_int * a) +{ + fp_zero(a); +} + +/* handle up to 6 inits */ +int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f) +{ + if (a) + fp_init(a); + if (b) + fp_init(b); + if (c) + fp_init(c); + if (d) + fp_init(d); + if (e) + fp_init(e); + if (f) + fp_init(f); + + return MP_OKAY; +} + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + fp_add(a, b, c); + return MP_OKAY; +} + +/* high level subtraction (handles signs) */ +int mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + fp_sub(a, b, c); + return MP_OKAY; +} + +/* high level multiplication (handles sign) */ +int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + fp_mul(a, b, c); + return MP_OKAY; +} + +/* d = a * b (mod c) */ +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + return fp_mulmod(a, b, c, d); +} + +/* c = a mod b, 0 <= c < b */ +int mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + return fp_mod (a, b, c); +} + +/* hac 14.61, pp608 */ +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + return fp_invmod(a, b, c); +} + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + return fp_exptmod(G, X, P, Y); +} + +/* compare two ints (signed)*/ +int mp_cmp (mp_int * a, mp_int * b) +{ + return fp_cmp(a, b); +} + +/* compare a digit */ +int mp_cmp_d(mp_int * a, mp_digit b) +{ + return fp_cmp_d(a, b); +} + +/* get the size for an unsigned equivalent */ +int mp_unsigned_bin_size (mp_int * a) +{ + return fp_unsigned_bin_size(a); +} + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + fp_to_unsigned_bin(a,b); + return MP_OKAY; +} + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + fp_read_unsigned_bin(a, (unsigned char *)b, c); + return MP_OKAY; +} + + +int mp_sub_d(fp_int *a, fp_digit b, fp_int *c) +{ + fp_sub_d(a, b, c); + return MP_OKAY; +} + + +/* fast math conversion */ +int mp_copy(fp_int* a, fp_int* b) +{ + fp_copy(a, b); + return MP_OKAY; +} + + +/* fast math conversion */ +int mp_isodd(mp_int* a) +{ + return fp_isodd(a); +} + + +/* fast math conversion */ +int mp_iszero(mp_int* a) +{ + return fp_iszero(a); +} + + +/* fast math conversion */ +int mp_count_bits (mp_int* a) +{ + return fp_count_bits(a); +} + + +int mp_leading_bit (mp_int* a) +{ + return fp_leading_bit(a); +} + + +/* fast math conversion */ +void mp_rshb (mp_int* a, int x) +{ + fp_rshb(a, x); +} + + +/* fast math wrappers */ +int mp_set_int(fp_int *a, fp_digit b) +{ + fp_set(a, b); + return MP_OKAY; +} + + +#if defined(CYASSL_KEY_GEN) || defined (HAVE_ECC) + +/* c = a * a (mod b) */ +int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c) +{ + fp_int tmp; + fp_zero(&tmp); + fp_sqr(a, &tmp); + return fp_mod(&tmp, b, c); +} + +/* fast math conversion */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c) +{ + return fp_sqrmod(a, b, c); +} + +/* fast math conversion */ +int mp_montgomery_calc_normalization(mp_int *a, mp_int *b) +{ + fp_montgomery_calc_normalization(a, b); + return MP_OKAY; +} + +#endif /* CYASSL_KEYGEN || HAVE_ECC */ + + +#if defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int fp_cnt_lsb(fp_int *a) +{ + int x; + fp_digit q, qq; + + /* easy out */ + if (fp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + + + + +static int s_is_power_of_two(fp_digit b, int *p) +{ + int x; + + /* fast return if no power of two */ + if ((b==0) || (b & (b-1))) { + return 0; + } + + for (x = 0; x < DIGIT_BIT; x++) { + if (b == (((fp_digit)1)< cb + d == a */ +static int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d) +{ + fp_int q; + fp_word w; + fp_digit t; + int ix; + + /* cannot divide by zero */ + if (b == 0) { + return FP_VAL; + } + + /* quick outs */ + if (b == 1 || fp_iszero(a) == 1) { + if (d != NULL) { + *d = 0; + } + if (c != NULL) { + fp_copy(a, c); + } + return FP_OKAY; + } + + /* power of two ? */ + if (s_is_power_of_two(b, &ix) == 1) { + if (d != NULL) { + *d = a->dp[0] & ((((fp_digit)1)<used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((fp_word)DIGIT_BIT)) | ((fp_word)a->dp[ix]); + + if (w >= b) { + t = (fp_digit)(w / b); + w -= ((fp_word)t) * ((fp_word)b); + } else { + t = 0; + } + q.dp[ix] = (fp_digit)t; + } + + if (d != NULL) { + *d = (fp_digit)w; + } + + if (c != NULL) { + fp_clamp(&q); + fp_copy(&q, c); + } + + return FP_OKAY; +} + + +/* c = a mod b, 0 <= c < b */ +static int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c) +{ + return fp_div_d(a, b, NULL, c); +} + +int mp_mod_d(fp_int *a, fp_digit b, fp_digit *c) +{ + return fp_mod_d(a, b, c); +} + +#endif /* defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) */ + +#ifdef CYASSL_KEY_GEN + +void fp_gcd(fp_int *a, fp_int *b, fp_int *c); +void fp_lcm(fp_int *a, fp_int *b, fp_int *c); +int fp_isprime(fp_int *a); + +int mp_gcd(fp_int *a, fp_int *b, fp_int *c) +{ + fp_gcd(a, b, c); + return MP_OKAY; +} + + +int mp_lcm(fp_int *a, fp_int *b, fp_int *c) +{ + fp_lcm(a, b, c); + return MP_OKAY; +} + + +int mp_prime_is_prime(mp_int* a, int t, int* result) +{ + (void)t; + *result = fp_isprime(a); + return MP_OKAY; +} + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +static void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result) +{ + fp_int n1, y, r; + int s, j; + + /* default */ + *result = FP_NO; + + /* ensure b > 1 */ + if (fp_cmp_d(b, 1) != FP_GT) { + return; + } + + /* get n1 = a - 1 */ + fp_init_copy(&n1, a); + fp_sub_d(&n1, 1, &n1); + + /* set 2**s * r = n1 */ + fp_init_copy(&r, &n1); + + /* count the number of least significant bits + * which are zero + */ + s = fp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + fp_div_2d (&r, s, &r, NULL); + + /* compute y = b**r mod a */ + fp_init(&y); + fp_exptmod(b, &r, a, &y); + + /* if y != 1 and y != n1 do */ + if (fp_cmp_d (&y, 1) != FP_EQ && fp_cmp (&y, &n1) != FP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && fp_cmp (&y, &n1) != FP_EQ) { + fp_sqrmod (&y, a, &y); + + /* if y == 1 then composite */ + if (fp_cmp_d (&y, 1) == FP_EQ) { + return; + } + ++j; + } + + /* if y != n1 then composite */ + if (fp_cmp (&y, &n1) != FP_EQ) { + return; + } + } + + /* probably prime now */ + *result = FP_YES; +} + + +/* a few primes */ +static const fp_digit primes[256] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +}; + +int fp_isprime(fp_int *a) +{ + fp_int b; + fp_digit d = 0; + int r, res; + + /* do trial division */ + for (r = 0; r < 256; r++) { + fp_mod_d(a, primes[r], &d); + if (d == 0) { + return FP_NO; + } + } + + /* now do 8 miller rabins */ + fp_init(&b); + for (r = 0; r < 8; r++) { + fp_set(&b, primes[r]); + fp_prime_miller_rabin(a, &b, &res); + if (res == FP_NO) { + return FP_NO; + } + } + return FP_YES; +} + + +/* c = [a, b] */ +void fp_lcm(fp_int *a, fp_int *b, fp_int *c) +{ + fp_int t1, t2; + + fp_init(&t1); + fp_init(&t2); + fp_gcd(a, b, &t1); + if (fp_cmp_mag(a, b) == FP_GT) { + fp_div(a, &t1, &t2, NULL); + fp_mul(b, &t2, c); + } else { + fp_div(b, &t1, &t2, NULL); + fp_mul(a, &t2, c); + } +} + + + +/* c = (a, b) */ +void fp_gcd(fp_int *a, fp_int *b, fp_int *c) +{ + fp_int u, v, r; + + /* either zero than gcd is the largest */ + if (fp_iszero (a) == 1 && fp_iszero (b) == 0) { + fp_abs (b, c); + return; + } + if (fp_iszero (a) == 0 && fp_iszero (b) == 1) { + fp_abs (a, c); + return; + } + + /* optimized. At this point if a == 0 then + * b must equal zero too + */ + if (fp_iszero (a) == 1) { + fp_zero(c); + return; + } + + /* sort inputs */ + if (fp_cmp_mag(a, b) != FP_LT) { + fp_init_copy(&u, a); + fp_init_copy(&v, b); + } else { + fp_init_copy(&u, b); + fp_init_copy(&v, a); + } + + fp_zero(&r); + while (fp_iszero(&v) == FP_NO) { + fp_mod(&u, &v, &r); + fp_copy(&v, &u); + fp_copy(&r, &v); + } + fp_copy(&u, c); +} + +#endif /* CYASSL_KEY_GEN */ + + +#if defined(HAVE_ECC) || !defined(NO_PWDBASED) +/* c = a + b */ +void fp_add_d(fp_int *a, fp_digit b, fp_int *c) +{ + fp_int tmp; + fp_set(&tmp, b); + fp_add(a,&tmp,c); +} + +/* external compatibility */ +int mp_add_d(fp_int *a, fp_digit b, fp_int *c) +{ + fp_add_d(a, b, c); + return MP_OKAY; +} + +#endif /* HAVE_ECC || !NO_PWDBASED */ + + +#ifdef HAVE_ECC + +/* chars used in radix conversions */ +static const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +static int fp_read_radix(fp_int *a, const char *str, int radix) +{ + int y, neg; + char ch; + + /* make sure the radix is ok */ + if (radix < 2 || radix > 64) { + return FP_VAL; + } + + /* if the leading digit is a + * minus set the sign to negative. + */ + if (*str == '-') { + ++str; + neg = FP_NEG; + } else { + neg = FP_ZPOS; + } + + /* set the integer to the default of zero */ + fp_zero (a); + + /* process each digit of the string */ + while (*str) { + /* if the radix < 36 the conversion is case insensitive + * this allows numbers like 1AB and 1ab to represent the same value + * [e.g. in hex] + */ + ch = (char) ((radix < 36) ? XTOUPPER(*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == fp_s_rmap[y]) { + break; + } + } + + /* if the char was found in the map + * and is less than the given radix add it + * to the number, otherwise exit the loop. + */ + if (y < radix) { + fp_mul_d (a, (fp_digit) radix, a); + fp_add_d (a, (fp_digit) y, a); + } else { + break; + } + ++str; + } + + /* set the sign only if a != 0 */ + if (fp_iszero(a) != FP_YES) { + a->sign = neg; + } + return FP_OKAY; +} + +/* fast math conversion */ +int mp_read_radix(mp_int *a, const char *str, int radix) +{ + return fp_read_radix(a, str, radix); +} + +/* fast math conversion */ +int mp_set(fp_int *a, fp_digit b) +{ + fp_set(a,b); + return MP_OKAY; +} + +/* fast math conversion */ +int mp_sqr(fp_int *A, fp_int *B) +{ + fp_sqr(A, B); + return MP_OKAY; +} + +/* fast math conversion */ +int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +{ + fp_montgomery_reduce(a, m, mp); + return MP_OKAY; +} + + +/* fast math conversion */ +int mp_montgomery_setup(fp_int *a, fp_digit *rho) +{ + return fp_montgomery_setup(a, rho); +} + +int mp_div_2(fp_int * a, fp_int * b) +{ + fp_div_2(a, b); + return MP_OKAY; +} + + +int mp_init_copy(fp_int * a, fp_int * b) +{ + fp_init_copy(a, b); + return MP_OKAY; +} + + +#ifdef HAVE_COMP_KEY + +int mp_cnt_lsb(fp_int* a) +{ + fp_cnt_lsb(a); + return MP_OKAY; +} + +int mp_div_2d(fp_int* a, int b, fp_int* c, fp_int* d) +{ + fp_div_2d(a, b, c, d); + return MP_OKAY; +} + +#endif /* HAVE_COMP_KEY */ + + +#endif /* HAVE_ECC */ + +#endif /* USE_FAST_MATH */ diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index bfb0d7b75..21a62ce20 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -21,12 +21,12 @@ #ifdef HAVE_ECC -#ifndef CTAO_CRYPT_ECC_H -#define CTAO_CRYPT_ECC_H +#ifndef WOLF_CRYPT_ECC_H +#define WOLF_CRYPT_ECC_H -#include -#include -#include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -83,50 +83,50 @@ typedef struct { extern const ecc_set_type ecc_sets[]; -CYASSL_API -int ecc_make_key(RNG* rng, int keysize, ecc_key* key); -CYASSL_API -int ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, +WOLFSSL_API +int wc_ecc_make_key(RNG* rng, int keysize, ecc_key* key); +WOLFSSL_API +int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, word32* outlen); -CYASSL_API -int ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, +WOLFSSL_API +int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, RNG* rng, ecc_key* key); -CYASSL_API -int ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, +WOLFSSL_API +int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, word32 hashlen, int* stat, ecc_key* key); -CYASSL_API -void ecc_init(ecc_key* key); -CYASSL_API -void ecc_free(ecc_key* key); -CYASSL_API -void ecc_fp_free(void); +WOLFSSL_API +void wc_ecc_init(ecc_key* key); +WOLFSSL_API +void wc_ecc_free(ecc_key* key); +WOLFSSL_API +void wc_ecc_fp_free(void); /* ASN key helpers */ -CYASSL_API -int ecc_export_x963(ecc_key*, byte* out, word32* outLen); -CYASSL_API -int ecc_export_x963_ex(ecc_key*, byte* out, word32* outLen, int compressed); +WOLFSSL_API +int wc_ecc_export_x963(ecc_key*, byte* out, word32* outLen); +WOLFSSL_API +int wc_ecc_export_x963_ex(ecc_key*, byte* out, word32* outLen, int compressed); /* extended functionality with compressed option */ -CYASSL_API -int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key); -CYASSL_API -int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, +WOLFSSL_API +int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key); +WOLFSSL_API +int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, word32 pubSz, ecc_key* key); -CYASSL_API -int ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen); -CYASSL_API -int ecc_import_raw(ecc_key* key, const char* qx, const char* qy, +WOLFSSL_API +int wc_ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen); +WOLFSSL_API +int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, const char* d, const char* curveName); -CYASSL_API -int ecc_export_private_only(ecc_key* key, byte* out, word32* outLen); +WOLFSSL_API +int wc_ecc_export_private_only(ecc_key* key, byte* out, word32* outLen); /* size helper */ -CYASSL_API -int ecc_size(ecc_key* key); -CYASSL_API -int ecc_sig_size(ecc_key* key); +WOLFSSL_API +int wc_ecc_size(ecc_key* key); +WOLFSSL_API +int wc_ecc_sig_size(ecc_key* key); #ifdef HAVE_ECC_ENCRYPT @@ -163,25 +163,25 @@ enum ecFlags { typedef struct ecEncCtx ecEncCtx; -CYASSL_API -ecEncCtx* ecc_ctx_new(int flags, RNG* rng); -CYASSL_API -void ecc_ctx_free(ecEncCtx*); -CYASSL_API -int ecc_ctx_reset(ecEncCtx*, RNG*); /* reset for use again w/o alloc/free */ +WOLFSSL_API +ecEncCtx* wc_ecc_ctx_new(int flags, RNG* rng); +WOLFSSL_API +void wc_ecc_ctx_free(ecEncCtx*); +WOLFSSL_API +int wc_ecc_ctx_reset(ecEncCtx*, RNG*); /* reset for use again w/o alloc/free */ -CYASSL_API -const byte* ecc_ctx_get_own_salt(ecEncCtx*); -CYASSL_API -int ecc_ctx_set_peer_salt(ecEncCtx*, const byte* salt); -CYASSL_API -int ecc_ctx_set_info(ecEncCtx*, const byte* info, int sz); +WOLFSSL_API +const byte* wc_ecc_ctx_get_own_salt(ecEncCtx*); +WOLFSSL_API +int wc_ecc_ctx_set_peer_salt(ecEncCtx*, const byte* salt); +WOLFSSL_API +int wc_ecc_ctx_set_info(ecEncCtx*, const byte* info, int sz); -CYASSL_API -int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, +WOLFSSL_API +int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx); -CYASSL_API -int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, +WOLFSSL_API +int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx); #endif /* HAVE_ECC_ENCRYPT */ @@ -190,5 +190,5 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, } /* extern "C" */ #endif -#endif /* CTAO_CRYPT_ECC_H */ +#endif /* WOLF_CRYPT_ECC_H */ #endif /* HAVE_ECC */ diff --git a/wolfssl/wolfcrypt/hmac.h b/wolfssl/wolfcrypt/hmac.h index f2e4bd6bf..6aae0670d 100644 --- a/wolfssl/wolfcrypt/hmac.h +++ b/wolfssl/wolfcrypt/hmac.h @@ -52,7 +52,7 @@ WOLFSSL_API int wc_HmacFinal(Hmac*, byte*); WOLFSSL_API void wc_HmacFreeCavium(Hmac*); #endif -WOLFSSL_API int wc_WolfSSL_GetHmacMaxSize(void); +WOLFSSL_API int wc_wolfSSL_GetHmacMaxSize(void); #ifdef HAVE_HKDF