#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/port/st/stsafe.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifndef NO_ASN
#include <wolfssl/wolfcrypt/asn.h>
#endif
#ifndef STSAFE_INTERFACE_PRINTF
#define STSAFE_INTERFACE_PRINTF(...) WC_DO_NOTHING
#endif
#ifdef WOLFSSL_STSAFE
#ifndef WOLFSSL_STSAFE_INTERFACE_EXTERNAL
#ifdef WOLFSSL_STSAFEA120
#include "stselib.h"
#else
#include <stsafe_a_types.h>
#include <stsafe_a_configuration.h>
#include <stsafe_a_basic.h>
#include <stsafe_a_tools.h>
#include <stsafe_a_administrative.h>
#include <stsafe_a_general_purpose.h>
#include <stsafe_a_private_public_key.h>
#include <stsafe_a_data_partition.h>
#endif
#ifdef WOLFSSL_STSAFEA120
static stse_Handler_t g_stse_handler;
static int g_stse_initialized = 0;
#else
static void* g_stsafe_handle = NULL;
#ifndef STSAFE_HOST_KEY_MAC
static const uint8_t g_host_mac_key[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
#endif
#ifndef STSAFE_HOST_KEY_CIPHER
static const uint8_t g_host_cipher_key[16] = {
0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44,
0x55, 0x55, 0x66, 0x66, 0x77, 0x77, 0x88, 0x88
};
#endif
#endif
static stsafe_curve_id_t g_stsafe_curve_mode = STSAFE_DEFAULT_CURVE;
#define STSAFE_SLOT_TO_DEVCXT(slot) ((void*)(uintptr_t)(slot))
#define STSAFE_DEVCXT_TO_SLOT(devCtx) ((stsafe_slot_t)(uintptr_t)(devCtx))
static int stsafe_get_key_size(stsafe_curve_id_t curve_id)
{
switch (curve_id) {
case STSAFE_ECC_CURVE_P256:
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256)
case STSAFE_ECC_CURVE_BP256:
#endif
return 32;
case STSAFE_ECC_CURVE_P384:
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384)
case STSAFE_ECC_CURVE_BP384:
#endif
return 48;
default:
break;
}
return 0;
}
static stsafe_curve_id_t stsafe_get_ecc_curve_id(int ecc_curve)
{
switch (ecc_curve) {
case ECC_SECP256R1:
return STSAFE_ECC_CURVE_P256;
case ECC_SECP384R1:
return STSAFE_ECC_CURVE_P384;
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256)
case ECC_BRAINPOOLP256R1:
return STSAFE_ECC_CURVE_BP256;
#endif
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384)
case ECC_BRAINPOOLP384R1:
return STSAFE_ECC_CURVE_BP384;
#endif
default:
break;
}
return STSAFE_DEFAULT_CURVE;
}
#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS)
static int stsafe_get_ecc_curve(stsafe_curve_id_t curve_id)
{
switch (curve_id) {
case STSAFE_ECC_CURVE_P256:
return ECC_SECP256R1;
case STSAFE_ECC_CURVE_P384:
return ECC_SECP384R1;
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256)
case STSAFE_ECC_CURVE_BP256:
return ECC_BRAINPOOLP256R1;
#endif
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384)
case STSAFE_ECC_CURVE_BP384:
return ECC_BRAINPOOLP384R1;
#endif
default:
break;
}
return ECC_SECP256R1;
}
#endif
static stsafe_curve_id_t stsafe_get_curve_mode(void)
{
return g_stsafe_curve_mode;
}
static int stsafe_set_curve_mode(stsafe_curve_id_t curve_id)
{
g_stsafe_curve_mode = curve_id;
return 0;
}
#ifdef __GNUC__
__attribute__((unused))
#endif
static void stsafe_unused_funcs(void)
{
#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS)
(void)stsafe_get_ecc_curve;
#endif
(void)stsafe_set_curve_mode;
}
#ifdef WOLFSSL_STSAFEA120
int stsafe_interface_init(void)
{
int rc = 0;
stse_ReturnCode_t ret;
if (g_stse_initialized) {
return 0;
}
ret = stse_set_default_handler_value(&g_stse_handler);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_set_default_handler_value error: %d\n",
ret);
rc = -1;
}
if (rc == 0) {
g_stse_handler.device_type = STSAFE_A120;
#ifdef STSAFE_I2C_BUS
g_stse_handler.io.busID = STSAFE_I2C_BUS;
#else
g_stse_handler.io.busID = 1;
#endif
g_stse_handler.io.BusSpeed = 400;
ret = stse_init(&g_stse_handler);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_init error: %d\n", ret);
rc = -1;
}
}
if (rc == 0) {
g_stse_initialized = 1;
#ifdef USE_STSAFE_VERBOSE
WOLFSSL_MSG("STSAFE-A120 (STSELib) initialized");
#endif
}
return rc;
}
static int stsafe_create_key(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
uint8_t* pPubKeyRaw)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
if (pPubKeyRaw == NULL) {
return BAD_FUNC_ARG;
}
ret = stse_generate_ecc_key_pair(&g_stse_handler, slot,
(stse_ecc_key_type_t)curve_id,
STSAFE_PERSISTENT_KEY_USAGE_LIMIT,
pPubKeyRaw);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair error: %d\n", ret);
rc = (int)ret;
}
return rc;
}
static int stsafe_create_ecdhe_key(stsafe_curve_id_t curve_id,
uint8_t* pPubKeyRaw)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
if (pPubKeyRaw == NULL) {
return BAD_FUNC_ARG;
}
ret = stse_generate_ecc_key_pair(&g_stse_handler,
STSAFE_KEY_SLOT_EPHEMERAL,
(stse_ecc_key_type_t)curve_id,
STSAFE_EPHEMERAL_KEY_USAGE_LIMIT,
pPubKeyRaw);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral) error: %d\n", ret);
rc = (int)ret;
}
return rc;
}
static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
uint8_t* pHash, uint8_t* pSigRS)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
int key_sz = stsafe_get_key_size(curve_id);
if (pHash == NULL || pSigRS == NULL) {
return BAD_FUNC_ARG;
}
ret = stse_ecc_generate_signature(&g_stse_handler, slot, curve_id,
pHash, (uint16_t)key_sz, pSigRS);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_ecc_generate_signature error: %d\n", ret);
rc = (int)ret;
}
return rc;
}
static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash,
uint8_t* pSigRS, uint8_t* pPubKeyX, uint8_t* pPubKeyY,
int32_t* pResult)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
int key_sz = stsafe_get_key_size(curve_id);
uint8_t pubKey[STSAFE_MAX_PUBKEY_RAW_LEN];
uint8_t validity = 0;
if (pHash == NULL || pSigRS == NULL || pPubKeyX == NULL ||
pPubKeyY == NULL || pResult == NULL) {
return BAD_FUNC_ARG;
}
XMEMCPY(pubKey, pPubKeyX, key_sz);
XMEMCPY(pubKey + key_sz, pPubKeyY, key_sz);
ret = stse_ecc_verify_signature(&g_stse_handler, curve_id,
pubKey,
pSigRS,
pHash,
(uint16_t)key_sz,
0,
&validity);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_ecc_verify_signature error: %d\n", ret);
*pResult = 0;
rc = (int)ret;
}
if (rc == STSAFE_A_OK) {
*pResult = (validity != 0) ? 1 : 0;
}
return rc;
}
static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
uint8_t* pPubKeyX, uint8_t* pPubKeyY,
uint8_t* pSharedSecret,
int32_t* pSharedSecretLen)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
int key_sz = stsafe_get_key_size(curve_id);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
uint8_t* peerPubKey = NULL;
#else
uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN];
#endif
if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL ||
pSharedSecretLen == NULL) {
return BAD_FUNC_ARG;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
peerPubKey = (uint8_t*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (peerPubKey == NULL) {
return MEMORY_E;
}
#endif
XMEMCPY(peerPubKey, pPubKeyX, key_sz);
XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz);
ret = stse_ecc_establish_shared_secret(&g_stse_handler, slot,
(stse_ecc_key_type_t)curve_id, peerPubKey, pSharedSecret);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret error: %d (slot: %d, curve_id: %d)\n",
ret, slot, curve_id);
rc = (int)ret;
}
if (rc == STSAFE_A_OK) {
*pSharedSecretLen = (int32_t)key_sz;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(peerPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return rc;
}
static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen)
{
#ifdef WOLFSSL_NO_MALLOC
(void)ppCert;
(void)pCertLen;
return NOT_COMPILED_IN;
#else
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
uint16_t certLen = 0;
uint8_t certZone = 0;
ret = stse_get_device_certificate_size(&g_stse_handler, certZone, &certLen);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size error: %d\n",
ret);
rc = (int)ret;
}
else if (certLen == 0) {
STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size returned zero length\n");
rc = ASN_PARSE_E;
}
if (rc == STSAFE_A_OK) {
*ppCert = (uint8_t*)XMALLOC(certLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*ppCert == NULL) {
rc = MEMORY_E;
}
}
if (rc == STSAFE_A_OK) {
ret = stse_get_device_certificate(&g_stse_handler, certZone, certLen,
*ppCert);
if (ret != STSE_OK) {
XFREE(*ppCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
*ppCert = NULL;
STSAFE_INTERFACE_PRINTF("stse_get_device_certificate error: %d\n",
ret);
rc = (int)ret;
}
}
if (rc == STSAFE_A_OK) {
*pCertLen = certLen;
}
return rc;
#endif
}
#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED)
static int stsafe_get_random(uint8_t* pRandom, uint32_t size)
{
int rc;
stse_ReturnCode_t ret;
uint16_t len = (size > 0xFFFF) ? 0xFFFF : (uint16_t)size;
ret = stse_generate_random(&g_stse_handler, pRandom, len);
if (ret != STSE_OK) {
rc = -1;
}
else {
rc = (int)len;
}
return rc;
}
#endif
#else
static void stsafe_set_host_keys(void* handle)
{
StSafeA_SetHostMacKey(handle, g_host_mac_key);
StSafeA_SetHostCipherKey(handle, g_host_cipher_key);
}
static int stsafe_check_host_keys(void* handle)
{
uint8_t status_code;
StSafeA_HostKeySlotBuffer* pHostKeySlot;
status_code = StSafeA_HostKeySlotQuery(handle, &pHostKeySlot,
STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK && !pHostKeySlot->HostKeyPresenceFlag) {
uint8_t hostKeys[32];
XMEMCPY(hostKeys, g_host_mac_key, 16);
XMEMCPY(hostKeys + 16, g_host_cipher_key, 16);
status_code = StSafeA_PutAttribute(handle, STSAFE_A_HOST_KEY_SLOT_TAG,
hostKeys, sizeof(hostKeys), STSAFE_A_NO_MAC);
}
return status_code;
}
int stsafe_interface_init(void)
{
int rc = 0;
uint8_t status_code;
const uint8_t echo_data[3] = {0x01, 0x02, 0x03};
StSafeA_EchoBuffer* echo_resp = NULL;
if (g_stsafe_handle != NULL) {
return 0;
}
status_code = StSafeA_CreateHandle(&g_stsafe_handle, STSAFE_I2C_ADDR);
if (status_code != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("StSafeA_CreateHandle error: %d\n",
status_code);
rc = -1;
}
if (rc == 0) {
status_code = StSafeA_Echo(g_stsafe_handle, (uint8_t*)echo_data, 3,
&echo_resp, STSAFE_A_NO_MAC);
if (status_code != STSAFE_A_OK ||
XMEMCMP(echo_data, echo_resp->Data, 3) != 0) {
STSAFE_INTERFACE_PRINTF("StSafeA_Echo error: %d\n", status_code);
rc = -1;
}
XFREE(echo_resp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (rc == 0) {
status_code = stsafe_check_host_keys(g_stsafe_handle);
if (status_code != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_check_host_keys error: %d\n",
status_code);
rc = -1;
}
}
#ifdef USE_STSAFE_VERBOSE
if (rc == 0) {
WOLFSSL_MSG("STSAFE-A100/A110 initialized");
}
#endif
return rc;
}
static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id,
uint8_t* pPubKeyRaw)
{
int rc;
uint8_t status_code;
int key_sz = stsafe_get_key_size(curve_id);
stsafe_slot_t slot = STSAFE_KEY_SLOT_1;
StSafeA_CoordinateBuffer* pubX = NULL;
StSafeA_CoordinateBuffer* pubY = NULL;
uint8_t* pointRepId = NULL;
stsafe_set_host_keys(g_stsafe_handle);
status_code = StSafeA_GenerateKeyPair(g_stsafe_handle, slot, 0xFFFF, 1,
(StSafeA_KeyUsageAuthorizationFlags)(
STSAFE_A_COMMAND_RESPONSE_SIGNATURE |
STSAFE_A_MESSAGE_DIGEST_SIGNATURE |
STSAFE_A_KEY_ESTABLISHMENT),
curve_id, &pointRepId, &pubX, &pubY, STSAFE_A_HOST_C_MAC);
if (status_code == STSAFE_A_OK && pointRepId != NULL &&
*pointRepId == STSAFE_A_POINT_REPRESENTATION_ID &&
pubX != NULL && pubY != NULL) {
XMEMCPY(pPubKeyRaw, pubX->Data, pubX->Length);
XMEMCPY(pPubKeyRaw + key_sz, pubY->Data, pubY->Length);
rc = STSAFE_A_OK;
}
else {
rc = (int)(uint8_t)-1;
}
XFREE(pubX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (rc == STSAFE_A_OK && pSlot != NULL) {
*pSlot = slot;
}
return rc;
}
static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
uint8_t* pHash, uint8_t* pSigRS)
{
int rc;
uint8_t status_code;
int key_sz = stsafe_get_key_size(curve_id);
StSafeA_SignatureBuffer* signature = NULL;
StSafeA_HashTypes hashType;
size_t r_length, s_length;
hashType = (curve_id == STSAFE_ECC_CURVE_P384 ||
curve_id == STSAFE_ECC_CURVE_BP384) ?
STSAFE_HASH_SHA384 : STSAFE_HASH_SHA256;
status_code = StSafeA_GenerateSignature(g_stsafe_handle, slot, pHash,
hashType, &signature, STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK && signature != NULL) {
r_length = ((uint16_t)signature->Data[0] << 8) | signature->Data[1];
if (r_length > key_sz || r_length == 0 ||
(size_t)(2 + r_length + 2) > signature->Length) {
rc = ASN_PARSE_E;
}
else {
s_length = ((uint16_t)signature->Data[2 + r_length] << 8) |
signature->Data[3 + r_length];
if (s_length > key_sz || s_length == 0 ||
(size_t)(4 + r_length + s_length) > signature->Length) {
rc = ASN_PARSE_E;
}
else {
XMEMSET(pSigRS, 0, key_sz * 2);
XMEMCPY(pSigRS + (key_sz - r_length), &signature->Data[2], r_length);
XMEMCPY(pSigRS + key_sz + (key_sz - s_length),
&signature->Data[4 + r_length], s_length);
rc = STSAFE_A_OK;
}
}
}
else {
rc = (int)status_code;
}
XFREE(signature, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return rc;
}
static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash,
uint8_t* pSigRS, uint8_t* pPubKeyX, uint8_t* pPubKeyY,
int32_t* pResult)
{
int rc = (int)(uint8_t)-1;
uint8_t status_code;
int key_sz = stsafe_get_key_size(curve_id);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
StSafeA_CoordinateBuffer* X = NULL;
StSafeA_CoordinateBuffer* Y = NULL;
StSafeA_SignatureBuffer* R = NULL;
StSafeA_SignatureBuffer* S = NULL;
StSafeA_SignatureBuffer* Hash = NULL;
#else
byte R_buf[2 + STSAFE_MAX_KEY_LEN];
byte S_buf[2 + STSAFE_MAX_KEY_LEN];
byte Hash_buf[2 + STSAFE_MAX_KEY_LEN];
byte X_buf[2 + STSAFE_MAX_KEY_LEN];
byte Y_buf[2 + STSAFE_MAX_KEY_LEN];
StSafeA_SignatureBuffer* R = (StSafeA_SignatureBuffer*)R_buf;
StSafeA_SignatureBuffer* S = (StSafeA_SignatureBuffer*)S_buf;
StSafeA_SignatureBuffer* Hash = (StSafeA_SignatureBuffer*)Hash_buf;
StSafeA_CoordinateBuffer* X = (StSafeA_CoordinateBuffer*)X_buf;
StSafeA_CoordinateBuffer* Y = (StSafeA_CoordinateBuffer*)Y_buf;
#endif
StSafeA_VerifySignatureBuffer* Verif = NULL;
*pResult = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
R = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
S = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
Hash = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
X = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
Y = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (X == NULL || Y == NULL || R == NULL || S == NULL || Hash == NULL) {
XFREE(R, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(S, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(Hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(X, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(Y, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
R->Length = key_sz;
S->Length = key_sz;
Hash->Length = key_sz;
X->Length = key_sz;
Y->Length = key_sz;
XMEMCPY(R->Data, pSigRS, key_sz);
XMEMCPY(S->Data, pSigRS + key_sz, key_sz);
XMEMCPY(Hash->Data, pHash, key_sz);
XMEMCPY(X->Data, pPubKeyX, key_sz);
XMEMCPY(Y->Data, pPubKeyY, key_sz);
status_code = StSafeA_VerifyMessageSignature(g_stsafe_handle,
curve_id, X, Y, R, S, Hash, &Verif, STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK && Verif != NULL) {
*pResult = Verif->SignatureValidity ? 1 : 0;
if (Verif->SignatureValidity) {
rc = STSAFE_A_OK;
}
}
#ifndef WOLFSSL_NO_MALLOC
XFREE(Verif, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(R, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(S, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(Hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(X, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(Y, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return rc;
}
static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
uint8_t* pPubKeyX, uint8_t* pPubKeyY,
uint8_t* pSharedSecret,
int32_t* pSharedSecretLen)
{
int rc = (int)(uint8_t)-1;
uint8_t status_code;
int key_sz = stsafe_get_key_size(curve_id);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
StSafeA_CoordinateBuffer* peerX = NULL;
StSafeA_CoordinateBuffer* peerY = NULL;
#else
byte peerX_buf[2 + STSAFE_MAX_KEY_LEN];
byte peerY_buf[2 + STSAFE_MAX_KEY_LEN];
StSafeA_CoordinateBuffer* peerX = (StSafeA_CoordinateBuffer*)peerX_buf;
StSafeA_CoordinateBuffer* peerY = (StSafeA_CoordinateBuffer*)peerY_buf;
#endif
StSafeA_SharedSecretBuffer* sharedSecret = NULL;
stsafe_set_host_keys(g_stsafe_handle);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
peerX = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
peerY = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (peerX == NULL || peerY == NULL) {
XFREE(peerX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(peerY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
peerX->Length = key_sz;
peerY->Length = key_sz;
XMEMCPY(peerX->Data, pPubKeyX, key_sz);
XMEMCPY(peerY->Data, pPubKeyY, key_sz);
status_code = StSafeA_EstablishKey(g_stsafe_handle, slot,
peerX, peerY, &sharedSecret, STSAFE_A_HOST_C_MAC);
if (status_code == STSAFE_A_OK && sharedSecret != NULL) {
*pSharedSecretLen = sharedSecret->SharedSecret.Length;
XMEMCPY(pSharedSecret, sharedSecret->SharedSecret.Data,
sharedSecret->SharedSecret.Length);
rc = STSAFE_A_OK;
}
#ifndef WOLFSSL_NO_MALLOC
XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(peerX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(peerY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return rc;
}
static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen)
{
#ifdef WOLFSSL_NO_MALLOC
(void)ppCert;
(void)pCertLen;
return NOT_COMPILED_IN;
#else
int rc = STSAFE_A_OK;
uint8_t status_code;
StSafeA_ReadBuffer* readBuf = NULL;
struct stsafe_a* stsafe_a = (struct stsafe_a*)g_stsafe_handle;
uint8_t step;
uint16_t i;
*pCertLen = 0;
status_code = StSafeA_Read(g_stsafe_handle, 0, 0, STSAFE_A_ALWAYS,
0, 0, 4, &readBuf, STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK && readBuf != NULL && readBuf->Length == 4) {
if (readBuf->Data[0] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
switch (readBuf->Data[1]) {
case (ASN_LONG_LENGTH | 0x01):
*pCertLen = readBuf->Data[2] + 3;
break;
case (ASN_LONG_LENGTH | 0x02):
*pCertLen = ((uint16_t)readBuf->Data[2] << 8) +
readBuf->Data[3] + 4;
break;
default:
if (readBuf->Data[1] < ASN_LONG_LENGTH) {
*pCertLen = readBuf->Data[1] + 2;
}
break;
}
if (*pCertLen == 0) {
rc = ASN_PARSE_E;
}
}
else {
rc = ASN_PARSE_E;
}
}
else {
rc = (int)status_code;
}
XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
readBuf = NULL;
if (rc == STSAFE_A_OK && *pCertLen > 0) {
*ppCert = (uint8_t*)XMALLOC(*pCertLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*ppCert == NULL) {
rc = MEMORY_E;
}
}
if (rc == STSAFE_A_OK && *pCertLen > 0) {
step = 223 - (stsafe_a->CrcSupport ? 2 : 0);
for (i = 0; rc == STSAFE_A_OK && i < *pCertLen / step; i++) {
status_code = StSafeA_Read(g_stsafe_handle, 0, 0,
STSAFE_A_ALWAYS, 0, i * step, step, &readBuf,
STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK) {
XMEMCPY(*ppCert + (i * step), readBuf->Data, readBuf->Length);
}
else {
rc = (int)status_code;
}
XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
readBuf = NULL;
}
if (rc == STSAFE_A_OK && (*pCertLen % step)) {
status_code = StSafeA_Read(g_stsafe_handle, 0, 0,
STSAFE_A_ALWAYS, 0, i * step, *pCertLen % step,
&readBuf, STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK) {
XMEMCPY(*ppCert + (i * step), readBuf->Data, readBuf->Length);
}
else {
rc = (int)status_code;
}
XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
readBuf = NULL;
}
}
return rc;
#endif
}
#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED)
static int stsafe_get_random(uint8_t* pRandom, uint32_t size)
{
int rc;
uint8_t status_code;
StSafeA_GenerateRandomBuffer* rndBuf = NULL;
uint8_t reqSize = (size > 255) ? 255 : (uint8_t)size;
status_code = StSafeA_GenerateRandom(g_stsafe_handle, STSAFE_A_EPHEMERAL,
reqSize, &rndBuf, STSAFE_A_NO_MAC);
if (status_code == STSAFE_A_OK && rndBuf != NULL) {
rc = (int)rndBuf->Length;
XMEMCPY(pRandom, rndBuf->Data, rndBuf->Length);
}
else {
rc = -1;
}
XFREE(rndBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return rc;
}
#endif
#endif
#endif
int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate,
word32* pRawCertificateLen)
{
int err = 0;
if (pRawCertificate == NULL || pRawCertificateLen == NULL) {
err = BAD_FUNC_ARG;
}
#ifdef USE_STSAFE_VERBOSE
if (err == 0) {
WOLFSSL_MSG("SSL_STSAFE_LoadDeviceCertificate");
}
#endif
if (err == 0) {
err = stsafe_read_certificate(pRawCertificate, pRawCertificateLen);
if (err != STSAFE_A_OK) {
err = WC_HW_E;
}
}
return err;
}
#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS)
int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz,
int ecc_curve, void* ctx)
{
int err = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* pubKeyRaw = NULL;
#else
byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN];
#endif
stsafe_slot_t slot;
stsafe_curve_id_t curve_id;
(void)ssl;
(void)ctx;
#ifdef USE_STSAFE_VERBOSE
WOLFSSL_MSG("CreateKeyCb: STSAFE (ECDHE)");
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (pubKeyRaw == NULL) {
err = MEMORY_E;
}
#endif
if (err == 0) {
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
#ifdef WOLFSSL_STSAFEA120
err = stsafe_create_ecdhe_key(curve_id, pubKeyRaw);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_create_ecdhe_key error: %d\n", err);
err = WC_HW_E;
}
slot = STSAFE_KEY_SLOT_EPHEMERAL;
#else
err = stsafe_create_key(&slot, curve_id, pubKeyRaw);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", err);
err = WC_HW_E;
}
#endif
}
if (err == 0) {
err = wc_ecc_import_unsigned(key, pubKeyRaw, &pubKeyRaw[keySz],
NULL, ecc_curve);
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
(void)slot;
return err;
}
int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl,
const unsigned char* sig, unsigned int sigSz,
const unsigned char* hash, unsigned int hashSz,
const unsigned char* keyDer, unsigned int keySz,
int* result, void* ctx)
{
int err = 0;
int eccKeyInit = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* sigRS = NULL;
byte* pubKeyX = NULL;
byte* pubKeyY = NULL;
#else
byte sigRS[STSAFE_MAX_SIG_LEN];
byte pubKeyX[STSAFE_MAX_PUBKEY_RAW_LEN/2];
byte pubKeyY[STSAFE_MAX_PUBKEY_RAW_LEN/2];
#endif
byte* r = NULL;
byte* s = NULL;
word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2;
word32 pubKeyX_len = STSAFE_MAX_PUBKEY_RAW_LEN/2;
word32 pubKeyY_len = STSAFE_MAX_PUBKEY_RAW_LEN/2;
ecc_key eccKey;
word32 inOutIdx = 0;
stsafe_curve_id_t curve_id = STSAFE_ECC_CURVE_P256;
int ecc_curve;
int key_sz = 0;
(void)ssl;
(void)ctx;
(void)hashSz;
#ifdef USE_STSAFE_VERBOSE
WOLFSSL_MSG("VerifyPeerCertCB: STSAFE");
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
pubKeyX = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
pubKeyY = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (sigRS == NULL || pubKeyX == NULL || pubKeyY == NULL) {
err = MEMORY_E;
}
#endif
if (err == 0) {
err = wc_ecc_init(&eccKey);
if (err == 0) {
eccKeyInit = 1;
}
}
if (err == 0) {
err = wc_EccPublicKeyDecode(keyDer, &inOutIdx, &eccKey, keySz);
}
if (err == 0) {
err = wc_ecc_export_public_raw(&eccKey, pubKeyX, &pubKeyX_len,
pubKeyY, &pubKeyY_len);
}
if (err == 0) {
ecc_curve = eccKey.dp->id;
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
key_sz = stsafe_get_key_size(curve_id);
if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) {
err = BAD_FUNC_ARG;
}
}
if (err == 0) {
XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN);
r = &sigRS[0];
s = &sigRS[key_sz];
err = wc_ecc_sig_to_rs(sig, sigSz, r, &r_len, s, &s_len);
}
if (err == 0) {
if ((int)r_len > key_sz || (int)s_len > key_sz) {
err = BAD_FUNC_ARG;
}
}
if (err == 0) {
XMEMMOVE(&sigRS[key_sz - r_len], r, r_len);
XMEMSET(&sigRS[0], 0, key_sz - r_len);
XMEMMOVE(&sigRS[key_sz + (key_sz - s_len)], s, s_len);
XMEMSET(&sigRS[key_sz], 0, key_sz - s_len);
err = stsafe_verify(curve_id, (uint8_t*)hash, sigRS,
pubKeyX, pubKeyY, (int32_t*)result);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_verify error: %d\n", err);
err = WC_HW_E;
}
}
if (eccKeyInit) {
wc_ecc_free(&eccKey);
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return err;
}
int SSL_STSAFE_SignCertificateCb(WOLFSSL* ssl, const byte* in,
word32 inSz, byte* out, word32* outSz,
const byte* key, word32 keySz, void* ctx)
{
int err = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* digest = NULL;
byte* sigRS = NULL;
#else
byte digest[STSAFE_MAX_KEY_LEN];
byte sigRS[STSAFE_MAX_SIG_LEN];
#endif
byte* r;
byte* s;
stsafe_curve_id_t curve_id;
int key_sz;
(void)ssl;
(void)ctx;
(void)key;
(void)keySz;
#ifdef USE_STSAFE_VERBOSE
WOLFSSL_MSG("SignCertificateCb: STSAFE");
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
digest = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (digest == NULL || sigRS == NULL) {
err = MEMORY_E;
}
#endif
if (err == 0) {
curve_id = stsafe_get_curve_mode();
key_sz = stsafe_get_key_size(curve_id);
if ((int)inSz > key_sz)
inSz = key_sz;
XMEMSET(digest, 0, STSAFE_MAX_KEY_LEN);
XMEMCPY(&digest[key_sz - inSz], in, inSz);
XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN);
err = stsafe_sign(STSAFE_KEY_SLOT_0, curve_id, digest, sigRS);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", err);
err = WC_HW_E;
}
}
if (err == 0) {
r = &sigRS[0];
s = &sigRS[key_sz];
err = wc_ecc_rs_raw_to_sig(r, key_sz, s, key_sz, out, outSz);
if (err != 0) {
WOLFSSL_MSG("Error converting RS to Signature");
}
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return err;
}
int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey,
unsigned char* pubKeyDer, unsigned int* pubKeySz,
unsigned char* out, unsigned int* outlen,
int side, void* ctx)
{
int err = 0;
int tmpKeyInit = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* otherKeyX = NULL;
byte* otherKeyY = NULL;
byte* pubKeyRaw = NULL;
#else
byte otherKeyX[STSAFE_MAX_KEY_LEN];
byte otherKeyY[STSAFE_MAX_KEY_LEN];
byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN];
#endif
word32 otherKeyX_len = STSAFE_MAX_KEY_LEN;
word32 otherKeyY_len = STSAFE_MAX_KEY_LEN;
stsafe_slot_t slot = STSAFE_KEY_SLOT_0;
stsafe_curve_id_t curve_id;
ecc_key tmpKey;
int ecc_curve;
int key_sz;
(void)ssl;
(void)ctx;
#ifdef USE_STSAFE_VERBOSE
WOLFSSL_MSG("SharedSecretCb: STSAFE (ECDHE)");
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
otherKeyX = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
otherKeyY = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (otherKeyX == NULL || otherKeyY == NULL || pubKeyRaw == NULL) {
err = MEMORY_E;
}
#endif
if (err == 0) {
err = wc_ecc_init(&tmpKey);
if (err == 0) {
tmpKeyInit = 1;
}
}
if (err == 0) {
ecc_curve = otherKey->dp->id;
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
key_sz = stsafe_get_key_size(curve_id);
if (side == WOLFSSL_CLIENT_END) {
err = wc_ecc_export_public_raw(otherKey, otherKeyX, &otherKeyX_len,
otherKeyY, &otherKeyY_len);
if (err == 0) {
#ifdef WOLFSSL_STSAFEA120
err = stsafe_create_ecdhe_key(curve_id, pubKeyRaw);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_create_ecdhe_key error: %d\n",
err);
err = WC_HW_E;
}
slot = STSAFE_KEY_SLOT_EPHEMERAL;
#else
err = stsafe_create_key(&slot, curve_id, pubKeyRaw);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n",
err);
err = WC_HW_E;
}
#endif
}
if (err == 0) {
err = wc_ecc_import_unsigned(&tmpKey, pubKeyRaw,
&pubKeyRaw[key_sz], NULL, ecc_curve);
}
if (err == 0) {
err = wc_ecc_export_x963(&tmpKey, pubKeyDer, pubKeySz);
}
}
else if (side == WOLFSSL_SERVER_END) {
err = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey,
ecc_curve);
if (err == 0) {
err = wc_ecc_export_public_raw(&tmpKey, otherKeyX,
&otherKeyX_len, otherKeyY, &otherKeyY_len);
}
}
else {
err = BAD_FUNC_ARG;
}
}
if (err == 0) {
err = stsafe_shared_secret(slot, curve_id, otherKeyX, otherKeyY,
out, (int32_t*)outlen);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", err);
err = WC_HW_E;
}
}
if (tmpKeyInit) {
wc_ecc_free(&tmpKey);
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(otherKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(otherKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return err;
}
int SSL_STSAFE_SetupPkCallbacks(WOLFSSL_CTX* ctx)
{
wolfSSL_CTX_SetEccKeyGenCb(ctx, SSL_STSAFE_CreateKeyCb);
wolfSSL_CTX_SetEccSignCb(ctx, SSL_STSAFE_SignCertificateCb);
wolfSSL_CTX_SetEccVerifyCb(ctx, SSL_STSAFE_VerifyPeerCertCb);
wolfSSL_CTX_SetEccSharedSecretCb(ctx, SSL_STSAFE_SharedSecretCb);
wolfSSL_CTX_SetDevId(ctx, 0);
return 0;
}
int SSL_STSAFE_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx)
{
wolfSSL_SetEccKeyGenCtx(ssl, user_ctx);
wolfSSL_SetEccSharedSecretCtx(ssl, user_ctx);
wolfSSL_SetEccSignCtx(ssl, user_ctx);
wolfSSL_SetEccVerifyCtx(ssl, user_ctx);
return 0;
}
#endif
#ifdef WOLF_CRYPTO_CB
int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
{
int rc = CRYPTOCB_UNAVAILABLE;
wolfSTSAFE_CryptoCb_Ctx* stsCtx = (wolfSTSAFE_CryptoCb_Ctx*)ctx;
if (info == NULL || ctx == NULL) {
rc = BAD_FUNC_ARG;
}
(void)devId;
(void)stsCtx;
if (rc != BAD_FUNC_ARG && info->algo_type == WC_ALGO_TYPE_SEED) {
#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED)
rc = 0;
while (rc == 0 && info->seed.sz > 0) {
int len = stsafe_get_random(info->seed.seed, info->seed.sz);
if (len < 0) {
rc = len;
}
else {
info->seed.seed += len;
info->seed.sz -= len;
}
}
#else
rc = CRYPTOCB_UNAVAILABLE;
#endif
}
#ifdef HAVE_ECC
else if (rc != BAD_FUNC_ARG && info->algo_type == WC_ALGO_TYPE_PK) {
#ifdef USE_STSAFE_VERBOSE
STSAFE_INTERFACE_PRINTF("STSAFE Pk: Type %d\n", info->pk.type);
#endif
if (info->pk.type == WC_PK_TYPE_EC_KEYGEN) {
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* pubKeyRaw = NULL;
#else
byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN];
#endif
stsafe_slot_t slot;
stsafe_curve_id_t curve_id;
int ecc_curve, key_sz;
WOLFSSL_MSG("STSAFE: ECC KeyGen");
rc = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (pubKeyRaw == NULL) {
rc = MEMORY_E;
}
#endif
if (rc == 0) {
ecc_curve = info->pk.eckg.curveId;
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
key_sz = stsafe_get_key_size(curve_id);
#ifdef WOLFSSL_STSAFEA120
if (info->pk.eckg.key != NULL && info->pk.eckg.key->devCtx != NULL) {
slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eckg.key->devCtx);
} else {
slot = STSAFE_KEY_SLOT_1;
}
STSAFE_INTERFACE_PRINTF("STSAFE: KeyGen slot %d, curve_id %d\n",
slot, curve_id);
if (slot == STSAFE_KEY_SLOT_EPHEMERAL) {
rc = stsafe_create_ecdhe_key(curve_id, pubKeyRaw);
} else {
rc = stsafe_create_key(slot, curve_id, pubKeyRaw);
}
if (rc != STSE_OK) {
STSAFE_INTERFACE_PRINTF("STSAFE: KeyGen (slot %d) error: %d\n", slot, rc);
rc = WC_HW_E;
} else {
rc = STSAFE_A_OK;
}
#else
rc = stsafe_create_key(&slot, curve_id, pubKeyRaw);
if (rc != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n",
rc);
rc = WC_HW_E;
}
#endif
}
if (rc == 0) {
rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw,
&pubKeyRaw[key_sz], NULL, ecc_curve);
}
if (rc == 0) {
info->pk.eckg.key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot);
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) {
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* digest = NULL;
byte* sigRS = NULL;
#else
byte digest[STSAFE_MAX_KEY_LEN];
byte sigRS[STSAFE_MAX_SIG_LEN];
#endif
byte* r;
byte* s;
stsafe_slot_t slot;
stsafe_curve_id_t curve_id;
int ecc_curve;
word32 inSz = info->pk.eccsign.inlen;
int key_sz;
WOLFSSL_MSG("STSAFE: ECC Sign");
rc = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
digest = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (digest == NULL || sigRS == NULL) {
rc = MEMORY_E;
}
#endif
if (rc == 0) {
if (info->pk.eccsign.key != NULL &&
info->pk.eccsign.key->dp != NULL) {
ecc_curve = info->pk.eccsign.key->dp->id;
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
} else {
curve_id = stsafe_get_curve_mode();
}
key_sz = stsafe_get_key_size(curve_id);
if ((int)inSz > key_sz)
inSz = key_sz;
XMEMSET(digest, 0, STSAFE_MAX_KEY_LEN);
XMEMCPY(&digest[key_sz - inSz], info->pk.eccsign.in, inSz);
XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN);
slot = STSAFE_KEY_SLOT_1;
if (info->pk.eccsign.key != NULL && info->pk.eccsign.key->devCtx != NULL) {
slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eccsign.key->devCtx);
STSAFE_INTERFACE_PRINTF("STSAFE: Sign using slot %d\n", slot);
} else {
WOLFSSL_MSG("STSAFE: Sign using default slot 1");
}
rc = stsafe_sign(slot, curve_id, digest, sigRS);
if (rc != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", rc);
rc = WC_HW_E;
}
}
if (rc == 0) {
r = &sigRS[0];
s = &sigRS[key_sz];
rc = wc_ecc_rs_raw_to_sig(r, key_sz, s, key_sz,
info->pk.eccsign.out, info->pk.eccsign.outlen);
if (rc != 0) {
WOLFSSL_MSG("Error converting RS to Signature");
}
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
else if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) {
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* sigRS = NULL;
byte* pubKeyX = NULL;
byte* pubKeyY = NULL;
#else
byte sigRS[STSAFE_MAX_SIG_LEN];
byte pubKeyX[STSAFE_MAX_PUBKEY_RAW_LEN/2];
byte pubKeyY[STSAFE_MAX_PUBKEY_RAW_LEN/2];
#endif
byte* r = NULL;
byte* s = NULL;
word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2;
word32 pubKeyX_len = STSAFE_MAX_PUBKEY_RAW_LEN/2;
word32 pubKeyY_len = STSAFE_MAX_PUBKEY_RAW_LEN/2;
stsafe_curve_id_t curve_id;
int ecc_curve, key_sz;
WOLFSSL_MSG("STSAFE: ECC Verify");
rc = 0;
if (info->pk.eccverify.key == NULL ||
info->pk.eccverify.key->dp == NULL) {
rc = BAD_FUNC_ARG;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
if (rc == 0) {
sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
pubKeyX = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
pubKeyY = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (sigRS == NULL || pubKeyX == NULL || pubKeyY == NULL) {
rc = MEMORY_E;
}
}
#endif
if (rc == 0) {
ecc_curve = info->pk.eccverify.key->dp->id;
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
key_sz = stsafe_get_key_size(curve_id);
if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) {
rc = BAD_FUNC_ARG;
}
}
if (rc == 0) {
rc = wc_ecc_export_public_raw(info->pk.eccverify.key,
pubKeyX, &pubKeyX_len, pubKeyY, &pubKeyY_len);
}
if (rc == 0) {
XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN);
r = &sigRS[0];
s = &sigRS[key_sz];
rc = wc_ecc_sig_to_rs(info->pk.eccverify.sig,
info->pk.eccverify.siglen, r, &r_len, s, &s_len);
}
if (rc == 0) {
if ((int)r_len > key_sz || (int)s_len > key_sz) {
rc = BAD_FUNC_ARG;
}
}
if (rc == 0) {
XMEMMOVE(&sigRS[key_sz - r_len], r, r_len);
XMEMSET(&sigRS[0], 0, key_sz - r_len);
XMEMMOVE(&sigRS[key_sz + (key_sz - s_len)], s, s_len);
XMEMSET(&sigRS[key_sz], 0, key_sz - s_len);
rc = stsafe_verify(curve_id, (uint8_t*)info->pk.eccverify.hash,
sigRS, pubKeyX, pubKeyY, (int32_t*)info->pk.eccverify.res);
if (rc != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_verify error: %d\n", rc);
rc = WC_HW_E;
}
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
else if (info->pk.type == WC_PK_TYPE_ECDH) {
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* otherKeyX = NULL;
byte* otherKeyY = NULL;
#else
byte otherKeyX[STSAFE_MAX_KEY_LEN];
byte otherKeyY[STSAFE_MAX_KEY_LEN];
#endif
word32 otherKeyX_len = STSAFE_MAX_KEY_LEN;
word32 otherKeyY_len = STSAFE_MAX_KEY_LEN;
stsafe_curve_id_t curve_id;
stsafe_slot_t slot;
int ecc_curve;
WOLFSSL_MSG("STSAFE: ECDH");
rc = 0;
if (info->pk.ecdh.public_key == NULL) {
rc = BAD_FUNC_ARG;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
if (rc == 0) {
otherKeyX = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
otherKeyY = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (otherKeyX == NULL || otherKeyY == NULL) {
rc = MEMORY_E;
}
}
#endif
if (rc == 0) {
if (info->pk.ecdh.private_key != NULL &&
info->pk.ecdh.private_key->dp != NULL) {
ecc_curve = info->pk.ecdh.private_key->dp->id;
} else if (info->pk.ecdh.public_key != NULL &&
info->pk.ecdh.public_key->dp != NULL) {
ecc_curve = info->pk.ecdh.public_key->dp->id;
} else {
rc = BAD_FUNC_ARG;
}
if (rc == 0) {
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
if (curve_id != STSAFE_ECC_CURVE_P256 && curve_id != STSAFE_ECC_CURVE_P384
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256)
&& curve_id != STSAFE_ECC_CURVE_BP256
#endif
#if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384)
&& curve_id != STSAFE_ECC_CURVE_BP384
#endif
) {
rc = BAD_FUNC_ARG;
}
}
if (rc == 0) {
rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key,
otherKeyX, &otherKeyX_len, otherKeyY, &otherKeyY_len);
}
}
if (rc == 0) {
*info->pk.ecdh.outlen = 0;
if (rc == 0) {
slot = STSAFE_KEY_SLOT_EPHEMERAL;
if (info->pk.ecdh.private_key != NULL &&
info->pk.ecdh.private_key->devCtx != NULL) {
slot = STSAFE_DEVCXT_TO_SLOT(info->pk.ecdh.private_key->devCtx);
}
STSAFE_INTERFACE_PRINTF("STSAFE: ECDH with slot %d, curve_id %d\n",
slot, curve_id);
rc = stsafe_shared_secret(slot, curve_id,
otherKeyX, otherKeyY,
info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen);
if (rc != STSAFE_A_OK) {
WOLFSSL_MSG("STSAFE: stsafe_shared_secret failed");
STSAFE_INTERFACE_PRINTF("stsafe_shared_secret "
"error: %d (slot: %d, curve_id: %d)\n",
rc, slot, curve_id);
rc = WC_HW_E;
}
}
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(otherKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(otherKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
}
#endif
if (rc != 0 && rc != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
WOLFSSL_MSG("STSAFE: CryptoCb failed");
#ifdef USE_STSAFE_VERBOSE
STSAFE_INTERFACE_PRINTF("STSAFE: CryptoCb failed %d\n", rc);
#endif
rc = WC_HW_E;
}
return rc;
}
#endif
#endif