From be318abbc20d120b543d993d937ad2dbe67a2a08 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 24 Aug 2018 16:10:51 -0700 Subject: [PATCH 01/11] Fixes for building with `WOLFSSL_ATECC508A` with latest atca. --- wolfcrypt/src/port/atmel/atmel.c | 8 ++++---- wolfssl/wolfcrypt/port/atmel/atmel.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index c5e5d95af..e45a716ba 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -92,7 +92,7 @@ int atmel_get_random_number(uint32_t count, uint8_t* rand_out) XMEMCPY(&rand_out[i], rng_buffer, copy_count); i += copy_count; } - atcab_printbin_label((const uint8_t*)"\r\nRandom Number", rand_out, count); + atcab_printbin_label((const char*)"\r\nRandom Number", rand_out, count); #else // TODO: Use on-board TRNG #endif @@ -156,7 +156,7 @@ void atmel_ecc_free(int slot) /** * \brief Give enc key to read pms. */ -static int atmel_set_enc_key(uint8_t* enckey, int16_t keysize) +static ATCA_STATUS atmel_get_enc_key(uint8_t* enckey, int16_t keysize) { if (enckey == NULL || keysize != ATECC_KEY_SIZE) { return -1; @@ -177,13 +177,13 @@ static int atmel_init_enc_key(void) uint8_t read_key[ATECC_KEY_SIZE] = { 0 }; XMEMSET(read_key, 0xFF, sizeof(read_key)); - ret = atcab_write_bytes_slot(TLS_SLOT_ENC_PARENT, 0, read_key, sizeof(read_key)); + ret = atcatls_set_enckey(read_key, TLS_SLOT_ENC_PARENT, 0); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to write key"); return -1; } - ret = atcatlsfn_set_get_enckey(atmel_set_enc_key); + ret = atcatlsfn_set_get_enckey(atmel_get_enc_key); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to set enckey"); return -1; diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index d021c6f04..209ab55bb 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -26,7 +26,6 @@ #include #include -#include #include #ifdef WOLFSSL_ATECC508A @@ -71,6 +70,7 @@ long atmel_get_curr_time_and_date(long* tm); int atmel_ecc_alloc(void); void atmel_ecc_free(int slot); +#include #ifdef HAVE_PK_CALLBACKS int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz, From e78ddfce75cbe8cdfcc06023c27add3141f93fa4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 6 Sep 2018 12:06:50 -0700 Subject: [PATCH 02/11] Fix for `wc_ecc_import_x963_ex` to handle ATECC508A raw public key. Cleanup of the ATECC508A encryption key support. Added new macro `ATCA_TLS_GET_ENC_KEY` to allow setting your own function at build-time for getting the encryption key. --- wolfcrypt/src/ecc.c | 5 +++++ wolfcrypt/src/port/atmel/atmel.c | 37 ++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index b2db1674c..e32da813a 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6329,6 +6329,11 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, inLen -= 1; in += 1; +#ifdef WOLFSSL_ATECC508A + /* populate key->pubkey_raw */ + XMEMCPY(key->pubkey_raw, (byte*)in, sizeof(key->pubkey_raw)); +#endif + if (err == MP_OKAY) { #ifdef HAVE_COMP_KEY /* adjust inLen if compressed */ diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index e45a716ba..d3b1dcbf4 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -153,20 +153,24 @@ void atmel_ecc_free(int slot) } -/** - * \brief Give enc key to read pms. - */ -static ATCA_STATUS atmel_get_enc_key(uint8_t* enckey, int16_t keysize) -{ - if (enckey == NULL || keysize != ATECC_KEY_SIZE) { - return -1; +/* The macros ATCA_TLS_GET_ENC_KEY can be set to override the default + encryption key with your own at build-time */ +#ifndef ATCA_TLS_GET_ENC_KEY + #define ATCA_TLS_GET_ENC_KEY atmel_get_enc_key + /** + * \brief Give enc key to read pms. + */ + static ATCA_STATUS atmel_get_enc_key(uint8_t* enckey, int16_t keysize) + { + if (enckey == NULL || keysize != ATECC_KEY_SIZE) { + return -1; + } + + XMEMSET(enckey, 0xFF, keysize); // use default values + + return ATCA_SUCCESS; } - - XMEMSET(enckey, 0xFF, keysize); // use default values - - return SSL_SUCCESS; -} - +#endif /** * \brief Write enc key before. @@ -174,16 +178,17 @@ static ATCA_STATUS atmel_get_enc_key(uint8_t* enckey, int16_t keysize) static int atmel_init_enc_key(void) { uint8_t ret = 0; - uint8_t read_key[ATECC_KEY_SIZE] = { 0 }; + uint8_t read_key[ATECC_KEY_SIZE]; + + ATCA_TLS_GET_ENC_KEY(read_key, sizeof(read_key)); - XMEMSET(read_key, 0xFF, sizeof(read_key)); ret = atcatls_set_enckey(read_key, TLS_SLOT_ENC_PARENT, 0); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to write key"); return -1; } - ret = atcatlsfn_set_get_enckey(atmel_get_enc_key); + ret = atcatlsfn_set_get_enckey(ATCA_TLS_GET_ENC_KEY); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to set enckey"); return -1; From 7074625048c63c65652c83ce436b7dbbfc14fa90 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 6 Sep 2018 12:40:17 -0700 Subject: [PATCH 03/11] Added slot callbacks. Improvements for the Atmel time support. Fix to make sure read encryption key is cleared from stack buffer. --- wolfcrypt/src/port/atmel/atmel.c | 108 +++++++++++++++++++-------- wolfssl/wolfcrypt/port/atmel/atmel.h | 12 ++- 2 files changed, 85 insertions(+), 35 deletions(-) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index d3b1dcbf4..41aee3d11 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -32,7 +32,15 @@ #include #include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + #ifdef WOLFSSL_ATMEL +/* remap name conflicts */ #define Aes Aes_Remap #define Gmac Gmac_Remap #include "asf.h" @@ -46,7 +54,9 @@ static bool mAtcaInitDone = 0; #ifdef WOLFSSL_ATECC508A -/* List of available key slots */ +/* Free slot handling */ +static atmel_slot_alloc_cb mSlotAlloc; +static atmel_slot_dealloc_cb mSlotDealloc; static int mSlotList[ATECC_MAX_SLOT+1]; /** @@ -60,9 +70,6 @@ t_atcert atcert = { .end_user = { 0 }, .end_user_pubkey = { 0 } }; - -static int atmel_init_enc_key(void); - #endif /* WOLFSSL_ATECC508A */ @@ -94,7 +101,7 @@ int atmel_get_random_number(uint32_t count, uint8_t* rand_out) } atcab_printbin_label((const char*)"\r\nRandom Number", rand_out, count); #else - // TODO: Use on-board TRNG + /* TODO: Use on-board TRNG */ #endif return ret; } @@ -104,50 +111,88 @@ int atmel_get_random_block(unsigned char* output, unsigned int sz) return atmel_get_random_number((uint32_t)sz, (uint8_t*)output); } -#ifdef WOLFSSL_ATMEL_TIME -extern struct rtc_module *_rtc_instance[RTC_INST_NUM]; +#if defined(WOLFSSL_ATMEL) && defined(WOLFSSL_ATMEL_TIME) + extern struct rtc_module *_rtc_instance[RTC_INST_NUM]; #endif long atmel_get_curr_time_and_date(long* tm) { - (void)tm; - -#ifdef WOLFSSL_ATMEL_TIME + long rt = 0; +#if defined(WOLFSSL_ATMEL) && defined(WOLFSSL_ATMEL_TIME) /* Get current time */ + struct rtc_calendar_time rtcTime; + const int monthDay[] = {0,31,59,90,120,151,181,212,243,273,304,334}; + int month, year, yearLeap; - //struct rtc_calendar_time rtcTime; - //rtc_calendar_get_time(_rtc_instance[0], &rtcTime); + rtc_calendar_get_time(_rtc_instance[0], &rtcTime); /* Convert rtc_calendar_time to seconds since UTC */ -#endif - - return 0; + month = rtcTime.month % 12; + year = rtcTime.year + rtcTime.month / 12; + if (month < 0) { + month += 12; + year--; + } + yearLeap = (month > 1) ? year + 1 : year; + rt = rtcTime.second + + 60 * (rtcTime.minute + + 60 * (rtcTime.hour + + 24 * (monthDay[month] + rtcTime.day - 1 + + 365 * (year - 70) + + (yearLeap - 69) / 4 + - (yearLeap - 1) / 100 + + (yearLeap + 299) / 400 + ) + ) + ); +#endif /* WOLFSSL_ATMEL_TIME */ + (void)tm; + return rt; } #ifdef WOLFSSL_ATECC508A +/* Function to set the slot allocator and deallocator */ +int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, + atmel_slot_dealloc_cb dealloc) +{ + mSlotAlloc = alloc; + mSlotDealloc = dealloc; + return 0; +} + /* Function to allocate new slot number */ int atmel_ecc_alloc(void) { - int i, slot = -1; - for (i=0; i <= ATECC_MAX_SLOT; i++) { - /* Find free slot */ - if (mSlotList[i] == ATECC_INVALID_SLOT) { - mSlotList[i] = i; - slot = i; - break; + int slot = ATECC_INVALID_SLOT; + + if (mSlotAlloc) { + slot = mSlotAlloc(); + } + else { + int i; + for (i=0; i <= ATECC_MAX_SLOT; i++) { + /* Find free slot */ + if (mSlotList[i] == ATECC_INVALID_SLOT) { + mSlotList[i] = i; + slot = i; + break; + } } } return slot; } -/* Function to return slot number to avail list */ +/* Function to return slot number to available list */ void atmel_ecc_free(int slot) { - if (slot >= 0 && slot <= ATECC_MAX_SLOT) { - /* Mark slot of free */ + if (mSlotDealloc) { + mSlotDealloc(slot); + } + else if (slot >= 0 && slot <= ATECC_MAX_SLOT) { + /* Mark slot free */ mSlotList[slot] = ATECC_INVALID_SLOT; } } @@ -158,15 +203,15 @@ void atmel_ecc_free(int slot) #ifndef ATCA_TLS_GET_ENC_KEY #define ATCA_TLS_GET_ENC_KEY atmel_get_enc_key /** - * \brief Give enc key to read pms. + * \brief Callback function for getting the current encryption key */ static ATCA_STATUS atmel_get_enc_key(uint8_t* enckey, int16_t keysize) { if (enckey == NULL || keysize != ATECC_KEY_SIZE) { - return -1; + return ATCA_BAD_PARAM; } - XMEMSET(enckey, 0xFF, keysize); // use default values + XMEMSET(enckey, 0xFF, keysize); /* use default value */ return ATCA_SUCCESS; } @@ -180,9 +225,10 @@ static int atmel_init_enc_key(void) uint8_t ret = 0; uint8_t read_key[ATECC_KEY_SIZE]; + /* get encryption key */ ATCA_TLS_GET_ENC_KEY(read_key, sizeof(read_key)); - ret = atcatls_set_enckey(read_key, TLS_SLOT_ENC_PARENT, 0); + ForceZero(read_key, sizeof(read_key)); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to write key"); return -1; @@ -190,7 +236,7 @@ static int atmel_init_enc_key(void) ret = atcatlsfn_set_get_enckey(ATCA_TLS_GET_ENC_KEY); if (ret != ATCA_SUCCESS) { - WOLFSSL_MSG("Failed to set enckey"); + WOLFSSL_MSG("Failed to set enckey cb"); return -1; } @@ -199,7 +245,7 @@ static int atmel_init_enc_key(void) static void atmel_show_rev_info(void) { -#if 0 +#ifdef WOLFSSL_ATECC508A_DEBUG uint32_t revision = 0; atcab_info((uint8_t*)&revision); printf("ATECC508A Revision: %x\n", (unsigned int)revision); diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index 209ab55bb..d9493d0b5 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -48,7 +48,7 @@ struct WOLFSSL; struct WOLFSSL_X509_STORE_CTX; -// Cert Structure +/* Cert Structure */ typedef struct t_atcert { uint32_t signer_ca_size; uint8_t signer_ca[512]; @@ -60,16 +60,20 @@ typedef struct t_atcert { extern t_atcert atcert; - /* Amtel port functions */ void atmel_init(void); void atmel_finish(void); -int atmel_get_random_number(uint32_t count, uint8_t* rand_out); +int atmel_get_random_number(uint32_t count, uint8_t* rand_out); long atmel_get_curr_time_and_date(long* tm); -int atmel_ecc_alloc(void); +int atmel_ecc_alloc(void); void atmel_ecc_free(int slot); +typedef int (*atmel_slot_alloc_cb)(void); +typedef void (*atmel_slot_dealloc_cb)(int); +int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, + atmel_slot_dealloc_cb dealloc); + #include #ifdef HAVE_PK_CALLBACKS From 53c22643270283bd4a7587275b5a65e73ace1a25 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 7 Sep 2018 12:39:27 -0700 Subject: [PATCH 04/11] Fix for checking the inLen when setting raw public key len for hardware. Finished the ATECC508A ECC functions to support native TLS with the WOLFSSL_ATECC508A option and SECP256R1. Added slot type for alloc/free. Added helper functions for setting the PK callbacks and custom content. Updated the README.md with build options. Added support for overriding the ATECC_MAX_SLOT. Added overridable define for encryption slot number `ATECC_SLOT_I2C_ENC`. Added new build option `WOLFSSL_ATECC_PKCB` for using just the reference PK callbacks. --- wolfcrypt/src/ecc.c | 103 +++++++++++---------------- wolfcrypt/src/port/atmel/README.md | 35 ++++++--- wolfcrypt/src/port/atmel/atmel.c | 66 ++++++++++++----- wolfssl/wolfcrypt/port/atmel/atmel.h | 39 +++++++--- 4 files changed, 149 insertions(+), 94 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index e32da813a..cc1d28a14 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -3381,12 +3381,20 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, } #ifdef WOLFSSL_ATECC508A - err = atcatls_ecdh(private_key->slot, public_key->pubkey_raw, out); - if (err != ATCA_SUCCESS) { - err = BAD_COND_E; + /* For SECP256R1 use hardware */ + if (private_key->dp->id == ECC_SECP256R1) { + err = atcatls_ecdh(private_key->slot, public_key->pubkey_raw, out); + if (err != ATCA_SUCCESS) { + err = BAD_COND_E; + } + *outlen = private_key->dp->size; } - *outlen = private_key->dp->size; + else { + err = NOT_COMPILED_IN; + } + #else + err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen); #endif /* WOLFSSL_ATECC508A */ @@ -3751,7 +3759,7 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, #endif ecc_point* pub; DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); -#endif +#endif /* !WOLFSSL_ATECC508A */ if (key == NULL) { return BAD_FUNC_ARG; @@ -3851,9 +3859,7 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, /* free up local curve */ if (curveIn == NULL) { wc_ecc_curve_free(curve); - #ifndef WOLFSSL_ATECC508A FREE_CURVE_SPECS(); - #endif } #else @@ -3893,7 +3899,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) #ifndef WOLFSSL_SP_MATH DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); #endif -#endif +#endif /* !WOLFSSL_ATECC508A */ if (key == NULL || rng == NULL) { return BAD_FUNC_ARG; @@ -3993,9 +3999,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) /* cleanup allocations */ wc_ecc_curve_free(curve); - #ifndef WOLFSSL_ATECC508A FREE_CURVE_SPECS(); - #endif #endif /* WOLFSSL_SP_MATH */ } @@ -4097,7 +4101,7 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) #endif #ifdef WOLFSSL_ATECC508A - key->slot = atmel_ecc_alloc(); + key->slot = atmel_ecc_alloc(ATMEL_SLOT_ANY); if (key->slot == ATECC_INVALID_SLOT) { return ECC_BAD_ARG_E; } @@ -5563,7 +5567,6 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx, ecc_point* point) { int err = 0; -#ifndef WOLFSSL_ATECC508A int compressed = 0; int keysize; byte pointType; @@ -5613,11 +5616,6 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx, /* calculate key size based on inLen / 2 */ keysize = inLen>>1; -#ifdef WOLFSSL_ATECC508A - /* populate key->pubkey_raw */ - XMEMCPY(key->pubkey_raw, (byte*)in, sizeof(key->pubkey_raw)); -#endif - /* read data */ if (err == MP_OKAY) err = mp_read_unsigned_bin(point->x, (byte*)in, keysize); @@ -5697,14 +5695,6 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx, mp_clear(point->z); } -#else - err = NOT_COMPILED_IN; - (void)in; - (void)inLen; - (void)curve_idx; - (void)point; -#endif /* !WOLFSSL_ATECC508A */ - return err; } #endif /* HAVE_ECC_KEY_IMPORT */ @@ -5716,13 +5706,11 @@ int wc_ecc_export_point_der(const int curve_idx, ecc_point* point, byte* out, { int ret = MP_OKAY; word32 numlen; -#ifndef WOLFSSL_ATECC508A #ifdef WOLFSSL_SMALL_STACK byte* buf; #else byte buf[ECC_BUFSIZE]; #endif -#endif /* !WOLFSSL_ATECC508A */ if ((curve_idx < 0) || (wc_ecc_is_valid_idx(curve_idx) == 0)) return ECC_BAD_ARG_E; @@ -5744,12 +5732,6 @@ int wc_ecc_export_point_der(const int curve_idx, ecc_point* point, byte* out, return BUFFER_E; } -#ifdef WOLFSSL_ATECC508A - /* TODO: Implement equiv call to ATECC508A */ - ret = BAD_COND_E; - -#else - /* store byte point type */ out[0] = ECC_POINT_UNCOMP; @@ -5781,7 +5763,6 @@ done: #ifdef WOLFSSL_SMALL_STACK XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER); #endif -#endif /* WOLFSSL_ATECC508A */ return ret; } @@ -6080,8 +6061,8 @@ static int ecc_check_privkey_gen_helper(ecc_key* key) return BAD_FUNC_ARG; #ifdef WOLFSSL_ATECC508A - /* TODO: Implement equiv call to ATECC508A */ - err = BAD_COND_E; + /* Hardware based private key, so this operation is not supported */ + err = MP_OKAY; /* just report success */ #else ALLOC_CURVE_SPECS(2); @@ -6173,7 +6154,7 @@ int wc_ecc_check_key(ecc_key* key) if (key->slot == ATECC_INVALID_SLOT) return ECC_BAD_ARG_E; - err = 0; /* consider key check success on ECC508A */ + err = 0; /* consider key check success on ATECC508A */ #else #ifdef USE_ECC_B_PARAM @@ -6330,8 +6311,11 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, in += 1; #ifdef WOLFSSL_ATECC508A - /* populate key->pubkey_raw */ - XMEMCPY(key->pubkey_raw, (byte*)in, sizeof(key->pubkey_raw)); + /* For SECP256R1 only save raw public key for hardware */ + if (curve_id == ECC_SECP256R1 && !compressed && + inLen <= sizeof(key->pubkey_raw)) { + XMEMCPY(key->pubkey_raw, (byte*)in, sizeof(key->pubkey_raw)); + } #endif if (err == MP_OKAY) { @@ -6471,7 +6455,7 @@ int wc_ecc_export_ex(ecc_key* key, byte* qx, word32* qxLen, #ifdef WOLFSSL_ATECC508A /* Hardware cannot export private portion */ - return BAD_COND_E; + return NOT_COMPILED_IN; #else err = wc_export_int(&key->k, d, dLen, keySz, encType); if (err != MP_OKAY) @@ -6572,8 +6556,8 @@ int wc_ecc_import_private_key_ex(const byte* priv, word32 privSz, return ret; #ifdef WOLFSSL_ATECC508A - /* TODO: Implement equiv call to ATECC508A */ - return BAD_COND_E; + /* Hardware does not support loading private keys */ + return NOT_COMPILED_IN; #else @@ -6835,14 +6819,6 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, return err; } -#ifdef WOLFSSL_ATECC508A - /* TODO: Implement equiv call to ATECC508A */ - err = BAD_COND_E; - (void)d; - (void)encType; - -#else - /* init key */ #ifdef ALT_ECC_SIZE key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; @@ -6881,9 +6857,25 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, if (err == MP_OKAY) err = mp_set(key->pubkey.z, 1); +#ifdef WOLFSSL_ATECC508A + /* For SECP256R1 only save raw public key for hardware */ + if (err == MP_OKAY && curve_id == ECC_SECP256R1) { + word32 keySz = key->dp->size; + err = wc_export_int(key->pubkey.x, key->pubkey_raw, + &keySz, keySz, WC_TYPE_UNSIGNED_BIN); + if (err == MP_OKAY) + err = wc_export_int(key->pubkey.y, &key->pubkey_raw[keySz], + &keySz, keySz, WC_TYPE_UNSIGNED_BIN); + } +#endif + /* import private key */ if (err == MP_OKAY) { if (d != NULL) { + #ifdef WOLFSSL_ATECC508A + /* Hardware doesn't support loading private key */ + err = NOT_COMPILED_IN; + #else key->type = ECC_PRIVATEKEY; if (encType == WC_TYPE_HEX_STR) @@ -6891,7 +6883,7 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, else err = mp_read_unsigned_bin(&key->k, (const byte*)d, key->dp->size); - + #endif /* WOLFSSL_ATECC508A */ } else { key->type = ECC_PUBLICKEY; } @@ -6908,7 +6900,6 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, mp_clear(key->pubkey.z); mp_clear(&key->k); } -#endif /* WOLFSSL_ATECC508A */ return err; } @@ -9403,12 +9394,6 @@ static int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen return BUFFER_E; } -#ifdef WOLFSSL_ATECC508A - /* TODO: Implement equiv call to ATECC508A */ - ret = BAD_COND_E; - -#else - /* store first byte */ out[0] = mp_isodd(key->pubkey.y) == MP_YES ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN; @@ -9418,8 +9403,6 @@ static int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen out+1 + (numlen - mp_unsigned_bin_size(key->pubkey.x))); *outLen = 1 + numlen; -#endif /* WOLFSSL_ATECC508A */ - return ret; } diff --git a/wolfcrypt/src/port/atmel/README.md b/wolfcrypt/src/port/atmel/README.md index f67b29be9..0283ea767 100644 --- a/wolfcrypt/src/port/atmel/README.md +++ b/wolfcrypt/src/port/atmel/README.md @@ -1,17 +1,36 @@ -# Atmel ATECC508A Port +# Microchip/Atmel ATECC508A/ATECC608A Support -* Adds wolfCrypt support for ECC Hardware acceleration using the ATECC508A - * The new defines added for this port are: `WOLFSSL_ATMEL` and `WOLFSSL_ATECC508A`. -* Adds new PK callback for Pre Master Secret. +Support for ATECC508A using these methods: +* TLS: Using the PK callbacks and reference ATECC508A callbacks. See Coding section below. Requires options `HAVE_PK_CALLBACKS` and `WOLFSSL_ATECC_PKCB or WOLFSSL_ATECC508A` +* wolfCrypt: Native wc_ecc_* API's using the `./configure CFLAGS="-DWOLFSSL_ATECC508A"` or `#define WOLFSSL_ATECC508A`. + +## Dependency + +Requires the Microchip CryptoAuthLib. The examples in `wolfcrypt/src/port/atmel/atmel.c` make calls to the `atcatls_*` API's. ## Building -`./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_ATECC508A"` +### Build Options + +* `HAVE_PK_CALLBACKS`: Option for enabling wolfSSL's PK callback support for TLS. +* `WOLFSSL_ATECC508A`: Enables support for initializing the CryptoAuthLib and setting up the encryption key used for the I2C communication. +* `WOLFSSL_ATECC_PKCB`: Enables support for the reference PK callbacks without init. +* `WOLFSSL_ATMEL`: Enables ASF hooks seeding random data using the `atmel_get_random_number` function. +* `WOLFSSL_ATMEL_TIME`: Enables the built-in `atmel_get_curr_time_and_date` function get getting time from ASF RTC. +* `ATECC_GET_ENC_KEY`: Macro to define your own function for getting the encryption key. +* `ATECC_SLOT_I2C_ENC`: Macro for the default encryption key slot. Can also get via the slot callback with `ATMEL_SLOT_ENCKEY`. +* `ATECC_MAX_SLOT`: Macro for the maximum dynamically allocated slots. + +### Build Command Examples + +`./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_ATECC_PKCB"` +`#define HAVE_PK_CALLBACKS` +`#define WOLFSSL_ATECC_PKCB` or -`#define HAVE_PK_CALLBACKS` +`./configure CFLAGS="-DWOLFSSL_ATECC508A"` `#define WOLFSSL_ATECC508A` @@ -31,7 +50,7 @@ wolfSSL_CTX_SetEccSharedSecretCb(ctx, atcatls_create_pms_cb); The reference ATECC508A PK callback functions are located in the `wolfcrypt/src/port/atmel/atmel.c` file. -Adding a custom contex to the callbacks: +Adding a custom context to the callbacks: ``` /* Setup PK Callbacks context */ @@ -49,7 +68,7 @@ wolfSSL_SetEccSharedSecretCtx(ssl, myOwnCtx); TLS Establishment Times: -* Hardware accelerated ATECC508A: 2.342 seconds avgerage +* Hardware accelerated ATECC508A: 2.342 seconds average * Software only: 13.422 seconds average The TLS connection establishment time is 5.73 times faster with the ATECC508A. diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index 41aee3d11..7c1803882 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -25,7 +25,7 @@ #include -#if defined(WOLFSSL_ATMEL) || defined(WOLFSSL_ATECC508A) +#if defined(WOLFSSL_ATMEL) || defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC_PKCB) #include #include @@ -50,7 +50,7 @@ #include -static bool mAtcaInitDone = 0; +static int mAtcaInitDone = 0; #ifdef WOLFSSL_ATECC508A @@ -59,6 +59,10 @@ static atmel_slot_alloc_cb mSlotAlloc; static atmel_slot_dealloc_cb mSlotDealloc; static int mSlotList[ATECC_MAX_SLOT+1]; +#ifndef ATECC_SLOT_I2C_ENC + #define ATECC_SLOT_I2C_ENC 0x04 /* Slot holding symmetric encryption key */ +#endif + /** * \brief Structure to contain certificate information. */ @@ -112,12 +116,12 @@ int atmel_get_random_block(unsigned char* output, unsigned int sz) } #if defined(WOLFSSL_ATMEL) && defined(WOLFSSL_ATMEL_TIME) - extern struct rtc_module *_rtc_instance[RTC_INST_NUM]; -#endif +extern struct rtc_module *_rtc_instance[RTC_INST_NUM]; + long atmel_get_curr_time_and_date(long* tm) { long rt = 0; -#if defined(WOLFSSL_ATMEL) && defined(WOLFSSL_ATMEL_TIME) + /* Get current time */ struct rtc_calendar_time rtcTime; const int monthDay[] = {0,31,59,90,120,151,181,212,243,273,304,334}; @@ -144,11 +148,11 @@ long atmel_get_curr_time_and_date(long* tm) ) ) ); -#endif /* WOLFSSL_ATMEL_TIME */ + (void)tm; return rt; } - +#endif #ifdef WOLFSSL_ATECC508A @@ -163,15 +167,20 @@ int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, } /* Function to allocate new slot number */ -int atmel_ecc_alloc(void) +int atmel_ecc_alloc(int slotType) { int slot = ATECC_INVALID_SLOT; if (mSlotAlloc) { - slot = mSlotAlloc(); + slot = mSlotAlloc(slotType); } else { int i; + + if (slotType == ATMEL_SLOT_ENCKEY) { + return ATECC_SLOT_I2C_ENC; + } + for (i=0; i <= ATECC_MAX_SLOT; i++) { /* Find free slot */ if (mSlotList[i] == ATECC_INVALID_SLOT) { @@ -198,10 +207,11 @@ void atmel_ecc_free(int slot) } -/* The macros ATCA_TLS_GET_ENC_KEY can be set to override the default +/* The macros ATECC_GET_ENC_KEY can be set to override the default encryption key with your own at build-time */ -#ifndef ATCA_TLS_GET_ENC_KEY - #define ATCA_TLS_GET_ENC_KEY atmel_get_enc_key +#ifndef ATECC_GET_ENC_KEY + #define ATECC_GET_ENC_KEY atmel_get_enc_key + /** * \brief Callback function for getting the current encryption key */ @@ -224,17 +234,22 @@ static int atmel_init_enc_key(void) { uint8_t ret = 0; uint8_t read_key[ATECC_KEY_SIZE]; + int slot = atmel_ecc_alloc(ATMEL_SLOT_ENCKEY); + + /* check for encryption key slot */ + if (slot == ATECC_INVALID_SLOT) + return -1; /* get encryption key */ - ATCA_TLS_GET_ENC_KEY(read_key, sizeof(read_key)); - ret = atcatls_set_enckey(read_key, TLS_SLOT_ENC_PARENT, 0); + ATECC_GET_ENC_KEY(read_key, sizeof(read_key)); + ret = atcatls_set_enckey(read_key, slot, 0); ForceZero(read_key, sizeof(read_key)); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to write key"); return -1; } - ret = atcatlsfn_set_get_enckey(ATCA_TLS_GET_ENC_KEY); + ret = atcatlsfn_set_get_enckey(ATECC_GET_ENC_KEY); if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to set enckey cb"); return -1; @@ -549,6 +564,25 @@ exit: return ret; } +int atcatls_set_callbacks(WOLFSSL_CTX* ctx) +{ + wolfSSL_CTX_SetEccKeyGenCb(ctx, atcatls_create_key_cb); + wolfSSL_CTX_SetEccVerifyCb(ctx, atcatls_verify_signature_cb); + wolfSSL_CTX_SetEccSignCb(ctx, atcatls_sign_certificate_cb); + wolfSSL_CTX_SetEccSharedSecretCb(ctx, atcatls_create_pms_cb); + return 0; +} + +int atcatls_set_callback_ctx(WOLFSSL* ssl, void* user_ctx) +{ + wolfSSL_SetEccKeyGenCtx(ssl, user_ctx); + wolfSSL_SetEccVerifyCtx(ssl, user_ctx); + wolfSSL_SetEccSignCtx(ssl, user_ctx); + wolfSSL_SetEccSharedSecretCtx(ssl, user_ctx); + return 0; +} + + #endif /* HAVE_PK_CALLBACKS */ -#endif /* WOLFSSL_ATMEL || WOLFSSL_ATECC508A */ \ No newline at end of file +#endif /* WOLFSSL_ATMEL || WOLFSSL_ATECC508A || WOLFSSL_ATECC_PKCB */ diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index d9493d0b5..a65697893 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -1,4 +1,4 @@ -/* atecc508.h +/* atmel.h * * Copyright (C) 2006-2018 wolfSSL Inc. * @@ -25,10 +25,9 @@ #include #include -#include #include -#ifdef WOLFSSL_ATECC508A +#if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC_PKCB) #undef SHA_BLOCK_SIZE #define SHA_BLOCK_SIZE SHA_BLOCK_SIZE_REMAP #include @@ -42,11 +41,18 @@ #define ATECC_KEY_SIZE (32) #define ATECC_PUBKEY_SIZE (ATECC_KEY_SIZE*2) /* X and Y */ #define ATECC_SIG_SIZE (ATECC_KEY_SIZE*2) /* R and S */ +#ifndef ATECC_MAX_SLOT #define ATECC_MAX_SLOT (0x7) /* Only use 0-7 */ +#endif #define ATECC_INVALID_SLOT (-1) +/* ATECC_KEY_SIZE required for ecc.h */ +#include + struct WOLFSSL; +struct WOLFSSL_CTX; struct WOLFSSL_X509_STORE_CTX; +struct ecc_key; /* Cert Structure */ typedef struct t_atcert { @@ -66,28 +72,41 @@ void atmel_finish(void); int atmel_get_random_number(uint32_t count, uint8_t* rand_out); long atmel_get_curr_time_and_date(long* tm); -int atmel_ecc_alloc(void); +#ifdef WOLFSSL_ATECC508A + +enum atmelSlotType { + ATMEL_SLOT_ANY, + ATMEL_SLOT_ENCKEY, + ATMEL_SLOT_DEVICE, + ATMEL_SLOT_ECDHE, + ATMEL_SLOT_ECDHEPUB, +}; + +int atmel_ecc_alloc(int slotType); void atmel_ecc_free(int slot); -typedef int (*atmel_slot_alloc_cb)(void); +typedef int (*atmel_slot_alloc_cb)(int); typedef void (*atmel_slot_dealloc_cb)(int); int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, atmel_slot_dealloc_cb dealloc); -#include +#endif /* WOLFSSL_ATECC508A */ #ifdef HAVE_PK_CALLBACKS - int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz, + int atcatls_create_key_cb(struct WOLFSSL* ssl, struct ecc_key* key, word32 keySz, int ecc_curve, void* ctx); - int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey, + int atcatls_create_pms_cb(struct WOLFSSL* ssl, struct ecc_key* otherKey, unsigned char* pubKeyDer, unsigned int* pubKeySz, unsigned char* out, unsigned int* outlen, int side, void* ctx); - int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz, + int atcatls_sign_certificate_cb(struct WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx); - int atcatls_verify_signature_cb(WOLFSSL* ssl, const byte* sig, word32 sigSz, + int atcatls_verify_signature_cb(struct WOLFSSL* ssl, const byte* sig, word32 sigSz, const byte* hash, word32 hashSz, const byte* key, word32 keySz, int* result, void* ctx); + + int atcatls_set_callbacks(struct WOLFSSL_CTX* ctx); + int atcatls_set_callback_ctx(struct WOLFSSL* ssl, void* user_ctx); #endif #endif /* _ATECC508_H_ */ From c51c607e9665499395d6b4ca5b90617687dc5864 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 7 Sep 2018 16:46:42 -0700 Subject: [PATCH 05/11] Fix to use `inLen` for raw public key copy. No need to throw an error for other curve types as this function may be used for software only import/export. In the TLS case with only SECP256R1 there are other places where an error will be thrown. --- wolfcrypt/src/ecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index cc1d28a14..1e4527404 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6314,7 +6314,7 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, /* For SECP256R1 only save raw public key for hardware */ if (curve_id == ECC_SECP256R1 && !compressed && inLen <= sizeof(key->pubkey_raw)) { - XMEMCPY(key->pubkey_raw, (byte*)in, sizeof(key->pubkey_raw)); + XMEMCPY(key->pubkey_raw, (byte*)in, inLen); } #endif From ba9f21bad61d4adb230b5a93699ba8b49aff82d2 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 11 Sep 2018 09:29:33 -0700 Subject: [PATCH 06/11] Improvements to the ATECC508A README.md. --- wolfcrypt/src/port/atmel/README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/wolfcrypt/src/port/atmel/README.md b/wolfcrypt/src/port/atmel/README.md index 0283ea767..50352fcd2 100644 --- a/wolfcrypt/src/port/atmel/README.md +++ b/wolfcrypt/src/port/atmel/README.md @@ -64,6 +64,8 @@ wolfSSL_SetEccSharedSecretCtx(ssl, myOwnCtx); ## Benchmarks +Supports ECC SECP256R1 (NIST P-256) + ### TLS TLS Establishment Times: @@ -77,16 +79,16 @@ The TLS connection establishment time is 5.73 times faster with the ATECC508A. Software only implementation (SAMD21 48Mhz Cortex-M0, Fast Math TFM-ASM): -`ECC 256 key generation 3123.000 milliseconds, avg over 5 iterations` -`EC-DHE key agreement 3117.000 milliseconds, avg over 5 iterations` -`EC-DSA sign time 1997.000 milliseconds, avg over 5 iterations` -`EC-DSA verify time 5057.000 milliseconds, avg over 5 iterations` +`EC-DHE key generation 3123.000 milliseconds, avg over 5 iterations, 1.601 ops/sec` +`EC-DHE key agreement 3117.000 milliseconds, avg over 5 iterations, 1.604 ops/sec` +`EC-DSA sign time 1997.000 milliseconds, avg over 5 iterations, 2.504 ops/sec` +`EC-DSA verify time 5057.000 milliseconds, avg over 5 iterations, 0.988 ops/sec` ATECC508A HW accelerated implementation: -`ECC 256 key generation 144.400 milliseconds, avg over 5 iterations` -`EC-DHE key agreement 134.200 milliseconds, avg over 5 iterations` -`EC-DSA sign time 293.400 milliseconds, avg over 5 iterations` -`EC-DSA verify time 208.400 milliseconds, avg over 5 iterations` +`EC-DHE key generation 144.400 milliseconds, avg over 5 iterations, 34.722 ops/sec` +`EC-DHE key agreement 134.200 milliseconds, avg over 5 iterations, 37.313 ops/sec` +`EC-DSA sign time 293.400 milliseconds, avg over 5 iterations, 17.065 ops/sec` +`EC-DSA verify time 208.400 milliseconds, avg over 5 iterations, 24.038 ops/sec` For details see our [wolfSSL Atmel ATECC508A](https://wolfssl.com/wolfSSL/wolfssl-atmel.html) page. From d67cb9e875cd7d6e91eba8978caa2945cae99b58 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 11 Sep 2018 15:46:46 -0700 Subject: [PATCH 07/11] Added new build option for Microchip CryptoAuthLib (--enable-cryptoauthlib). Build fixes with WOLFSSL_ATECC508A enabled. --- configure.ac | 14 ++++++++++++++ tests/api.c | 6 ++++-- wolfcrypt/src/include.am | 5 ++++- wolfssl/wolfcrypt/port/atmel/atmel.h | 1 + 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index a544cd7e8..e5d49c8e2 100644 --- a/configure.ac +++ b/configure.ac @@ -788,6 +788,20 @@ fi AM_CONDITIONAL([BUILD_PKCALLBACKS], [ test "x$ENABLED_PKCALLBACKS" = "xyes" ]) +AC_ARG_ENABLE([cryptoauthlib], + [AS_HELP_STRING([--enable-cryptoauthlib],[Enable CryptoAuthLib (default: disabled)])], + [ ENABLED_CRYPTOAUTHLIB=$enableval ], + [ ENABLED_CRYPTOAUTHLIB=no ] + ) + +if test "$ENABLED_CRYPTOAUTHLIB" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ATECC508A" +fi + +AM_CONDITIONAL([BUILD_CRYPTOAUTHLIB], [ test "x$ENABLED_CRYPTOAUTHLIB" = "xyes" ]) + + # sniffer doesn't work in maxstrength mode if test "$ENABLED_SNIFFER" = "yes" && test "$ENABLED_MAXSTRENGTH" = "yes" then diff --git a/tests/api.c b/tests/api.c index c565bdda6..4d13402a1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14266,7 +14266,8 @@ static int test_wc_ecc_pointFns (void) { int ret = 0; -#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && \ + !defined(WC_NO_RNG) && !defined(WOLFSSL_ATECC508A) ecc_key key; WC_RNG rng; ecc_point* point = NULL; @@ -14440,7 +14441,8 @@ static int test_wc_ecc_shared_secret_ssh (void) { int ret = 0; -#if defined(HAVE_ECC) && defined(HAVE_ECC_DHE) && !defined(WC_NO_RNG) +#if defined(HAVE_ECC) && defined(HAVE_ECC_DHE) && \ + !defined(WC_NO_RNG) && !defined(WOLFSSL_ATECC508A) ecc_key key, key2; WC_RNG rng; int keySz = KEY32; diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index a68dae838..83a1b7b90 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -52,7 +52,6 @@ EXTRA_DIST += wolfcrypt/src/port/ti/ti-aes.c \ wolfcrypt/src/port/arm/armv8-aes.c \ wolfcrypt/src/port/arm/armv8-sha256.c \ wolfcrypt/src/port/nxp/ksdk_port.c \ - wolfcrypt/src/port/atmel/atmel.c \ wolfcrypt/src/port/atmel/README.md \ wolfcrypt/src/port/xilinx/xil-sha3.c \ wolfcrypt/src/port/xilinx/xil-aesgcm.c \ @@ -96,3 +95,7 @@ src_libwolfssl_la_SOURCES += wolfcrypt/src/port/intel/quickassist_mem.c EXTRA_DIST += wolfcrypt/src/port/intel/README.md endif + +if BUILD_CRYPTOAUTHLIB +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/atmel/atmel.c +endif diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index a65697893..8372742f0 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -70,6 +70,7 @@ extern t_atcert atcert; void atmel_init(void); void atmel_finish(void); int atmel_get_random_number(uint32_t count, uint8_t* rand_out); +int atmel_get_random_block(unsigned char* output, unsigned int sz); long atmel_get_curr_time_and_date(long* tm); #ifdef WOLFSSL_ATECC508A From bb737ec99d43a70d259937617467de20e78ba364 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 26 Sep 2018 14:16:32 -0700 Subject: [PATCH 08/11] Fixes for building against latest CryptoAuthLib. Refactor to eliminate the atcatls function calls, since these have been removed from latest CryptoAuthLib. Cleanup of the slot assignment handling. --- configure.ac | 47 +++- wolfcrypt/src/ecc.c | 35 +-- wolfcrypt/src/port/atmel/atmel.c | 395 +++++++++++++++++---------- wolfcrypt/src/wc_port.c | 6 +- wolfssl/wolfcrypt/port/atmel/atmel.h | 61 +++-- 5 files changed, 351 insertions(+), 193 deletions(-) diff --git a/configure.ac b/configure.ac index e5d49c8e2..5985bcdd8 100644 --- a/configure.ac +++ b/configure.ac @@ -788,18 +788,43 @@ fi AM_CONDITIONAL([BUILD_PKCALLBACKS], [ test "x$ENABLED_PKCALLBACKS" = "xyes" ]) -AC_ARG_ENABLE([cryptoauthlib], - [AS_HELP_STRING([--enable-cryptoauthlib],[Enable CryptoAuthLib (default: disabled)])], - [ ENABLED_CRYPTOAUTHLIB=$enableval ], - [ ENABLED_CRYPTOAUTHLIB=no ] - ) +# Microchip/Atmel CryptoAuthLib +ENABLED_CRYPTOAUTHLIB="no" +trylibatcadir="" +AC_ARG_WITH([cryptoauthlib], + [AS_HELP_STRING([--with-cryptoauthlib=PATH],[PATH to CryptoAuthLib install (default /usr/)])], + [ + AC_MSG_CHECKING([for cryptoauthlib]) + CPPFLAGS="$CPPFLAGS -DWOLFSSL_ATECC508A" + LIBS="$LIBS -lcryptoauth" -if test "$ENABLED_CRYPTOAUTHLIB" = "yes" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ATECC508A" -fi + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ atcab_init(0); ]])],[ libatca_linked=yes ],[ libatca_linked=no ]) -AM_CONDITIONAL([BUILD_CRYPTOAUTHLIB], [ test "x$ENABLED_CRYPTOAUTHLIB" = "xyes" ]) + if test "x$libatca_linked" == "xno" ; then + if test "x$withval" != "xno" ; then + trylibatcadir=$withval + fi + if test "x$withval" == "xyes" ; then + trylibatcadir="/usr" + fi + + LDFLAGS="$LDFLAGS -L$trylibatcadir/lib" + CPPFLAGS="$CPPFLAGS -I$trylibatcadir/lib" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ atcab_init(0); ]])],[ libatca_linked=yes ],[ libatca_linked=no ]) + + if test "x$libatca_linked" == "xno" ; then + AC_MSG_ERROR([cryptoauthlib isn't found. + If it's already installed, specify its path using --with-cryptoauthlib=/dir/]) + fi + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([yes]) + fi + ENABLED_CRYPTOAUTHLIB="yes" + ] +) +AM_CONDITIONAL([BUILD_CRYPTOAUTHLIB], [test "x$ENABLED_CRYPTOAUTHLIB" = "xyes"]) # sniffer doesn't work in maxstrength mode @@ -3542,7 +3567,7 @@ AC_ARG_WITH([libz], trylibzdir="/usr" fi - AM_LDFLAGS="$AM_LDFLAGS -L$trylibzdir/lib" + LDFLAGS="$LDFLAGS -L$trylibzdir/lib" CPPFLAGS="$CPPFLAGS -I$trylibzdir/include" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ deflateInit(0, 8); ]])],[ libz_linked=yes ],[ libz_linked=no ]) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 1e4527404..23284928d 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -3383,10 +3383,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, #ifdef WOLFSSL_ATECC508A /* For SECP256R1 use hardware */ if (private_key->dp->id == ECC_SECP256R1) { - err = atcatls_ecdh(private_key->slot, public_key->pubkey_raw, out); - if (err != ATCA_SUCCESS) { - err = BAD_COND_E; - } + err = atmel_ecc_create_pms(private_key->slot, public_key->pubkey_raw, out); *outlen = private_key->dp->size; } else { @@ -3942,10 +3939,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) #ifdef WOLFSSL_ATECC508A key->type = ECC_PRIVATEKEY; - err = atcatls_create_key(key->slot, key->pubkey_raw); - if (err != ATCA_SUCCESS) { - err = BAD_COND_E; - } + err = atmel_ecc_create_key(key->slot, key->pubkey_raw); /* populate key->pubkey */ err = mp_read_unsigned_bin(key->pubkey.x, key->pubkey_raw, @@ -4101,10 +4095,7 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) #endif #ifdef WOLFSSL_ATECC508A - key->slot = atmel_ecc_alloc(ATMEL_SLOT_ANY); - if (key->slot == ATECC_INVALID_SLOT) { - return ECC_BAD_ARG_E; - } + key->slot = -1; #else #ifdef ALT_ECC_SIZE key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; @@ -4199,10 +4190,15 @@ static int wc_ecc_sign_hash_hw(const byte* in, word32 inlen, } #if defined(WOLFSSL_ATECC508A) + key->slot = atmel_ecc_alloc(ATMEL_SLOT_DEVICE); + if (key->slot == ATECC_INVALID_SLOT) { + return ECC_BAD_ARG_E; + } + /* Sign: Result is 32-bytes of R then 32-bytes of S */ - err = atcatls_sign(key->slot, in, out); - if (err != ATCA_SUCCESS) { - return BAD_COND_E; + err = atmel_ecc_sign(key->slot, in, out); + if (err != 0) { + return err; } #elif defined(PLUTON_CRYPTO_ECC) { @@ -5280,9 +5276,9 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, return err; } - err = atcatls_verify(hash, sigRS, key->pubkey_raw, (bool*)res); - if (err != ATCA_SUCCESS) { - return BAD_COND_E; + err = atmel_ecc_verify(hash, sigRS, key->pubkey_raw, res); + if (err != 0) { + return err; } (void)hashlen; @@ -6151,9 +6147,6 @@ int wc_ecc_check_key(ecc_key* key) #ifdef WOLFSSL_ATECC508A - if (key->slot == ATECC_INVALID_SLOT) - return ECC_BAD_ARG_E; - err = 0; /* consider key check success on ATECC508A */ #else diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index 7c1803882..c465a8e64 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -50,30 +50,18 @@ #include -static int mAtcaInitDone = 0; - #ifdef WOLFSSL_ATECC508A -/* Free slot handling */ +static int mAtcaInitDone = 0; + +/* ATECC slotId handling */ static atmel_slot_alloc_cb mSlotAlloc; static atmel_slot_dealloc_cb mSlotDealloc; -static int mSlotList[ATECC_MAX_SLOT+1]; - -#ifndef ATECC_SLOT_I2C_ENC - #define ATECC_SLOT_I2C_ENC 0x04 /* Slot holding symmetric encryption key */ +static byte mSlotList[ATECC_MAX_SLOT]; +#ifndef SINGLE_THREADED +static wolfSSL_Mutex mSlotMutex; #endif -/** - * \brief Structure to contain certificate information. - */ -t_atcert atcert = { - .signer_ca_size = 512, - .signer_ca = { 0 }, - .signer_ca_pubkey = { 0 }, - .end_user_size = 512, - .end_user = { 0 }, - .end_user_pubkey = { 0 } -}; #endif /* WOLFSSL_ATECC508A */ @@ -92,10 +80,9 @@ int atmel_get_random_number(uint32_t count, uint8_t* rand_out) return -1; } - while(i < count) { - - ret = atcatls_random(rng_buffer); - if (ret != 0) { + while (i < count) { + ret = atcab_random(rng_buffer); + if (ret != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to create random number!"); return -1; } @@ -157,171 +144,290 @@ long atmel_get_curr_time_and_date(long* tm) #ifdef WOLFSSL_ATECC508A -/* Function to set the slot allocator and deallocator */ +int atmel_ecc_translate_err(int status) +{ + switch (status) { + case ATCA_SUCCESS: + return 0; + case ATCA_BAD_PARAM: + return BAD_FUNC_ARG; + case ATCA_ALLOC_FAILURE: + return MEMORY_E; + default: + #ifdef WOLFSSL_ATECC508A_DEBUG + printf("ATECC Failure: %x\n", (word32)status); + #endif + break; + } + return WC_HW_E; +} + +/* Function to set the slotId allocator and deallocator */ int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, atmel_slot_dealloc_cb dealloc) { +#ifndef SINGLE_THREADED + wc_LockMutex(&mSlotMutex); +#endif mSlotAlloc = alloc; mSlotDealloc = dealloc; +#ifndef SINGLE_THREADED + wc_UnLockMutex(&mSlotMutex); +#endif return 0; } -/* Function to allocate new slot number */ +/* Function to allocate new slotId number */ int atmel_ecc_alloc(int slotType) { - int slot = ATECC_INVALID_SLOT; + int slotId = ATECC_INVALID_SLOT, i; + +#ifndef SINGLE_THREADED + wc_LockMutex(&mSlotMutex); +#endif if (mSlotAlloc) { - slot = mSlotAlloc(slotType); + slotId = mSlotAlloc(slotType); } else { - int i; - - if (slotType == ATMEL_SLOT_ENCKEY) { - return ATECC_SLOT_I2C_ENC; - } - - for (i=0; i <= ATECC_MAX_SLOT; i++) { - /* Find free slot */ - if (mSlotList[i] == ATECC_INVALID_SLOT) { - mSlotList[i] = i; - slot = i; + switch (slotType) { + case ATMEL_SLOT_ENCKEY: + /* not reserved in mSlotList, so return */ + slotId = ATECC_SLOT_I2C_ENC; + goto exit; + case ATMEL_SLOT_DEVICE: + /* not reserved in mSlotList, so return */ + slotId = ATECC_SLOT_AUTH_PRIV; + goto exit; + case ATMEL_SLOT_ECDHE: + slotId = ATECC_SLOT_ECDHE_PRIV; + break; + case ATMEL_SLOT_ECDHE_ENC: + slotId = ATECC_SLOT_ENC_PARENT; + break; + case ATMEL_SLOT_ANY: + for (i=0; i < ATECC_MAX_SLOT; i++) { + /* Find free slotId */ + if (mSlotList[i] == ATECC_INVALID_SLOT) { + slotId = i; + break; + } + } break; - } - } - } - return slot; -} - - -/* Function to return slot number to available list */ -void atmel_ecc_free(int slot) -{ - if (mSlotDealloc) { - mSlotDealloc(slot); - } - else if (slot >= 0 && slot <= ATECC_MAX_SLOT) { - /* Mark slot free */ - mSlotList[slot] = ATECC_INVALID_SLOT; - } -} - - -/* The macros ATECC_GET_ENC_KEY can be set to override the default - encryption key with your own at build-time */ -#ifndef ATECC_GET_ENC_KEY - #define ATECC_GET_ENC_KEY atmel_get_enc_key - - /** - * \brief Callback function for getting the current encryption key - */ - static ATCA_STATUS atmel_get_enc_key(uint8_t* enckey, int16_t keysize) - { - if (enckey == NULL || keysize != ATECC_KEY_SIZE) { - return ATCA_BAD_PARAM; } - XMEMSET(enckey, 0xFF, keysize); /* use default value */ - - return ATCA_SUCCESS; + /* is slot available */ + if (mSlotList[slotId] != ATECC_INVALID_SLOT) { + slotId = ATECC_INVALID_SLOT; + } + else { + mSlotList[slotId] = slotId; + } } + +exit: +#ifndef SINGLE_THREADED + wc_UnLockMutex(&mSlotMutex); #endif + return slotId; +} + + +/* Function to return slotId number to available list */ +void atmel_ecc_free(int slotId) +{ +#ifndef SINGLE_THREADED + wc_LockMutex(&mSlotMutex); +#endif + if (mSlotDealloc) { + mSlotDealloc(slotId); + } + else if (slotId >= 0 && slotId < ATECC_MAX_SLOT) { + if (slotId != ATECC_SLOT_AUTH_PRIV && slotId != ATECC_SLOT_I2C_ENC) { + /* Mark slotId free */ + mSlotList[slotId] = ATECC_INVALID_SLOT; + } + } +#ifndef SINGLE_THREADED + wc_UnLockMutex(&mSlotMutex); +#endif +} + + +/** + * \brief Callback function for getting the current encryption key + */ +int atmel_get_enc_key_default(byte* enckey, word16 keysize) +{ + if (enckey == NULL || keysize != ATECC_KEY_SIZE) { + return BAD_FUNC_ARG; + } + + XMEMSET(enckey, 0xFF, keysize); /* use default value */ + + return 0; +} + /** * \brief Write enc key before. */ static int atmel_init_enc_key(void) { - uint8_t ret = 0; + int ret; uint8_t read_key[ATECC_KEY_SIZE]; - int slot = atmel_ecc_alloc(ATMEL_SLOT_ENCKEY); + uint8_t writeBlock = 0; + uint8_t writeOffset = 0; + int slotId; - /* check for encryption key slot */ - if (slot == ATECC_INVALID_SLOT) - return -1; + slotId = atmel_ecc_alloc(ATMEL_SLOT_ENCKEY); + + /* check for encryption key slotId */ + if (slotId == ATECC_INVALID_SLOT) + return BAD_FUNC_ARG; /* get encryption key */ ATECC_GET_ENC_KEY(read_key, sizeof(read_key)); - ret = atcatls_set_enckey(read_key, slot, 0); - ForceZero(read_key, sizeof(read_key)); - if (ret != ATCA_SUCCESS) { - WOLFSSL_MSG("Failed to write key"); - return -1; - } - ret = atcatlsfn_set_get_enckey(ATECC_GET_ENC_KEY); - if (ret != ATCA_SUCCESS) { - WOLFSSL_MSG("Failed to set enckey cb"); - return -1; - } + ret = atcab_write_zone(ATCA_ZONE_DATA, slotId, writeBlock, writeOffset, + read_key, ATCA_BLOCK_SIZE); + ForceZero(read_key, sizeof(read_key)); + ret = atmel_ecc_translate_err(ret); return ret; } -static void atmel_show_rev_info(void) +int atmel_get_rev_info(byte* revision) +{ + int ret; + ret = atcab_info((uint8_t*)revision); + ret = atmel_ecc_translate_err(ret); + return ret; +} + +void atmel_show_rev_info(void) { #ifdef WOLFSSL_ATECC508A_DEBUG - uint32_t revision = 0; - atcab_info((uint8_t*)&revision); - printf("ATECC508A Revision: %x\n", (unsigned int)revision); + byte revision = 0; + atmel_get_rev_info(&revision); + printf("ATECC508A Revision: %x\n", (word32)revision); #endif } +int atmel_ecc_create_pms(int slotId, const uint8_t* peerKey, uint8_t* pms) +{ + int ret; + uint8_t read_key[ATECC_KEY_SIZE]; + int slotIdEnc; + + slotIdEnc = atmel_ecc_alloc(ATMEL_SLOT_ECDHE_ENC); + if (slotIdEnc != ATECC_INVALID_SLOT) + return BAD_FUNC_ARG; + + /* get encryption key */ + ATECC_GET_ENC_KEY(read_key, sizeof(read_key)); + + /* send the encrypted version of the ECDH command */ + ret = atcab_ecdh_enc(slotId, peerKey, pms, read_key, slotIdEnc); + ret = atmel_ecc_translate_err(ret); + return ret; +} + +int atmel_ecc_create_key(int slotId, byte* peerKey) +{ + int ret; + + /* generate new ephemeral key on device */ + ret = atcab_genkey(slotId, peerKey); + ret = atmel_ecc_translate_err(ret); + return ret; +} + +int atmel_ecc_sign(int slotId, const byte* message, byte* signature) +{ + int ret; + + ret = atcab_sign(slotId, message, signature); + ret = atmel_ecc_translate_err(ret); + return ret; +} + +int atmel_ecc_verify(const byte* message, const byte* signature, + const byte* pubkey, int* verified) +{ + int ret; + + ret = atcab_verify_extern(message, signature, pubkey, (bool*)verified); + ret = atmel_ecc_translate_err(ret); + return ret; +} + #endif /* WOLFSSL_ATECC508A */ -void atmel_init(void) +int atmel_init(void) { - if (!mAtcaInitDone) { + int ret = 0; + #ifdef WOLFSSL_ATECC508A + if (!mAtcaInitDone) { + ATCA_STATUS status; int i; - /* Init the free slot list */ + #ifndef SINGLE_THREADED + wc_InitMutex(&mSlotMutex); + #endif + + /* Init the free slotId list */ for (i=0; i<=ATECC_MAX_SLOT; i++) { - if (i == 0 || i == 2 || i == 7) { - /* ECC Slots (mark avail) */ - mSlotList[i] = ATECC_INVALID_SLOT; + if (i == ATECC_SLOT_AUTH_PRIV || i == ATECC_SLOT_I2C_ENC) { + mSlotList[i] = i; } else { - mSlotList[i] = i; + /* ECC Slots (mark avail) */ + mSlotList[i] = ATECC_INVALID_SLOT; } } /* Initialize the CryptoAuthLib to communicate with ATECC508A */ - atcatls_init(&cfg_ateccx08a_i2c_default); + status = atcab_init(&cfg_ateccx08a_i2c_default); + if (status != ATCA_SUCCESS) { + WOLFSSL_MSG("Failed to initialize atcab"); + return WC_HW_E; + } /* Init the I2C pipe encryption key. */ /* Value is generated/stored during pair for the ATECC508A and stored on micro flash */ /* For this example its a fixed value */ - if (atmel_init_enc_key() != ATCA_SUCCESS) { + if (atmel_init_enc_key() != 0) { WOLFSSL_MSG("Failed to initialize transport key"); + return WC_HW_E; } /* show revision information */ atmel_show_rev_info(); - /* Configure the ECC508 for use with TLS API functions */ - #if 0 - atcatls_device_provision(); - #else - atcatls_config_default(); - #endif -#endif /* WOLFSSL_ATECC508A */ - mAtcaInitDone = 1; } +#endif /* WOLFSSL_ATECC508A */ + return ret; } void atmel_finish(void) { - if (mAtcaInitDone) { #ifdef WOLFSSL_ATECC508A - atcatls_finish(); -#endif + if (mAtcaInitDone) { + atcab_release(); + + #ifndef SINGLE_THREADED + wc_FreeMutex(&mSlotMutex); + #endif + mAtcaInitDone = 0; } +#endif } @@ -335,6 +441,7 @@ int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz, uint8_t peerKey[ATECC_PUBKEY_SIZE]; uint8_t* qx = &peerKey[0]; uint8_t* qy = &peerKey[ATECC_PUBKEY_SIZE/2]; + int slotId; (void)ssl; (void)ctx; @@ -344,22 +451,27 @@ int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz, return BAD_FUNC_ARG; } + slotId = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); + if (slotId == ATECC_INVALID_SLOT) + return WC_HW_WAIT_E; + /* generate new ephemeral key on device */ - ret = atcatls_create_key(TLS_SLOT_ECDHE_PRIV, peerKey); - if (ret != ATCA_SUCCESS) { - ret = WC_HW_E; goto exit; - } + ret = atmel_ecc_create_key(slotId, peerKey); /* load generated ECC508A public key into key, used by wolfSSL */ - ret = wc_ecc_import_unsigned(key, qx, qy, NULL, ECC_SECP256R1); - -exit: - -#ifdef WOLFSSL_ATECC508A_DEBUG - if (ret != 0) { - printf("atcatls_create_key_cb: ret %d\n", ret); + if (ret == 0) { + ret = wc_ecc_import_unsigned(key, qx, qy, NULL, ECC_SECP256R1); + } + + if (ret == 0) { + key->slot = slotId; + } + else { + atmel_ecc_free(slotId); + #ifdef WOLFSSL_ATECC508A_DEBUG + printf("atcatls_create_key_cb: ret %d\n", ret); + #endif } -#endif return ret; } @@ -394,10 +506,15 @@ int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey, /* for client: create and export public key */ if (side == WOLFSSL_CLIENT_END) { + int slotId = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); + if (slotId == ATECC_INVALID_SLOT) + return WC_HW_WAIT_E; + tmpKey.slot = slotId; + /* generate new ephemeral key on device */ - ret = atcatls_create_key(TLS_SLOT_ECDHE_PRIV, peerKey); + ret = atmel_ecc_create_key(slotId, peerKey); if (ret != ATCA_SUCCESS) { - ret = WC_HW_E; goto exit; + goto exit; } /* convert raw unsigned public key to X.963 format for TLS */ @@ -409,6 +526,8 @@ int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey, /* for server: import public key */ else if (side == WOLFSSL_SERVER_END) { + tmpKey.slot = otherKey->slot; + /* import peer's key and export as raw unsigned for hardware */ ret = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, ECC_SECP256R1); if (ret == 0) { @@ -425,16 +544,7 @@ int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey, goto exit; } -#if 1 - ret = atcatls_ecdh(TLS_SLOT_ECDHE_PRIV, peerKey, out); -#else - /* other syntax for encrypted ECDH using key in another slot */ - ret = atcatls_ecdh_enc(TLS_SLOT_ECDHE_PRIV, TLS_SLOT_FEATURE_PRIV, - peerKey, out); -#endif - if (ret != ATCA_SUCCESS) { - ret = WC_HW_E; - } + ret = atmel_ecc_create_pms(tmpKey.slot, peerKey, out); *outlen = ATECC_SIG_SIZE; exit: @@ -442,7 +552,7 @@ exit: #ifdef WOLFSSL_ATECC508A_DEBUG if (ret != 0) { - printf("atcatls_create_pms_cb: ret %d\n", ret); + printf("atcab_ecdh_enc: ret %d\n", ret); } #endif @@ -458,6 +568,7 @@ int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz, { int ret; byte sigRs[ATECC_SIG_SIZE*2]; + int slotId; (void)ssl; (void)inSz; @@ -469,7 +580,11 @@ int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz, return BAD_FUNC_ARG; } - ret = atcatls_sign(TLS_SLOT_AUTH_PRIV, in, sigRs); + slotId = atmel_ecc_alloc(ATMEL_SLOT_DEVICE); + if (slotId == ATECC_INVALID_SLOT) + return WC_HW_WAIT_E; + + ret = atmel_ecc_sign(slotId, in, sigRs); if (ret != ATCA_SUCCESS) { ret = WC_HW_E; goto exit; } @@ -485,6 +600,8 @@ int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz, exit: + atmel_ecc_free(slotId); + #ifdef WOLFSSL_ATECC508A_DEBUG if (ret != 0) { printf("atcatls_sign_certificate_cb: ret %d\n", ret); @@ -546,7 +663,7 @@ int atcatls_verify_signature_cb(WOLFSSL* ssl, const byte* sig, word32 sigSz, (void)rSz; (void)sSz; - ret = atcatls_verify(hash, sigRs, peerKey, (bool*)result); + ret = atmel_ecc_verify(hash, sigRs, peerKey, result); if (ret != ATCA_SUCCESS || !*result) { ret = WC_HW_E; goto exit; } diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index f44459b0b..c3ece65cf 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -153,7 +153,11 @@ int wolfCrypt_Init(void) #endif #if defined(WOLFSSL_ATMEL) || defined(WOLFSSL_ATECC508A) - atmel_init(); + ret = atmel_init(); + if (ret != 0) { + WOLFSSL_MSG("CryptoAuthLib init failed"); + return ret; + } #endif #if defined(WOLFSSL_STSAFEA100) diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index 8372742f0..94afb3187 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -31,9 +31,7 @@ #undef SHA_BLOCK_SIZE #define SHA_BLOCK_SIZE SHA_BLOCK_SIZE_REMAP #include - #include #include - #include #undef SHA_BLOCK_SIZE #endif @@ -44,7 +42,24 @@ #ifndef ATECC_MAX_SLOT #define ATECC_MAX_SLOT (0x7) /* Only use 0-7 */ #endif -#define ATECC_INVALID_SLOT (-1) +#define ATECC_INVALID_SLOT (0xFF) + +/* Device Key for signing */ +#ifndef ATECC_SLOT_AUTH_PRIV +#define ATECC_SLOT_AUTH_PRIV (0x0) +#endif +/* Ephemeral key */ +#ifndef ATECC_SLOT_ECDHE_PRIV +#define ATECC_SLOT_ECDHE_PRIV (0x2) +#endif +/* Symmetric encryption key */ +#ifndef ATECC_SLOT_I2C_ENC +#define ATECC_SLOT_I2C_ENC (0x04) +#endif +/* Parent encryption key */ +#ifndef ATECC_SLOT_ENC_PARENT +#define ATECC_SLOT_ENC_PARENT (0x7) +#endif /* ATECC_KEY_SIZE required for ecc.h */ #include @@ -54,23 +69,11 @@ struct WOLFSSL_CTX; struct WOLFSSL_X509_STORE_CTX; struct ecc_key; -/* Cert Structure */ -typedef struct t_atcert { - uint32_t signer_ca_size; - uint8_t signer_ca[512]; - uint8_t signer_ca_pubkey[64]; - uint32_t end_user_size; - uint8_t end_user[512]; - uint8_t end_user_pubkey[64]; -} t_atcert; - -extern t_atcert atcert; - -/* Amtel port functions */ -void atmel_init(void); +/* Atmel port functions */ +int atmel_init(void); void atmel_finish(void); int atmel_get_random_number(uint32_t count, uint8_t* rand_out); -int atmel_get_random_block(unsigned char* output, unsigned int sz); +int atmel_get_random_block(unsigned char* output, unsigned int sz); long atmel_get_curr_time_and_date(long* tm); #ifdef WOLFSSL_ATECC508A @@ -80,17 +83,33 @@ enum atmelSlotType { ATMEL_SLOT_ENCKEY, ATMEL_SLOT_DEVICE, ATMEL_SLOT_ECDHE, - ATMEL_SLOT_ECDHEPUB, + ATMEL_SLOT_ECDHE_ENC, }; int atmel_ecc_alloc(int slotType); -void atmel_ecc_free(int slot); +void atmel_ecc_free(int slotId); typedef int (*atmel_slot_alloc_cb)(int); typedef void (*atmel_slot_dealloc_cb)(int); -int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, +int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, atmel_slot_dealloc_cb dealloc); +int atmel_ecc_translate_err(int status); +int atmel_get_rev_info(byte* revision); +void atmel_show_rev_info(void); + +/* The macro ATECC_GET_ENC_KEY can be set to override the default + encryption key with your own at build-time */ +#ifndef ATECC_GET_ENC_KEY + #define ATECC_GET_ENC_KEY(enckey, keysize) atmel_get_enc_key_default((enckey), (keysize)) +#endif +int atmel_get_enc_key_default(byte* enckey, word16 keysize); +int atmel_ecc_create_pms(int slotId, const uint8_t* peerKey, uint8_t* pms); +int atmel_ecc_create_key(int slotId, byte* peerKey); +int atmel_ecc_sign(int slotId, const byte* message, byte* signature); +int atmel_ecc_verify(const byte* message, const byte* signature, + const byte* pubkey, int* verified); + #endif /* WOLFSSL_ATECC508A */ #ifdef HAVE_PK_CALLBACKS From 177bf49fa68a06c8b7470d3b139be67cb999ad6e Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 27 Sep 2018 15:41:58 -0700 Subject: [PATCH 09/11] Updates to the atmel.c code to allow easier customization of the hardware interface. --- configure.ac | 5 +++++ wolfcrypt/src/port/atmel/atmel.c | 23 ++++++++++++++++++++++- wolfssl/wolfcrypt/port/atmel/atmel.h | 3 +-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 5985bcdd8..3c4e91373 100644 --- a/configure.ac +++ b/configure.ac @@ -817,11 +817,16 @@ AC_ARG_WITH([cryptoauthlib], AC_MSG_ERROR([cryptoauthlib isn't found. If it's already installed, specify its path using --with-cryptoauthlib=/dir/]) fi + + AM_LDFLAGS="$AM_LDFLAGS -L$trylibatcadir/lib" + AM_CFLAGS="$AM_CFLAGS -I$trylibatcadir/lib" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([yes]) fi + ENABLED_CRYPTOAUTHLIB="yes" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ATECC508A" ] ) AM_CONDITIONAL([BUILD_CRYPTOAUTHLIB], [test "x$ENABLED_CRYPTOAUTHLIB" = "xyes"]) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index c465a8e64..340b52d2e 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -62,6 +62,17 @@ static byte mSlotList[ATECC_MAX_SLOT]; static wolfSSL_Mutex mSlotMutex; #endif +/* Raspberry Pi uses /dev/i2c-1 */ +#ifndef ATECC_I2C_ADDR +#define ATECC_I2C_ADDR 0xC0 +#endif +#ifndef ATECC_I2C_BUS +#define ATECC_I2C_BUS 1 +#endif +#ifndef ATECC_DEV_TYPE +#define ATECC_DEV_TYPE ATECC508A +#endif +static ATCAIfaceCfg cfg_ateccx08a_i2c_pi; #endif /* WOLFSSL_ATECC508A */ @@ -390,8 +401,18 @@ int atmel_init(void) } } + /* Setup the hardware interface */ + XMEMSET(&cfg_ateccx08a_i2c_pi, 0, sizeof(cfg_ateccx08a_i2c_pi)); + cfg_ateccx08a_i2c_pi.iface_type = ATCA_I2C_IFACE; + cfg_ateccx08a_i2c_pi.devtype = ATECC_DEV_TYPE; + cfg_ateccx08a_i2c_pi.atcai2c.slave_address = ATECC_I2C_ADDR; + cfg_ateccx08a_i2c_pi.atcai2c.bus = ATECC_I2C_BUS; + cfg_ateccx08a_i2c_pi.atcai2c.baud = 400000; + cfg_ateccx08a_i2c_pi.wake_delay = 1500; + cfg_ateccx08a_i2c_pi.rx_retries = 20; + /* Initialize the CryptoAuthLib to communicate with ATECC508A */ - status = atcab_init(&cfg_ateccx08a_i2c_default); + status = atcab_init(&cfg_ateccx08a_i2c_pi); if (status != ATCA_SUCCESS) { WOLFSSL_MSG("Failed to initialize atcab"); return WC_HW_E; diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index 94afb3187..479a89250 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -31,11 +31,10 @@ #undef SHA_BLOCK_SIZE #define SHA_BLOCK_SIZE SHA_BLOCK_SIZE_REMAP #include - #include #undef SHA_BLOCK_SIZE #endif -/* ATECC508A only supports ECC-256 */ +/* ATECC508A only supports ECC P-256 */ #define ATECC_KEY_SIZE (32) #define ATECC_PUBKEY_SIZE (ATECC_KEY_SIZE*2) /* X and Y */ #define ATECC_SIG_SIZE (ATECC_KEY_SIZE*2) /* R and S */ From bd57f5b385fcb35ce4aef0a8d9314d41600bdb87 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 28 Sep 2018 11:33:42 -0700 Subject: [PATCH 10/11] Fix to resolve possible buffer overflow with `atmel_get_rev_info` when using byte. --- wolfcrypt/src/port/atmel/atmel.c | 4 ++-- wolfssl/wolfcrypt/port/atmel/atmel.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index 340b52d2e..dbd5cc8fd 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -308,7 +308,7 @@ static int atmel_init_enc_key(void) return ret; } -int atmel_get_rev_info(byte* revision) +int atmel_get_rev_info(word32* revision) { int ret; ret = atcab_info((uint8_t*)revision); @@ -319,7 +319,7 @@ int atmel_get_rev_info(byte* revision) void atmel_show_rev_info(void) { #ifdef WOLFSSL_ATECC508A_DEBUG - byte revision = 0; + word32 revision = 0; atmel_get_rev_info(&revision); printf("ATECC508A Revision: %x\n", (word32)revision); #endif diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index 479a89250..9b5b1b858 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -94,7 +94,7 @@ int atmel_set_slot_allocator(atmel_slot_alloc_cb alloc, atmel_slot_dealloc_cb dealloc); int atmel_ecc_translate_err(int status); -int atmel_get_rev_info(byte* revision); +int atmel_get_rev_info(word32* revision); void atmel_show_rev_info(void); /* The macro ATECC_GET_ENC_KEY can be set to override the default From e53694b351f49c93bc8aa4f8b11f2e22f9419bff Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 15 Oct 2018 16:01:04 -0700 Subject: [PATCH 11/11] Fix for shared secret callback for client side, where it was not using the provided peer's public key. Fix for ATECC508A to put it into idle mode after operations to prevent watchdog fault mode (can be disabled by defining `WOLFSSL_ATECC508A_NOIDLE`). Fixes for callbacks to support using software for non P-256 curves (can be disabled by defining `WOLFSSL_ATECC508A_NOSOFTECC`). --- wolfcrypt/src/port/atmel/atmel.c | 238 +++++++++++++++++++++---------- 1 file changed, 165 insertions(+), 73 deletions(-) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index dbd5cc8fd..fcfc121a6 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -455,6 +455,9 @@ void atmel_finish(void) /* Reference PK Callbacks */ #ifdef HAVE_PK_CALLBACKS +/** + * \brief Used on the server-side only for creating the ephemeral key for ECDH + */ int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz, int ecc_curve, void* ctx) { @@ -467,36 +470,49 @@ int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz, (void)ssl; (void)ctx; - /* only supports P-256 */ - if (ecc_curve != ECC_SECP256R1 && keySz != ATECC_PUBKEY_SIZE/2) { - return BAD_FUNC_ARG; - } + /* ATECC508A only supports P-256 */ + if (ecc_curve == ECC_SECP256R1) { + slotId = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); + if (slotId == ATECC_INVALID_SLOT) + return WC_HW_WAIT_E; - slotId = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); - if (slotId == ATECC_INVALID_SLOT) - return WC_HW_WAIT_E; + /* generate new ephemeral key on device */ + ret = atmel_ecc_create_key(slotId, peerKey); - /* generate new ephemeral key on device */ - ret = atmel_ecc_create_key(slotId, peerKey); + /* load generated ECC508A public key into key, used by wolfSSL */ + if (ret == 0) { + ret = wc_ecc_import_unsigned(key, qx, qy, NULL, ECC_SECP256R1); + } - /* load generated ECC508A public key into key, used by wolfSSL */ - if (ret == 0) { - ret = wc_ecc_import_unsigned(key, qx, qy, NULL, ECC_SECP256R1); - } - - if (ret == 0) { - key->slot = slotId; + if (ret == 0) { + key->slot = slotId; + } + else { + atmel_ecc_free(slotId); + #ifdef WOLFSSL_ATECC508A_DEBUG + printf("atcatls_create_key_cb: ret %d\n", ret); + #endif + } } else { - atmel_ecc_free(slotId); - #ifdef WOLFSSL_ATECC508A_DEBUG - printf("atcatls_create_key_cb: ret %d\n", ret); - #endif + #ifndef WOLFSSL_ATECC508A_NOSOFTECC + /* use software for non P-256 cases */ + WC_RNG rng; + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_ecc_make_key_ex(&rng, keySz, key, ecc_curve); + wc_FreeRng(&rng); + } + #else + ret = NOT_COMPILED_IN; + #endif /* !WOLFSSL_ATECC508A_NOSOFTECC */ } - return ret; } +/** + * \brief Creates a shared secret using a peer public key and a device key + */ int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey, unsigned char* pubKeyDer, unsigned int* pubKeySz, unsigned char* out, unsigned int* outlen, @@ -523,50 +539,106 @@ int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey, return ret; } - XMEMSET(peerKey, 0, ATECC_PUBKEY_SIZE); + /* ATECC508A only supports P-256 */ + if (otherKey->dp->id == ECC_SECP256R1) { + XMEMSET(peerKey, 0, ATECC_PUBKEY_SIZE); - /* for client: create and export public key */ - if (side == WOLFSSL_CLIENT_END) { - int slotId = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); - if (slotId == ATECC_INVALID_SLOT) - return WC_HW_WAIT_E; - tmpKey.slot = slotId; + /* for client: create and export public key */ + if (side == WOLFSSL_CLIENT_END) { + int slotId = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); + if (slotId == ATECC_INVALID_SLOT) + return WC_HW_WAIT_E; + tmpKey.slot = slotId; - /* generate new ephemeral key on device */ - ret = atmel_ecc_create_key(slotId, peerKey); - if (ret != ATCA_SUCCESS) { + /* generate new ephemeral key on device */ + ret = atmel_ecc_create_key(slotId, peerKey); + if (ret != ATCA_SUCCESS) { + goto exit; + } + + /* convert raw unsigned public key to X.963 format for TLS */ + ret = wc_ecc_import_unsigned(&tmpKey, qx, qy, NULL, ECC_SECP256R1); + if (ret == 0) { + ret = wc_ecc_export_x963(&tmpKey, pubKeyDer, pubKeySz); + } + + /* export peer's key as raw unsigned for hardware */ + if (ret == 0) { + ret = wc_ecc_export_public_raw(otherKey, qx, &qxLen, qy, &qyLen); + } + } + + /* for server: import public key */ + else if (side == WOLFSSL_SERVER_END) { + tmpKey.slot = otherKey->slot; + + /* import peer's key and export as raw unsigned for hardware */ + ret = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, ECC_SECP256R1); + if (ret == 0) { + ret = wc_ecc_export_public_raw(&tmpKey, qx, &qxLen, qy, &qyLen); + } + } + else { + ret = BAD_FUNC_ARG; + } + + if (ret != 0) { goto exit; } - /* convert raw unsigned public key to X.963 format for TLS */ - ret = wc_ecc_import_unsigned(&tmpKey, qx, qy, NULL, ECC_SECP256R1); - if (ret == 0) { - ret = wc_ecc_export_x963(&tmpKey, pubKeyDer, pubKeySz); - } - } + ret = atmel_ecc_create_pms(tmpKey.slot, peerKey, out); + *outlen = ATECC_SIG_SIZE; - /* for server: import public key */ - else if (side == WOLFSSL_SERVER_END) { - tmpKey.slot = otherKey->slot; + #ifndef WOLFSSL_ATECC508A_NOIDLE + /* put chip into idle to prevent watchdog situation on chip */ + atcab_idle(); + #endif - /* import peer's key and export as raw unsigned for hardware */ - ret = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, ECC_SECP256R1); - if (ret == 0) { - ret = wc_ecc_export_public_raw(&tmpKey, qx, &qxLen, qy, &qyLen); - } (void)qxLen; (void)qyLen; } else { - ret = BAD_FUNC_ARG; - } + #ifndef WOLFSSL_ATECC508A_NOSOFTECC + /* use software for non P-256 cases */ + ecc_key* privKey = NULL; + ecc_key* pubKey = NULL; - if (ret != 0) { - goto exit; - } + /* for client: create and export public key */ + if (side == WOLFSSL_CLIENT_END) + { + WC_RNG rng; + privKey = &tmpKey; + pubKey = otherKey; - ret = atmel_ecc_create_pms(tmpKey.slot, peerKey, out); - *outlen = ATECC_SIG_SIZE; + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_ecc_make_key_ex(&rng, 0, privKey, otherKey->dp->id); + if (ret == 0) { + ret = wc_ecc_export_x963(privKey, pubKeyDer, pubKeySz); + } + wc_FreeRng(&rng); + } + } + /* for server: import public key */ + else if (side == WOLFSSL_SERVER_END) { + privKey = otherKey; + pubKey = &tmpKey; + + ret = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, pubKey, + otherKey->dp->id); + } + else { + ret = BAD_FUNC_ARG; + } + + /* generate shared secret and return it */ + if (ret == 0) { + ret = wc_ecc_shared_secret(privKey, pubKey, out, outlen); + } + #else + ret = NOT_COMPILED_IN; + #endif /* !WOLFSSL_ATECC508A_NOSOFTECC */ + } exit: wc_ecc_free(&tmpKey); @@ -582,7 +654,7 @@ exit: /** - * \brief Sign received digest so far for private key to be proved. + * \brief Sign received digest using private key on device */ int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx) @@ -605,11 +677,17 @@ int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz, if (slotId == ATECC_INVALID_SLOT) return WC_HW_WAIT_E; + /* We can only sign with P-256 */ ret = atmel_ecc_sign(slotId, in, sigRs); if (ret != ATCA_SUCCESS) { ret = WC_HW_E; goto exit; } +#ifndef WOLFSSL_ATECC508A_NOIDLE + /* put chip into idle to prevent watchdog situation on chip */ + atcab_idle(); +#endif + /* Encode with ECDSA signature */ ret = wc_ecc_rs_raw_to_sig( &sigRs[0], ATECC_SIG_SIZE, @@ -658,36 +736,50 @@ int atcatls_verify_signature_cb(WOLFSSL* ssl, const byte* sig, word32 sigSz, return BAD_FUNC_ARG; } - /* import public key and export public as unsigned bin for hardware */ + /* import public key */ ret = wc_ecc_init(&tmpKey); if (ret == 0) { ret = wc_EccPublicKeyDecode(key, &idx, &tmpKey, keySz); - if (ret == 0) { - ret = wc_ecc_export_public_raw(&tmpKey, qx, &qxLen, qy, &qyLen); - } + } + if (ret != 0) { + goto exit; + } + + if (tmpKey.dp->id == ECC_SECP256R1) { + /* export public as unsigned bin for hardware */ + ret = wc_ecc_export_public_raw(&tmpKey, qx, &qxLen, qy, &qyLen); wc_ecc_free(&tmpKey); - (void)qxLen; - (void)qyLen; + /* decode the ECDSA signature */ + ret = wc_ecc_sig_to_rs(sig, sigSz, + &sigRs[0], &rSz, + &sigRs[ATECC_SIG_SIZE], &sSz); + if (ret != 0) { + goto exit; + } + + ret = atmel_ecc_verify(hash, sigRs, peerKey, result); + if (ret != ATCA_SUCCESS || !*result) { + ret = WC_HW_E; goto exit; + } + + #ifndef WOLFSSL_ATECC508A_NOIDLE + /* put chip into idle to prevent watchdog situation on chip */ + atcab_idle(); + #endif } - if (ret != 0) { - goto exit; + else { + #ifndef WOLFSSL_ATECC508A_NOSOFTECC + ret = wc_ecc_verify_hash(sig, sigSz, hash, hashSz, result, &tmpKey); + #else + ret = NOT_COMPILED_IN; + #endif /* !WOLFSSL_ATECC508A_NOSOFTECC */ } - /* decode the ECDSA signature */ - ret = wc_ecc_sig_to_rs(sig, sigSz, - &sigRs[0], &rSz, - &sigRs[ATECC_SIG_SIZE], &sSz); - if (ret != 0) { - goto exit; - } (void)rSz; (void)sSz; - - ret = atmel_ecc_verify(hash, sigRs, peerKey, result); - if (ret != ATCA_SUCCESS || !*result) { - ret = WC_HW_E; goto exit; - } + (void)qxLen; + (void)qyLen; ret = 0; /* success */