/* wolfcrypt-secure.c * * Copyright (C) 2023 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #include "wolfboot/wc_secure.h" #define WCS_ECC_MAX_KEY_LEN (66 * 2) /* Up to ECC-521 */ #define WCS_ECC_MAX_SIGN_LEN (66 * 2) #ifdef HAVE_PK_CALLBACKS /** * \brief Key Gen Callback (used by TLS server) */ int wcs_tls_ecc_keygen(WOLFSSL* ssl, ecc_key* key, word32 keySz, int ecc_curve, void* ctx) { int err; byte pubKeyRaw[WCS_ECC_MAX_KEY_LEN]; int slot_id; int ecc_curve, key_sz; (void)ctx; /* not used in kg */ WOLFSSL_MSG("CreateKeyCb: WC-S"); /* get curve */ ecc_curve = info->pk.eckg.curveId; key_sz = info->pk.eckg.keySz; /* generate new key in secure mode */ err = wcs_ecc_keygen(ecc_curve, key_sz); if (err < 0) { WOLFSSL_MSG_EX("wcs_tls_ecc_keygen error: %d\n", rc); return WC_HW_E; } slot_id = err; rc = wcs_ecc_getpublic(slot_id, pubKeyRaw, WCS_MAX_PUBKEY_RAW_LEN); if (rc < 0) { WOLFSSL_MSG_EX("wcs_ecc_getpublic error: %d\n", rc); /* TODO: drop key just created */ //wcs_drop(slot_id); rc = WC_HW_E; return rc; } /* load generated public key into key, used by wolfSSL */ err = wc_ecc_import_unsigned(key, &pubKeyRaw[0], &pubKeyRaw[keySz], NULL, ecc_curve); return err; } static int wcs_tls_ecc_sign(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, word32* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx) { int slot_id = (int)ctx; (void)keyDer; (void)keySz; if (slot_id < 0) return BAD_FUNC_ARG; ret = wcs_ecc_sign(slot_id, in, inSz, out, outSz); return ret; } static int wcs_tls_ecc_verify(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 slot_id = (int)ctx; (void)keyDer; (void)keySz; if (slot_id < 0) return BAD_FUNC_ARG; ret = wcs_ecc_verify(slot_id, sig, sigSz, hash, hashSz, result); return ret; } static int wcs_tls_ecc_shared_secret(WOLFSSL* ssl, struct ecc_key* otherKey, unsigned char* pubKeyDer, word32* pubKeySz, unsigned char* out, word32* outlen, int side, void* ctx) { int sk_id, pk_id, shared_id; ecc_key tmpKey; uint8_t pubKey_buf[WCS_ECC_MAX_KEY_LEN]; int curve_id, keySz; if (!otherKey) return BAD_FUNC_ARG; curve_id = otherKey->dp.id; keySz = otherKey->dp.keySz; sk_id = (int)ctx; /* for client: create and export public key */ if (side == WOLFSSL_CLIENT_END) { /* TLS v1.3 calls key gen already, so don't do it here */ if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) { ret = wcs_ecc_keygen(otherKey->dp.id, otherKey->dp.keySz); if (ret < 0) return WC_HW_E; sk_id = ret; } else { sk_id = (int)ctx; } if (wc_ecc_export_public_raw(otherKey, pubKey_buf, keySz, pubKey_buf + keySz, keySz) != 0) return BAD_FUNC_ARG; ret = wcs_ecc_import_public(otherKey->dp,id, pubKey_buf, keySz); if (ret < 0) return WC_HW_E; pk_id = ret; } else { /* Server side */ /* Private key is already present */ sk_id = (int)ctx; /* Import x963 pubkey into tmpKey */ ret = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, otherKey->dp->id); if (ret != 0) { return BAD_FUNC_ARG; } ret = wc_ecc_export_public_raw(&tmpKey, pubKey_buf, keySz, pubKey_buf + keySz, keySz); if (ret != 0) { return WC_HW_E; } ret = wcs_ecc_import_public(curve_id, pubKey_buf, keySz); if (ret < 0) { return WC_HW_E; } pk_id = ret; ret = 0; } ret = wcs_ecdh_shared(sk_id, pk_id, *outlen); if (ret < 0) return ret; shared_id = ret; ret = wcs_slot_read(shared_id, out, *outlen); if (ret < 0) return ret; else *outlen = ret; return 0; } #endif /* HAVE_PK_CALLBACKS */ #ifdef WOLF_CRYPTO_CB #define WCS_DEVID 0x57432D53 /* WC-S */ int wolfSSL_WCS_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) { int rc = CRYPTOCB_UNAVAILABLE; int slot_id = (uint32_t) ((uintptr_t)ctx & 0xFFFFFFFF); if (info == NULL) return BAD_FUNC_ARG; if (slot_id < 0) return BAD_FUNC_ARG; if (devId != WCS_DEVID) return BAD_FUNC_ARG; if (info->algo_type == WC_ALGO_TYPE_SEED) { /* use the WCS hardware for RNG seed */ #if !defined(WC_NO_RNG) && defined(USE_WCS_RNG_SEED) while (info->seed.sz > 0) { rc = wcs_get_random(info->seed.seed, info->seed.sz); if (rc < 0) { return rc; } info->seed.seed += rc; info->seed.sz -= rc; } rc = 0; #else rc = CRYPTOCB_UNAVAILABLE; #endif } #ifdef HAVE_ECC else if (info->algo_type == WC_ALGO_TYPE_PK) { #ifdef USE_WCS_VERBOSE WCS_INTERFACE_PRINTF("WCS Pk: Type %d\n", info->pk.type); #endif if (info->pk.type == WC_PK_TYPE_EC_KEYGEN) { byte pubKeyRaw[WCS_MAX_PUBKEY_RAW_LEN]; int ecc_curve, key_sz; WOLFSSL_MSG("WCS: ECC KeyGen"); /* get curve */ ecc_curve = info->pk.eckg.curveId; key_sz = info->pk.eckg.keySz; /* generate new ephemeral key on device */ rc = wcs_ecc_keygen(ecc_curve, key_sz); if (rc < 0) { #ifdef USE_WCS_VERBOSE WCS_INTERFACE_PRINTF("wcs_ecc_keygen error: %d\n", rc); #endif rc = WC_HW_E; return rc; } slot_id = rc; rc = wcs_ecc_getpublic(slot_id, pubKeyRaw, WCS_MAX_PUBKEY_RAW_LEN); if (rc < 0) { #ifdef USE_WCS_VERBOSE WCS_INTERFACE_PRINTF("wcs_ecc_getpublic error: %d\n", rc); #endif /* TODO: drop key just created */ //wcs_drop(slot_id); rc = WC_HW_E; return rc; } rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, pubKeyRaw + key_sz, NULL, ecc_curve); if (rc < 0) { #ifdef USE_WCS_VERBOSE WCS_INTERFACE_PRINTF("wc_ecc_import_unsigned error: %d\n", rc); #endif return rc; } } else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { byte sigRS[WCS_ECC_MAX_SIGN_LEN]; byte *r, *s; word32 inSz = info->pk.eccsign.inlen; int key_sz; WOLFSSL_MSG("WCS: ECC Sign"); key_sz = info->pk.eccsign.keySz; /* truncate input to match key size */ if (inSz > key_sz) inSz = key_sz; rc = wcs_ecc_sign(slot_id, info->pk.eccsign.in, inSz, sigRS, WCS_ECC_MAX_SIGN_LEN); if (rc < 0) { #ifdef USE_WCS_VERBOSE WCS_INTERFACE_PRINTF("wc_ecc_sign error: %d\n", rc); #endif rc = WC_HW_E; return rc; } /* Convert R and S to signature */ r = &sigRS[0]; s = &sigRS[key_sz]; rc = wc_ecc_rs_raw_to_sig((const byte*)r, key_sz, (const byte*)s, key_sz, info->pk.eccsign.out, info->pk.eccsign.outlen); if (rc != 0) { WOLFSSL_MSG("Error converting RS to Signature"); return rc; } } else if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) { /* TODO */ return CRYPTOCB_UNAVAILABLE; } else if (info->pk.type == WC_PK_TYPE_ECDH) { /* TODO */ return CRYPTOCB_UNAVAILABLE; } } #endif /* HAVE_ECC */ /* need to return negative here for error */ if (rc != 0 && rc != CRYPTOCB_UNAVAILABLE) { WOLFSSL_MSG("WCS: CryptoCb failed"); #ifdef USE_WCS_VERBOSE WCS_INTERFACE_PRINTF("WCS: CryptoCb failed %d\n", rc); #endif rc = WC_HW_E; } return rc; } #endif /* WOLF_CRYPTO_CB */