From 53c22643270283bd4a7587275b5a65e73ace1a25 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 7 Sep 2018 12:39:27 -0700 Subject: [PATCH] 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_ */