mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 14:50:49 +02:00
c43ab39306
Add a crypto-callback operation for validating an ECC key. Under WOLF_CRYPTO_CB_ONLY_ECC validation now fails closed with NO_VALID_DEVID when no device handles the operation; previously such keys were accepted unvalidated. This is a deliberate compatibility break, documented at the dispatch site.
874 lines
24 KiB
C
874 lines
24 KiB
C
/* swdev.c
|
|
*
|
|
* Copyright (C) 2006-2026 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
|
|
*/
|
|
|
|
/* wc_swdev callback. */
|
|
|
|
#include "swdev.h"
|
|
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
#include <wolfssl/wolfcrypt/types.h>
|
|
#include <wolfssl/wolfcrypt/error-crypt.h>
|
|
#include <wolfssl/wolfcrypt/wc_port.h>
|
|
|
|
#ifndef NO_RSA
|
|
#include <wolfssl/wolfcrypt/rsa.h>
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
#include <wolfssl/wolfcrypt/ecc.h>
|
|
#endif
|
|
#ifndef NO_SHA256
|
|
#include <wolfssl/wolfcrypt/sha256.h>
|
|
#endif
|
|
#ifndef NO_AES
|
|
#include <wolfssl/wolfcrypt/aes.h>
|
|
#endif
|
|
|
|
static int swdev_initialized = 0;
|
|
|
|
static int swdev_ensure_init(void)
|
|
{
|
|
if (!swdev_initialized) {
|
|
int ret = wolfCrypt_Init();
|
|
if (ret != 0)
|
|
return ret;
|
|
swdev_initialized = 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
WC_SWDEV_EXPORT void wc_SwDev_InternalCleanup(void)
|
|
{
|
|
if (swdev_initialized) {
|
|
wolfCrypt_Cleanup();
|
|
swdev_initialized = 0;
|
|
}
|
|
}
|
|
|
|
#ifndef NO_RSA
|
|
static int swdev_rsa(wc_CryptoInfo* info)
|
|
{
|
|
switch (info->pk.rsa.type) {
|
|
case RSA_PUBLIC_ENCRYPT:
|
|
case RSA_PUBLIC_DECRYPT:
|
|
case RSA_PRIVATE_ENCRYPT:
|
|
case RSA_PRIVATE_DECRYPT:
|
|
return wc_RsaFunction(info->pk.rsa.in, info->pk.rsa.inLen,
|
|
info->pk.rsa.out, info->pk.rsa.outLen, info->pk.rsa.type,
|
|
info->pk.rsa.key, info->pk.rsa.rng);
|
|
default:
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
}
|
|
|
|
#ifdef WOLFSSL_KEY_GEN
|
|
static int swdev_rsa_keygen(wc_CryptoInfo* info)
|
|
{
|
|
return wc_MakeRsaKey(info->pk.rsakg.key, info->pk.rsakg.size,
|
|
info->pk.rsakg.e, info->pk.rsakg.rng);
|
|
}
|
|
#endif
|
|
#endif /* !NO_RSA */
|
|
|
|
#ifdef HAVE_ECC
|
|
static int swdev_ecc_keygen(wc_CryptoInfo* info)
|
|
{
|
|
#ifdef HAVE_ECC_DHE
|
|
return wc_ecc_make_key_ex(info->pk.eckg.rng, info->pk.eckg.size,
|
|
info->pk.eckg.key, info->pk.eckg.curveId);
|
|
#else
|
|
(void)info;
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
}
|
|
|
|
static int swdev_ecdh(wc_CryptoInfo* info)
|
|
{
|
|
#ifdef HAVE_ECC_DHE
|
|
return wc_ecc_shared_secret(info->pk.ecdh.private_key,
|
|
info->pk.ecdh.public_key, info->pk.ecdh.out,
|
|
info->pk.ecdh.outlen);
|
|
#else
|
|
(void)info;
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
}
|
|
|
|
static int swdev_ecc_sign(wc_CryptoInfo* info)
|
|
{
|
|
#ifdef HAVE_ECC_SIGN
|
|
return wc_ecc_sign_hash(info->pk.eccsign.in, info->pk.eccsign.inlen,
|
|
info->pk.eccsign.out, info->pk.eccsign.outlen,
|
|
info->pk.eccsign.rng, info->pk.eccsign.key);
|
|
#else
|
|
(void)info;
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
}
|
|
|
|
static int swdev_ecc_verify(wc_CryptoInfo* info)
|
|
{
|
|
#ifdef HAVE_ECC_VERIFY
|
|
return wc_ecc_verify_hash(info->pk.eccverify.sig,
|
|
info->pk.eccverify.siglen, info->pk.eccverify.hash,
|
|
info->pk.eccverify.hashlen, info->pk.eccverify.res,
|
|
info->pk.eccverify.key);
|
|
#else
|
|
(void)info;
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
}
|
|
|
|
static int swdev_ecc_get_size(wc_CryptoInfo* info)
|
|
{
|
|
int sz = wc_ecc_size((ecc_key*)info->pk.ecc_get_size.key);
|
|
if (sz <= 0)
|
|
return sz; /* propagate negative error */
|
|
*info->pk.ecc_get_size.keySize = sz;
|
|
return 0;
|
|
}
|
|
|
|
static int swdev_ecc_get_sig_size(wc_CryptoInfo* info)
|
|
{
|
|
int sz = wc_ecc_sig_size(info->pk.ecc_get_sig_size.key);
|
|
if (sz <= 0)
|
|
return sz;
|
|
*info->pk.ecc_get_sig_size.sigSize = sz;
|
|
return 0;
|
|
}
|
|
|
|
static int swdev_ecc_make_pub(wc_CryptoInfo* info)
|
|
{
|
|
int ret;
|
|
ecc_key* key = info->pk.ecc_make_pub.key;
|
|
ecc_point* pub = wc_ecc_new_point_h(key->heap);
|
|
|
|
if (pub == NULL)
|
|
return MEMORY_E;
|
|
|
|
/* derive Q = d*G in software, then emit X9.63 uncompressed bytes. The
|
|
* point is serialized with the curve size from key->dp so custom-curve
|
|
* keys (idx == ECC_CUSTOM_IDX) work too; wc_ecc_export_point_der rejects
|
|
* negative curve indices. */
|
|
ret = wc_ecc_make_pub(key, pub);
|
|
if (ret == 0) {
|
|
byte* out = info->pk.ecc_make_pub.pubOut;
|
|
word32 curveSz = (word32)key->dp->size;
|
|
word32 ptSz = 1 + 2 * curveSz;
|
|
word32 xSz = curveSz;
|
|
word32 ySz = curveSz;
|
|
|
|
if (*info->pk.ecc_make_pub.pubOutSz < ptSz) {
|
|
ret = BUFFER_E;
|
|
}
|
|
else {
|
|
out[0] = ECC_POINT_UNCOMP;
|
|
ret = wc_export_int(pub->x, out + 1, &xSz, curveSz,
|
|
WC_TYPE_UNSIGNED_BIN);
|
|
if (ret == MP_OKAY)
|
|
ret = wc_export_int(pub->y, out + 1 + curveSz, &ySz, curveSz,
|
|
WC_TYPE_UNSIGNED_BIN);
|
|
if (ret == MP_OKAY)
|
|
*info->pk.ecc_make_pub.pubOutSz = ptSz;
|
|
}
|
|
}
|
|
|
|
wc_ecc_del_point_h(pub, key->heap);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef HAVE_ECC_CHECK_KEY
|
|
static int swdev_ecc_check_pub(wc_CryptoInfo* info)
|
|
{
|
|
ecc_key* key = info->pk.ecc_check_pub.key;
|
|
int ret = 0;
|
|
int validatedFromWire = 0;
|
|
|
|
if (info->pk.ecc_check_pub.pubKeySz == 0) {
|
|
return ECC_INF_E;
|
|
}
|
|
#ifdef HAVE_ECC_KEY_IMPORT
|
|
if (key->idx >= 0) {
|
|
WC_DECLARE_VAR(pubOnly, ecc_key, 1, key->heap);
|
|
WC_ALLOC_VAR(pubOnly, ecc_key, 1, key->heap);
|
|
if (!WC_VAR_OK(pubOnly))
|
|
ret = MEMORY_E;
|
|
else
|
|
ret = wc_ecc_init_ex(pubOnly, key->heap, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
ret = wc_ecc_import_x963_ex(info->pk.ecc_check_pub.pubKey,
|
|
info->pk.ecc_check_pub.pubKeySz, pubOnly, key->dp->id);
|
|
if (ret == 0 &&
|
|
wc_ecc_cmp_point(&pubOnly->pubkey, &key->pubkey) != MP_EQ) {
|
|
/* wire bytes disagree with key->pubkey */
|
|
ret = BAD_STATE_E;
|
|
}
|
|
if (ret == 0)
|
|
ret = wc_ecc_check_key(pubOnly);
|
|
wc_ecc_free(pubOnly);
|
|
}
|
|
WC_FREE_VAR(pubOnly, key->heap);
|
|
validatedFromWire = 1;
|
|
}
|
|
#endif
|
|
if (ret == 0 && (!validatedFromWire ||
|
|
(info->pk.ecc_check_pub.checkPriv &&
|
|
key->type == ECC_PRIVATEKEY))) {
|
|
ret = wc_ecc_check_key(key);
|
|
}
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_ECC_CHECK_KEY */
|
|
#endif /* HAVE_ECC */
|
|
|
|
#ifndef NO_SHA256
|
|
/* Copy hash state between caller's wc_Sha256 and swdev's shadow, leaving
|
|
* admin fields (heap, devId, devCtx, W, async, HW ctx) per-side. */
|
|
static void swdev_sha256_copy_state(wc_Sha256* dst, const wc_Sha256* src)
|
|
{
|
|
XMEMCPY(dst->digest, src->digest, sizeof(dst->digest));
|
|
XMEMCPY(dst->buffer, src->buffer, sizeof(dst->buffer));
|
|
dst->buffLen = src->buffLen;
|
|
dst->loLen = src->loLen;
|
|
dst->hiLen = src->hiLen;
|
|
#ifdef WC_C_DYNAMIC_FALLBACK
|
|
dst->sha_method = src->sha_method;
|
|
#endif
|
|
#ifdef WOLFSSL_HASH_FLAGS
|
|
dst->flags = src->flags;
|
|
#endif
|
|
}
|
|
|
|
/* Run the op on a per-call shadow wc_Sha256 owned by swdev, copying state
|
|
* in and out around it. The caller's struct, allocated by libwolfssl with
|
|
* the software init stripped, can't be used directly. */
|
|
static int swdev_sha256(wc_CryptoInfo* info)
|
|
{
|
|
wc_Sha256* sha256 = info->hash.sha256;
|
|
wc_Sha256 shadow;
|
|
int ret;
|
|
|
|
if (sha256 == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_InitSha256(&shadow);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
swdev_sha256_copy_state(&shadow, sha256);
|
|
|
|
if (info->hash.in != NULL) {
|
|
ret = wc_Sha256Update(&shadow, info->hash.in, info->hash.inSz);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
if (info->hash.digest != NULL) {
|
|
ret = wc_Sha256Final(&shadow, info->hash.digest);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
swdev_sha256_copy_state(sha256, &shadow);
|
|
|
|
out:
|
|
wc_Sha256Free(&shadow);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_SHA224
|
|
/* SHA-224 is SHA-256 with a different IV/truncation; wc_Sha224 is a typedef
|
|
* of wc_Sha256, so the same shadow/copy-state dance applies. */
|
|
static int swdev_sha224(wc_CryptoInfo* info)
|
|
{
|
|
wc_Sha224* sha224 = info->hash.sha224;
|
|
wc_Sha224 shadow;
|
|
int ret;
|
|
|
|
if (sha224 == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_InitSha224(&shadow);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
swdev_sha256_copy_state((wc_Sha256*)&shadow, (const wc_Sha256*)sha224);
|
|
|
|
if (info->hash.in != NULL) {
|
|
ret = wc_Sha224Update(&shadow, info->hash.in, info->hash.inSz);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
if (info->hash.digest != NULL) {
|
|
ret = wc_Sha224Final(&shadow, info->hash.digest);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
swdev_sha256_copy_state((wc_Sha256*)sha224, (const wc_Sha256*)&shadow);
|
|
|
|
out:
|
|
wc_Sha224Free(&shadow);
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_SHA224 */
|
|
#endif /* !NO_SHA256 */
|
|
|
|
#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
|
|
/* Copy hash state between caller's wc_Sha512 and swdev's shadow, leaving
|
|
* admin fields (heap, devId, devCtx, W, async, HW ctx) per-side. The same
|
|
* helper works for SHA-384, SHA-512/224, SHA-512/256 since they all typedef
|
|
* to wc_Sha512. */
|
|
static void swdev_sha512_copy_state(wc_Sha512* dst, const wc_Sha512* src)
|
|
{
|
|
XMEMCPY(dst->digest, src->digest, sizeof(dst->digest));
|
|
XMEMCPY(dst->buffer, src->buffer, sizeof(dst->buffer));
|
|
dst->buffLen = src->buffLen;
|
|
dst->loLen = src->loLen;
|
|
dst->hiLen = src->hiLen;
|
|
#ifdef WC_C_DYNAMIC_FALLBACK
|
|
dst->sha_method = src->sha_method;
|
|
#endif
|
|
#ifdef WOLFSSL_HASH_FLAGS
|
|
dst->flags = src->flags;
|
|
#endif
|
|
#if defined(WOLFSSL_SHA512_HASHTYPE)
|
|
dst->hashType = src->hashType;
|
|
#endif
|
|
}
|
|
#endif /* WOLFSSL_SHA512 || WOLFSSL_SHA384 */
|
|
|
|
#ifdef WOLFSSL_SHA512
|
|
static int swdev_sha512(wc_CryptoInfo* info)
|
|
{
|
|
wc_Sha512* sha512 = info->hash.sha512;
|
|
wc_Sha512 shadow;
|
|
int ret;
|
|
|
|
if (sha512 == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_InitSha512(&shadow);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
swdev_sha512_copy_state(&shadow, sha512);
|
|
|
|
if (info->hash.in != NULL) {
|
|
ret = wc_Sha512Update(&shadow, info->hash.in, info->hash.inSz);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
if (info->hash.digest != NULL) {
|
|
ret = wc_Sha512Final(&shadow, info->hash.digest);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
swdev_sha512_copy_state(sha512, &shadow);
|
|
|
|
out:
|
|
wc_Sha512Free(&shadow);
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(WOLFSSL_NOSHA512_224) && \
|
|
!defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY)
|
|
static int swdev_sha512_224(wc_CryptoInfo* info)
|
|
{
|
|
wc_Sha512 shadow;
|
|
wc_Sha512* sha = info->hash.sha512;
|
|
int ret;
|
|
|
|
if (sha == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_InitSha512_224(&shadow);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
swdev_sha512_copy_state(&shadow, sha);
|
|
|
|
if (info->hash.in != NULL) {
|
|
ret = wc_Sha512_224Update(&shadow, info->hash.in, info->hash.inSz);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
if (info->hash.digest != NULL) {
|
|
ret = wc_Sha512_224Final(&shadow, info->hash.digest);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
swdev_sha512_copy_state(sha, &shadow);
|
|
|
|
out:
|
|
wc_Sha512_224Free(&shadow);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_NOSHA512_256) && \
|
|
!defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY)
|
|
static int swdev_sha512_256(wc_CryptoInfo* info)
|
|
{
|
|
wc_Sha512 shadow;
|
|
wc_Sha512* sha = info->hash.sha512;
|
|
int ret;
|
|
|
|
if (sha == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_InitSha512_256(&shadow);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
swdev_sha512_copy_state(&shadow, sha);
|
|
|
|
if (info->hash.in != NULL) {
|
|
ret = wc_Sha512_256Update(&shadow, info->hash.in, info->hash.inSz);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
if (info->hash.digest != NULL) {
|
|
ret = wc_Sha512_256Final(&shadow, info->hash.digest);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
swdev_sha512_copy_state(sha, &shadow);
|
|
|
|
out:
|
|
wc_Sha512_256Free(&shadow);
|
|
return ret;
|
|
}
|
|
#endif
|
|
#endif /* WOLFSSL_SHA512 */
|
|
|
|
#if defined(WOLFSSL_SHA384) && !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY)
|
|
/* SHA-384 is SHA-512 with a different IV/truncation; wc_Sha384 is a typedef
|
|
* of wc_Sha512, so the shadow/copy-state dance is identical to swdev_sha512.
|
|
* When WOLFSSL_SWDEV_SHA512_GENERAL_ONLY is set this is omitted so swdev declines
|
|
* SHA-384 and the cryptocb dispatcher's SHA-512 fallback path is exercised. */
|
|
static int swdev_sha384(wc_CryptoInfo* info)
|
|
{
|
|
wc_Sha384* sha384 = info->hash.sha384;
|
|
wc_Sha384 shadow;
|
|
int ret;
|
|
|
|
if (sha384 == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_InitSha384(&shadow);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
swdev_sha512_copy_state(&shadow, sha384);
|
|
|
|
if (info->hash.in != NULL) {
|
|
ret = wc_Sha384Update(&shadow, info->hash.in, info->hash.inSz);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
if (info->hash.digest != NULL) {
|
|
ret = wc_Sha384Final(&shadow, info->hash.digest);
|
|
if (ret != 0)
|
|
goto out;
|
|
}
|
|
|
|
swdev_sha512_copy_state(sha384, &shadow);
|
|
|
|
out:
|
|
wc_Sha384Free(&shadow);
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_SHA384 && !WOLFSSL_SWDEV_SHA512_GENERAL_ONLY */
|
|
|
|
#ifndef NO_AES
|
|
/* Rebuild a software AES shadow from the caller's raw devKey, since the
|
|
* caller's Aes has no software round-key schedule under CB_ONLY_AES. */
|
|
static int swdev_aes_shadow_init(Aes* shadow, const Aes* aes, int dir)
|
|
{
|
|
int ret;
|
|
|
|
if (shadow == NULL || aes == NULL)
|
|
return BAD_FUNC_ARG;
|
|
if (aes->keylen <= 0 || aes->keylen > (int)sizeof(aes->devKey))
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_AesInit(shadow, aes->heap, INVALID_DEVID);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = wc_AesSetKey(shadow, (const byte*)aes->devKey,
|
|
(word32)aes->keylen, (const byte*)aes->reg, dir);
|
|
if (ret != 0) {
|
|
wc_AesFree(shadow);
|
|
return ret;
|
|
}
|
|
|
|
XMEMCPY(shadow->tmp, aes->tmp, sizeof(shadow->tmp));
|
|
#if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB) || \
|
|
defined(WOLFSSL_AES_OFB) || defined(WOLFSSL_AES_XTS) || \
|
|
defined(WOLFSSL_AES_CTS)
|
|
shadow->left = aes->left;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void swdev_aes_shadow_sync(Aes* dst, const Aes* src)
|
|
{
|
|
XMEMCPY(dst->reg, src->reg, sizeof(dst->reg));
|
|
XMEMCPY(dst->tmp, src->tmp, sizeof(dst->tmp));
|
|
#if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB) || \
|
|
defined(WOLFSSL_AES_OFB) || defined(WOLFSSL_AES_XTS) || \
|
|
defined(WOLFSSL_AES_CTS)
|
|
dst->left = src->left;
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_AES_CBC
|
|
static int swdev_aes_cbc(wc_CryptoInfo* info)
|
|
{
|
|
Aes* aes = info->cipher.aescbc.aes;
|
|
byte* out = info->cipher.aescbc.out;
|
|
const byte* in = info->cipher.aescbc.in;
|
|
word32 sz = info->cipher.aescbc.sz;
|
|
Aes shadow;
|
|
int ret;
|
|
|
|
ret = swdev_aes_shadow_init(&shadow, aes,
|
|
info->cipher.enc ? AES_ENCRYPTION : AES_DECRYPTION);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
if (info->cipher.enc)
|
|
ret = wc_AesCbcEncrypt(&shadow, out, in, sz);
|
|
#ifdef HAVE_AES_DECRYPT
|
|
else
|
|
ret = wc_AesCbcDecrypt(&shadow, out, in, sz);
|
|
#else
|
|
else
|
|
ret = CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
swdev_aes_shadow_sync(aes, &shadow);
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_AES_CBC */
|
|
|
|
#ifdef WOLFSSL_AES_COUNTER
|
|
static int swdev_aes_ctr(wc_CryptoInfo* info)
|
|
{
|
|
Aes* aes = info->cipher.aesctr.aes;
|
|
Aes shadow;
|
|
int ret;
|
|
|
|
ret = swdev_aes_shadow_init(&shadow, aes, AES_ENCRYPTION);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = wc_AesCtrEncrypt(&shadow, info->cipher.aesctr.out,
|
|
info->cipher.aesctr.in, info->cipher.aesctr.sz);
|
|
swdev_aes_shadow_sync(aes, &shadow);
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT)
|
|
static int swdev_aes_ecb(wc_CryptoInfo* info)
|
|
{
|
|
Aes* aes = info->cipher.aesecb.aes;
|
|
byte* out = info->cipher.aesecb.out;
|
|
const byte* in = info->cipher.aesecb.in;
|
|
word32 sz = info->cipher.aesecb.sz;
|
|
Aes shadow;
|
|
int ret;
|
|
|
|
ret = swdev_aes_shadow_init(&shadow, aes,
|
|
info->cipher.enc ? AES_ENCRYPTION : AES_DECRYPTION);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
#ifdef HAVE_AES_ECB
|
|
if (info->cipher.enc)
|
|
ret = wc_AesEcbEncrypt(&shadow, out, in, sz);
|
|
#ifdef HAVE_AES_DECRYPT
|
|
else
|
|
ret = wc_AesEcbDecrypt(&shadow, out, in, sz);
|
|
#else
|
|
else
|
|
ret = CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
#elif defined(WOLFSSL_AES_DIRECT)
|
|
if (sz != WC_AES_BLOCK_SIZE) {
|
|
ret = CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
else if (info->cipher.enc) {
|
|
ret = wc_AesEncryptDirect(&shadow, out, in);
|
|
}
|
|
#ifdef HAVE_AES_DECRYPT
|
|
else {
|
|
ret = wc_AesDecryptDirect(&shadow, out, in);
|
|
}
|
|
#else
|
|
else {
|
|
ret = CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
#endif
|
|
#else
|
|
(void)out;
|
|
(void)in;
|
|
(void)sz;
|
|
ret = CRYPTOCB_UNAVAILABLE;
|
|
#endif
|
|
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT */
|
|
|
|
/* SWDEV_AES_ONLYECB: when defined, swdev's AES backend returns
|
|
* CRYPTOCB_UNAVAILABLE for AES-GCM so the parent's CB_ONLY_AES host-side
|
|
* GCM software path runs (GHASH on the host; AES-CTR blocks dispatch back
|
|
* through cryptocb ECB). Without this macro, swdev handles GCM end-to-end
|
|
* and the host-side software path is never exercised. */
|
|
#if defined(HAVE_AESGCM) && !defined(SWDEV_AES_ONLYECB)
|
|
static int swdev_aes_gcm(wc_CryptoInfo* info)
|
|
{
|
|
Aes* aes = info->cipher.enc ? info->cipher.aesgcm_enc.aes :
|
|
info->cipher.aesgcm_dec.aes;
|
|
Aes shadow;
|
|
int ret;
|
|
|
|
if (aes == NULL || aes->keylen <= 0 || aes->keylen > (int)sizeof(aes->devKey))
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_AesInit(&shadow, aes->heap, INVALID_DEVID);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = wc_AesGcmSetKey(&shadow, (const byte*)aes->devKey, (word32)aes->keylen);
|
|
if (ret != 0) {
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
|
|
if (info->cipher.enc) {
|
|
ret = wc_AesGcmEncrypt(&shadow,
|
|
info->cipher.aesgcm_enc.out, info->cipher.aesgcm_enc.in,
|
|
info->cipher.aesgcm_enc.sz,
|
|
info->cipher.aesgcm_enc.iv, info->cipher.aesgcm_enc.ivSz,
|
|
info->cipher.aesgcm_enc.authTag,
|
|
info->cipher.aesgcm_enc.authTagSz,
|
|
info->cipher.aesgcm_enc.authIn,
|
|
info->cipher.aesgcm_enc.authInSz);
|
|
}
|
|
else {
|
|
ret = wc_AesGcmDecrypt(&shadow, info->cipher.aesgcm_dec.out,
|
|
info->cipher.aesgcm_dec.in, info->cipher.aesgcm_dec.sz,
|
|
info->cipher.aesgcm_dec.iv, info->cipher.aesgcm_dec.ivSz,
|
|
info->cipher.aesgcm_dec.authTag,
|
|
info->cipher.aesgcm_dec.authTagSz,
|
|
info->cipher.aesgcm_dec.authIn,
|
|
info->cipher.aesgcm_dec.authInSz);
|
|
}
|
|
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_AESGCM && !SWDEV_AES_ONLYECB */
|
|
|
|
#ifdef HAVE_AESCCM
|
|
static int swdev_aes_ccm(wc_CryptoInfo* info)
|
|
{
|
|
Aes* aes = info->cipher.enc ? info->cipher.aesccm_enc.aes :
|
|
info->cipher.aesccm_dec.aes;
|
|
Aes shadow;
|
|
int ret;
|
|
|
|
if (aes == NULL || aes->keylen <= 0 || aes->keylen > (int)sizeof(aes->devKey))
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = wc_AesInit(&shadow, aes->heap, INVALID_DEVID);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = wc_AesCcmSetKey(&shadow, (const byte*)aes->devKey, (word32)aes->keylen);
|
|
if (ret != 0) {
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
|
|
if (info->cipher.enc) {
|
|
ret = wc_AesCcmEncrypt(&shadow,
|
|
info->cipher.aesccm_enc.out, info->cipher.aesccm_enc.in,
|
|
info->cipher.aesccm_enc.sz,
|
|
info->cipher.aesccm_enc.nonce,
|
|
info->cipher.aesccm_enc.nonceSz,
|
|
info->cipher.aesccm_enc.authTag,
|
|
info->cipher.aesccm_enc.authTagSz,
|
|
info->cipher.aesccm_enc.authIn,
|
|
info->cipher.aesccm_enc.authInSz);
|
|
}
|
|
#ifdef HAVE_AES_DECRYPT
|
|
else {
|
|
ret = wc_AesCcmDecrypt(&shadow, info->cipher.aesccm_dec.out,
|
|
info->cipher.aesccm_dec.in, info->cipher.aesccm_dec.sz,
|
|
info->cipher.aesccm_dec.nonce,
|
|
info->cipher.aesccm_dec.nonceSz,
|
|
info->cipher.aesccm_dec.authTag,
|
|
info->cipher.aesccm_dec.authTagSz,
|
|
info->cipher.aesccm_dec.authIn,
|
|
info->cipher.aesccm_dec.authInSz);
|
|
}
|
|
#else
|
|
else {
|
|
ret = CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
#endif
|
|
|
|
wc_AesFree(&shadow);
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_AESCCM */
|
|
#endif /* !NO_AES */
|
|
|
|
WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info,
|
|
void* ctx)
|
|
{
|
|
int ret;
|
|
|
|
(void)devId;
|
|
(void)ctx;
|
|
|
|
if (info == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ret = swdev_ensure_init();
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
switch (info->algo_type) {
|
|
#if !defined(NO_RSA) || defined(HAVE_ECC)
|
|
case WC_ALGO_TYPE_PK:
|
|
switch (info->pk.type) {
|
|
#ifndef NO_RSA
|
|
case WC_PK_TYPE_RSA:
|
|
return swdev_rsa(info);
|
|
#ifdef WOLFSSL_KEY_GEN
|
|
case WC_PK_TYPE_RSA_KEYGEN:
|
|
return swdev_rsa_keygen(info);
|
|
#endif
|
|
#endif /* !NO_RSA */
|
|
#ifdef HAVE_ECC
|
|
case WC_PK_TYPE_EC_KEYGEN:
|
|
return swdev_ecc_keygen(info);
|
|
case WC_PK_TYPE_ECDH:
|
|
return swdev_ecdh(info);
|
|
case WC_PK_TYPE_ECDSA_SIGN:
|
|
return swdev_ecc_sign(info);
|
|
case WC_PK_TYPE_ECDSA_VERIFY:
|
|
return swdev_ecc_verify(info);
|
|
case WC_PK_TYPE_EC_GET_SIZE:
|
|
return swdev_ecc_get_size(info);
|
|
case WC_PK_TYPE_EC_GET_SIG_SIZE:
|
|
return swdev_ecc_get_sig_size(info);
|
|
case WC_PK_TYPE_EC_MAKE_PUB:
|
|
return swdev_ecc_make_pub(info);
|
|
#ifdef HAVE_ECC_CHECK_KEY
|
|
case WC_PK_TYPE_EC_CHECK_PUB_KEY:
|
|
return swdev_ecc_check_pub(info);
|
|
#endif
|
|
#endif /* HAVE_ECC */
|
|
default:
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
#endif
|
|
#if !defined(NO_SHA256) || defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
|
|
case WC_ALGO_TYPE_HASH:
|
|
switch (info->hash.type) {
|
|
#ifndef NO_SHA256
|
|
case WC_HASH_TYPE_SHA256:
|
|
return swdev_sha256(info);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA224
|
|
case WC_HASH_TYPE_SHA224:
|
|
return swdev_sha224(info);
|
|
#endif
|
|
#ifdef WOLFSSL_SHA512
|
|
case WC_HASH_TYPE_SHA512:
|
|
return swdev_sha512(info);
|
|
#if !defined(WOLFSSL_NOSHA512_224) && \
|
|
!defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY)
|
|
case WC_HASH_TYPE_SHA512_224:
|
|
return swdev_sha512_224(info);
|
|
#endif
|
|
#if !defined(WOLFSSL_NOSHA512_256) && \
|
|
!defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY)
|
|
case WC_HASH_TYPE_SHA512_256:
|
|
return swdev_sha512_256(info);
|
|
#endif
|
|
#endif
|
|
#if defined(WOLFSSL_SHA384) && \
|
|
!defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY)
|
|
case WC_HASH_TYPE_SHA384:
|
|
return swdev_sha384(info);
|
|
#endif
|
|
default:
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
#endif
|
|
#ifndef NO_AES
|
|
case WC_ALGO_TYPE_CIPHER:
|
|
switch (info->cipher.type) {
|
|
#ifdef HAVE_AES_CBC
|
|
case WC_CIPHER_AES_CBC:
|
|
return swdev_aes_cbc(info);
|
|
#endif
|
|
#ifdef WOLFSSL_AES_COUNTER
|
|
case WC_CIPHER_AES_CTR:
|
|
return swdev_aes_ctr(info);
|
|
#endif
|
|
#if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT)
|
|
case WC_CIPHER_AES_ECB:
|
|
return swdev_aes_ecb(info);
|
|
#endif
|
|
#if defined(HAVE_AESGCM) && !defined(SWDEV_AES_ONLYECB)
|
|
case WC_CIPHER_AES_GCM:
|
|
return swdev_aes_gcm(info);
|
|
#endif
|
|
#ifdef HAVE_AESCCM
|
|
case WC_CIPHER_AES_CCM:
|
|
return swdev_aes_ccm(info);
|
|
#endif
|
|
default:
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
#endif /* !NO_AES */
|
|
default:
|
|
return CRYPTOCB_UNAVAILABLE;
|
|
}
|
|
}
|