Merge pull request #1699 from dgarske/ecc508a_pkcb

Added reference PK callbacks for ATECC508A to support TLS
pull/1701/head
toddouska 2018-07-18 09:35:58 -07:00 committed by GitHub
commit aa2d6f8060
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 342 additions and 4 deletions

View File

@ -5,4 +5,69 @@
* Adds new PK callback for Pre Master Secret.
## Building
`./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_ATECC508A"`
or
`#define HAVE_PK_CALLBACKS`
`#define WOLFSSL_ATECC508A`
## Coding
Setup the PK callbacks for TLS using:
```
/* Setup PK Callbacks for ATECC508A */
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);
```
The reference ATECC508A PK callback functions are located in the `wolfcrypt/src/port/atmel/atmel.c` file.
Adding a custom contex to the callbacks:
```
/* Setup PK Callbacks context */
WOLFSSL* ssl;
void* myOwnCtx;
wolfSSL_SetEccKeyGenCtx(ssl, myOwnCtx);
wolfSSL_SetEccVerifyCtx(ssl, myOwnCtx);
wolfSSL_SetEccSignCtx(ssl, myOwnCtx);
wolfSSL_SetEccSharedSecretCtx(ssl, myOwnCtx);
```
## Benchmarks
### TLS
TLS Establishment Times:
* Hardware accelerated ATECC508A: 2.342 seconds avgerage
* Software only: 13.422 seconds average
The TLS connection establishment time is 5.73 times faster with the ATECC508A.
### Cryptographic ECC
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`
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`
For details see our [wolfSSL Atmel ATECC508A](wolfhttps://wolfssl.com/wolfSSL/wolfssl-atmel.html) page.

View File

@ -1,6 +1,6 @@
/* atmel.c
*
* Copyright (C) 2006-2017 wolfSSL Inc.
* Copyright (C) 2006-2018 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
@ -176,7 +176,7 @@ 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(0x04, 0, read_key, sizeof(read_key));
ret = atcab_write_bytes_slot(TLS_SLOT_ENC_PARENT, 0, read_key, sizeof(read_key));
if (ret != ATCA_SUCCESS) {
WOLFSSL_MSG("Failed to write key");
return -1;
@ -235,7 +235,7 @@ void atmel_init(void)
/* show revision information */
atmel_show_rev_info();
/* Configure the ECC508 for use with TLS API funcitons */
/* Configure the ECC508 for use with TLS API functions */
#if 0
atcatls_device_provision();
#else
@ -247,4 +247,254 @@ void atmel_init(void)
}
}
void atmel_finish(void)
{
if (mAtcaInitDone) {
atcatls_finish();
mAtcaInitDone = 0;
}
}
/* Reference PK Callbacks */
#ifdef HAVE_PK_CALLBACKS
int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz,
int ecc_curve, void* ctx)
{
int ret;
uint8_t peerKey[ATECC_PUBKEY_SIZE];
uint8_t* qx = &peerKey[0];
uint8_t* qy = &peerKey[ATECC_PUBKEY_SIZE/2];
(void)ssl;
(void)ctx;
/* only supports P-256 */
if (ecc_curve != ECC_SECP256R1 && keySz != ATECC_PUBKEY_SIZE/2) {
return BAD_FUNC_ARG;
}
/* 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;
}
/* 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);
}
#endif
return ret;
}
int atcatls_create_pms_cb(WOLFSSL* ssl, ecc_key* otherKey,
unsigned char* pubKeyDer, unsigned int* pubKeySz,
unsigned char* out, unsigned int* outlen,
int side, void* ctx)
{
int ret;
ecc_key tmpKey;
uint8_t peerKeyBuf[ATECC_PUBKEY_SIZE];
uint8_t* peerKey = peerKeyBuf;
uint8_t* qx = &peerKey[0];
uint8_t* qy = &peerKey[ATECC_PUBKEY_SIZE/2];
word32 qxLen = ATECC_PUBKEY_SIZE/2, qyLen = ATECC_PUBKEY_SIZE/2;
if (pubKeyDer == NULL || pubKeySz == NULL || out == NULL || outlen == NULL) {
return BAD_FUNC_ARG;
}
(void)ssl;
(void)ctx;
(void)otherKey;
ret = wc_ecc_init(&tmpKey);
if (ret != 0) {
return ret;
}
XMEMSET(peerKey, 0, ATECC_PUBKEY_SIZE);
/* for client: create and export public key */
if (side == WOLFSSL_CLIENT_END) {
/* 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;
}
/* 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);
}
}
/* for server: import public key */
else if (side == WOLFSSL_SERVER_END) {
/* 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;
}
if (ret != 0) {
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;
}
*outlen = ATECC_SIG_SIZE;
exit:
wc_ecc_free(&tmpKey);
#ifdef WOLFSSL_ATECC508A_DEBUG
if (ret != 0) {
printf("atcatls_create_pms_cb: ret %d\n", ret);
}
#endif
return ret;
}
/**
* \brief Sign received digest so far for private key to be proved.
*/
int atcatls_sign_certificate_cb(WOLFSSL* ssl, const byte* in, word32 inSz,
byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
{
int ret;
byte sigRs[ATECC_SIG_SIZE*2];
(void)ssl;
(void)inSz;
(void)key;
(void)keySz;
(void)ctx;
if (in == NULL || out == NULL || outSz == NULL) {
return BAD_FUNC_ARG;
}
ret = atcatls_sign(TLS_SLOT_AUTH_PRIV, in, sigRs);
if (ret != ATCA_SUCCESS) {
ret = WC_HW_E; goto exit;
}
/* Encode with ECDSA signature */
ret = wc_ecc_rs_raw_to_sig(
&sigRs[0], ATECC_SIG_SIZE,
&sigRs[ATECC_SIG_SIZE], ATECC_SIG_SIZE,
out, outSz);
if (ret != 0) {
goto exit;
}
exit:
#ifdef WOLFSSL_ATECC508A_DEBUG
if (ret != 0) {
printf("atcatls_sign_certificate_cb: ret %d\n", ret);
}
#endif
return ret;
}
/**
* \brief Verify signature received from peers to prove peer's private key.
*/
int atcatls_verify_signature_cb(WOLFSSL* ssl, const byte* sig, word32 sigSz,
const byte* hash, word32 hashSz, const byte* key, word32 keySz, int* result,
void* ctx)
{
int ret;
ecc_key tmpKey;
word32 idx = 0;
uint8_t peerKey[ATECC_PUBKEY_SIZE];
uint8_t* qx = &peerKey[0];
uint8_t* qy = &peerKey[ATECC_PUBKEY_SIZE/2];
word32 qxLen = ATECC_PUBKEY_SIZE/2, qyLen = ATECC_PUBKEY_SIZE/2;
byte sigRs[ATECC_SIG_SIZE*2];
word32 rSz = ATECC_SIG_SIZE;
word32 sSz = ATECC_SIG_SIZE;
(void)sigSz;
(void)hashSz;
(void)ctx;
if (ssl == NULL || key == NULL || sig == NULL || hash == NULL || result == NULL) {
return BAD_FUNC_ARG;
}
/* import public key and export public as unsigned bin for hardware */
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);
}
wc_ecc_free(&tmpKey);
(void)qxLen;
(void)qyLen;
}
if (ret != 0) {
goto exit;
}
/* 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 = atcatls_verify(hash, sigRs, peerKey, (bool*)result);
if (ret != ATCA_SUCCESS || !*result) {
ret = WC_HW_E; goto exit;
}
ret = 0; /* success */
exit:
#ifdef WOLFSSL_ATECC508A_DEBUG
if (ret != 0) {
printf("atcatls_verify_signature_cb: ret %d\n", ret);
}
#endif
return ret;
}
#endif /* HAVE_PK_CALLBACKS */
#endif /* WOLFSSL_ATMEL || WOLFSSL_ATECC508A */

View File

@ -1,6 +1,6 @@
/* atecc508.h
*
* Copyright (C) 2006-2017 wolfSSL Inc.
* Copyright (C) 2006-2018 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
@ -24,6 +24,11 @@
#include <stdint.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#ifdef WOLFSSL_ATECC508A
#undef SHA_BLOCK_SIZE
#define SHA_BLOCK_SIZE SHA_BLOCK_SIZE_REMAP
@ -36,6 +41,8 @@
/* ATECC508A only supports ECC-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 */
#define ATECC_MAX_SLOT (0x7) /* Only use 0-7 */
#define ATECC_INVALID_SLOT (-1)
@ -57,10 +64,26 @@ 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);
long atmel_get_curr_time_and_date(long* tm);
int atmel_ecc_alloc(void);
void atmel_ecc_free(int slot);
#ifdef HAVE_PK_CALLBACKS
int atcatls_create_key_cb(WOLFSSL* ssl, ecc_key* key, word32 keySz,
int ecc_curve, void* ctx);
int atcatls_create_pms_cb(WOLFSSL* ssl, 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,
byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx);
int atcatls_verify_signature_cb(WOLFSSL* ssl, const byte* sig, word32 sigSz,
const byte* hash, word32 hashSz, const byte* key, word32 keySz, int* result,
void* ctx);
#endif
#endif /* _ATECC508_H_ */