From 681b769f0a18a0a6c260dbbf69c50cb3dda5e90b Mon Sep 17 00:00:00 2001 From: night1rider Date: Wed, 18 Mar 2026 12:58:37 -0600 Subject: [PATCH 01/12] Add SHE (Secure Hardware Extension) support to wolfCrypt --- .github/workflows/os-check.yml | 2 + .wolfssl_known_macro_extras | 2 + CMakeLists.txt | 15 + configure.ac | 10 + src/include.am | 16 + tests/api.c | 6 + tests/api/include.am | 3 + tests/api/test_she.c | 875 +++++++++++++++++++++++++++++++++ tests/api/test_she.h | 70 +++ wolfcrypt/src/cryptocb.c | 118 +++++ wolfcrypt/src/she.c | 702 ++++++++++++++++++++++++++ wolfcrypt/test/test.c | 234 +++++++++ wolfssl/wolfcrypt/cryptocb.h | 44 ++ wolfssl/wolfcrypt/include.am | 1 + wolfssl/wolfcrypt/she.h | 207 ++++++++ wolfssl/wolfcrypt/types.h | 3 +- 16 files changed, 2307 insertions(+), 1 deletion(-) create mode 100644 tests/api/test_she.c create mode 100644 tests/api/test_she.h create mode 100644 wolfcrypt/src/she.c create mode 100644 wolfssl/wolfcrypt/she.h diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index b65270e5670..7575e0ecbe2 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -42,6 +42,8 @@ jobs: '--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation --enable-psk --enable-aesccm --enable-nullcipher CPPFLAGS=-DWOLFSSL_STATIC_RSA', + '--enable-she --enable-cmac', + '--enable-she --enable-cmac --enable-cryptocb --enable-cryptocbutils', '--enable-all CPPFLAGS=''-DNO_AES_192 -DNO_AES_256'' ', '--enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CPPFLAGS=-DWOLFSSL_DH_EXTRA', diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index ba5e47ef67e..fb5da292555 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -883,6 +883,8 @@ WOLFSSL_SE050_NO_TRNG WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT WOLFSSL_SERVER_EXAMPLE WOLFSSL_SETTINGS_FILE +WOLFSSL_SHE +WOLFSSL_SH224 WOLFSSL_SHA256_ALT_CH_MAJ WOLFSSL_SHA512_HASHTYPE WOLFSSL_SHUTDOWNONCE diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f69885656a..53bf54436c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1640,6 +1640,20 @@ if(WOLFSSL_CMAC) endif() endif() +# SHE (Secure Hardware Extension) key update message generation +add_option("WOLFSSL_SHE" + "Enable SHE key update support (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_SHE) + if (NOT WOLFSSL_AES) + message(FATAL_ERROR "Cannot use SHE without AES.") + else() + list(APPEND WOLFSSL_DEFINITIONS + "-DWOLFSSL_SHE") + endif() +endif() + # TODO: - RC2 # - FIPS, again (there's more logic for FIPS in configure.ac) # - Selftest @@ -2816,6 +2830,7 @@ if(WOLFSSL_EXAMPLES) tests/api/test_hash.c tests/api/test_hmac.c tests/api/test_cmac.c + tests/api/test_she.c tests/api/test_des3.c tests/api/test_chacha.c tests/api/test_poly1305.c diff --git a/configure.ac b/configure.ac index e1e142174f6..119cfe4ed91 100644 --- a/configure.ac +++ b/configure.ac @@ -5944,6 +5944,15 @@ fi AS_IF([test "x$ENABLED_CMAC" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT"]) +# SHE (Secure Hardware Extension) key update message generation +AC_ARG_ENABLE([she], + [AS_HELP_STRING([--enable-she],[Enable SHE key update support (default: disabled)])], + [ ENABLED_SHE=$enableval ], + [ ENABLED_SHE=no ] + ) + +AS_IF([test "x$ENABLED_SHE" = "xyes"], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE"]) # AES-XTS AC_ARG_ENABLE([aesxts], @@ -11543,6 +11552,7 @@ AM_CONDITIONAL([BUILD_FIPS_V6],[test $HAVE_FIPS_VERSION = 6]) AM_CONDITIONAL([BUILD_FIPS_V6_PLUS],[test $HAVE_FIPS_VERSION -ge 6]) AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_SHE],[test "x$ENABLED_SHE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SELFTEST],[test "x$ENABLED_SELFTEST" = "xyes"]) AM_CONDITIONAL([BUILD_SHA224],[test "x$ENABLED_SHA224" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SHA3],[test "x$ENABLED_SHA3" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) diff --git a/src/include.am b/src/include.am index 7b012e8481c..864261c39c8 100644 --- a/src/include.am +++ b/src/include.am @@ -159,6 +159,10 @@ if BUILD_CMAC src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif +if BUILD_SHE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +endif + src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ wolfcrypt/src/fips_test.c @@ -424,6 +428,10 @@ if BUILD_CMAC src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif +if BUILD_SHE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +endif + src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ wolfcrypt/src/fips_test.c @@ -673,6 +681,10 @@ if BUILD_CMAC src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif +if BUILD_SHE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +endif + if BUILD_CURVE448 src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve448.c endif @@ -1005,6 +1017,10 @@ if !BUILD_FIPS_V2_PLUS if BUILD_CMAC src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif + +if BUILD_SHE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +endif endif !BUILD_FIPS_V2_PLUS if !BUILD_FIPS_V2 diff --git a/tests/api.c b/tests/api.c index 0d40dbb636b..58e4b18bd40 100644 --- a/tests/api.c +++ b/tests/api.c @@ -202,6 +202,7 @@ #include #include #include +#include #include #include #include @@ -35174,6 +35175,11 @@ TEST_CASE testCases[] = { TEST_HMAC_DECLS, /* CMAC */ TEST_CMAC_DECLS, + /* SHE */ + TEST_SHE_DECLS, +#ifdef WOLF_CRYPTO_CB + TEST_SHE_CB_DECLS, +#endif /* Cipher */ /* Triple-DES */ diff --git a/tests/api/include.am b/tests/api/include.am index 49f6b181ab5..cbe2e10a8ae 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -18,6 +18,8 @@ tests_unit_test_SOURCES += tests/api/test_hash.c # MAC tests_unit_test_SOURCES += tests/api/test_hmac.c tests_unit_test_SOURCES += tests/api/test_cmac.c +# SHE +tests_unit_test_SOURCES += tests/api/test_she.c # Cipher tests_unit_test_SOURCES += tests/api/test_des3.c tests_unit_test_SOURCES += tests/api/test_chacha.c @@ -124,6 +126,7 @@ EXTRA_DIST += tests/api/test_digest.h EXTRA_DIST += tests/api/test_hash.h EXTRA_DIST += tests/api/test_hmac.h EXTRA_DIST += tests/api/test_cmac.h +EXTRA_DIST += tests/api/test_she.h EXTRA_DIST += tests/api/test_des3.h EXTRA_DIST += tests/api/test_chacha.h EXTRA_DIST += tests/api/test_poly1305.h diff --git a/tests/api/test_she.c b/tests/api/test_she.c new file mode 100644 index 00000000000..25cc0ae8830 --- /dev/null +++ b/tests/api/test_she.c @@ -0,0 +1,875 @@ +/* test_she.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 + */ + +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#ifdef WOLF_CRYPTO_CB + #include +#endif +#include +#include + +/* + * Testing wc_SHE_Init() + */ +int test_wc_SHE_Init(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + + /* Valid init with default heap/devId */ + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* Verify heap and devId are stored correctly */ + ExpectTrue(she.heap == NULL); + ExpectIntEQ(she.devId, INVALID_DEVID); + + /* Verify state flags are zeroed */ + ExpectIntEQ(she.generated, 0); + ExpectIntEQ(she.verified, 0); + + /* Verify key material is zeroed */ + { + byte zeros[WC_SHE_KEY_SZ] = {0}; + ExpectIntEQ(XMEMCMP(she.authKey, zeros, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.newKey, zeros, WC_SHE_KEY_SZ), 0); + } + + wc_SHE_Free(&she); + + /* Test bad args: NULL pointer */ + ExpectIntEQ(wc_SHE_Init(NULL, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_Init */ + +/* + * Testing wc_SHE_Free() + */ +int test_wc_SHE_Free(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + + /* Init, then free — should scrub key material */ + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + wc_SHE_Free(&she); + + /* After free, context should be zeroed */ + ExpectIntEQ(she.devId, 0); + ExpectIntEQ(she.generated, 0); + ExpectIntEQ(she.verified, 0); + + /* Free with NULL should not crash */ + wc_SHE_Free(NULL); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_Free */ + +/* + * Testing wc_SHE_Init_Id() + */ +int test_wc_SHE_Init_Id(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) && defined(WOLF_PRIVATE_KEY_ID) + wc_SHE she; + unsigned char testId[] = {0x01, 0x02, 0x03, 0x04}; + + /* Valid init with a 4-byte key ID */ + ExpectIntEQ(wc_SHE_Init_Id(&she, testId, (int)sizeof(testId), + NULL, INVALID_DEVID), 0); + + /* Verify the ID was copied and length is set */ + ExpectIntEQ(she.idLen, (int)sizeof(testId)); + ExpectIntEQ(XMEMCMP(she.id, testId, sizeof(testId)), 0); + + /* Verify label length is cleared */ + ExpectIntEQ(she.labelLen, 0); + + /* Verify heap and devId are stored */ + ExpectTrue(she.heap == NULL); + ExpectIntEQ(she.devId, INVALID_DEVID); + + wc_SHE_Free(&she); + + /* Test bad args: NULL she pointer */ + ExpectIntEQ(wc_SHE_Init_Id(NULL, testId, (int)sizeof(testId), + NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Test bad args: ID length too large */ + ExpectIntEQ(wc_SHE_Init_Id(&she, testId, WC_SHE_MAX_ID_LEN + 1, + NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BUFFER_E)); + + /* Test bad args: negative ID length */ + ExpectIntEQ(wc_SHE_Init_Id(&she, testId, -1, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BUFFER_E)); + + /* Test zero-length ID is valid */ + ExpectIntEQ(wc_SHE_Init_Id(&she, testId, 0, NULL, INVALID_DEVID), 0); + ExpectIntEQ(she.idLen, 0); + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_Init_Id */ + +/* + * Testing wc_SHE_Init_Label() + */ +int test_wc_SHE_Init_Label(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) && defined(WOLF_PRIVATE_KEY_ID) + wc_SHE she; + const char* testLabel = "my_she_key"; + + /* Valid init with a label string */ + ExpectIntEQ(wc_SHE_Init_Label(&she, testLabel, NULL, INVALID_DEVID), 0); + + /* Verify the label was copied and length is set */ + ExpectIntEQ(she.labelLen, (int)XSTRLEN(testLabel)); + ExpectIntEQ(XMEMCMP(she.label, testLabel, XSTRLEN(testLabel)), 0); + + /* Verify ID length is cleared */ + ExpectIntEQ(she.idLen, 0); + + /* Verify heap and devId are stored */ + ExpectTrue(she.heap == NULL); + ExpectIntEQ(she.devId, INVALID_DEVID); + + wc_SHE_Free(&she); + + /* Test bad args: NULL she pointer */ + ExpectIntEQ(wc_SHE_Init_Label(NULL, testLabel, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Test bad args: NULL label */ + ExpectIntEQ(wc_SHE_Init_Label(&she, NULL, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Test bad args: empty label */ + ExpectIntEQ(wc_SHE_Init_Label(&she, "", NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(BUFFER_E)); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_Init_Label */ + +/* + * Testing wc_SHE_SetUID() + */ +int test_wc_SHE_SetUID(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + byte uid[WC_SHE_UID_SZ] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* Valid UID */ + ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ, NULL), 0); + ExpectIntEQ(XMEMCMP(she.uid, uid, WC_SHE_UID_SZ), 0); + + /* Bad args */ + ExpectIntEQ(wc_SHE_SetUID(NULL, uid, WC_SHE_UID_SZ, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetUID(&she, NULL, WC_SHE_UID_SZ, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ - 1, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ + 1, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetUID */ + +/* + * Testing wc_SHE_SetAuthKey() + */ +int test_wc_SHE_SetAuthKey(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + byte key[WC_SHE_KEY_SZ] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* Valid auth key */ + ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, + key, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.authKeyId, WC_SHE_MASTER_ECU_KEY_ID); + ExpectIntEQ(XMEMCMP(she.authKey, key, WC_SHE_KEY_SZ), 0); + + /* Bad args */ + ExpectIntEQ(wc_SHE_SetAuthKey(NULL, 0, key, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetAuthKey(&she, 0, NULL, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetAuthKey(&she, 0, key, WC_SHE_KEY_SZ - 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetAuthKey */ + +/* + * Testing wc_SHE_SetNewKey() + */ +int test_wc_SHE_SetNewKey(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + byte key[WC_SHE_KEY_SZ] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* Valid new key */ + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, key, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.targetKeyId, 4); + ExpectIntEQ(XMEMCMP(she.newKey, key, WC_SHE_KEY_SZ), 0); + + /* Bad args */ + ExpectIntEQ(wc_SHE_SetNewKey(NULL, 4, key, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, NULL, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, key, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetNewKey */ + +/* + * Testing wc_SHE_SetCounter() + */ +int test_wc_SHE_SetCounter(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); + ExpectIntEQ(she.counter, 1); + + ExpectIntEQ(wc_SHE_SetCounter(&she, 0x0FFFFFFF), 0); + ExpectIntEQ(she.counter, 0x0FFFFFFF); + + /* Bad args */ + ExpectIntEQ(wc_SHE_SetCounter(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetCounter */ + +/* + * Testing wc_SHE_SetFlags() + */ +int test_wc_SHE_SetFlags(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); + ExpectIntEQ(she.flags, 0); + + ExpectIntEQ(wc_SHE_SetFlags(&she, WC_SHE_FLAG_WRITE_PROTECT | + WC_SHE_FLAG_BOOT_PROTECT), 0); + ExpectIntEQ(she.flags, WC_SHE_FLAG_WRITE_PROTECT | + WC_SHE_FLAG_BOOT_PROTECT); + + /* Bad args */ + ExpectIntEQ(wc_SHE_SetFlags(NULL, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetFlags */ + +/* + * Testing wc_SHE_SetKdfConstants() + */ +int test_wc_SHE_SetKdfConstants(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + const byte defEncC[] = WC_SHE_KEY_UPDATE_ENC_C; + const byte defMacC[] = WC_SHE_KEY_UPDATE_MAC_C; + byte customEncC[WC_SHE_KEY_SZ]; + byte customMacC[WC_SHE_KEY_SZ]; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* Init should set defaults */ + ExpectIntEQ(XMEMCMP(she.kdfEncC, defEncC, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.kdfMacC, defMacC, WC_SHE_KEY_SZ), 0); + + /* Override both */ + XMEMCPY(customEncC, defEncC, WC_SHE_KEY_SZ); + XMEMCPY(customMacC, defMacC, WC_SHE_KEY_SZ); + customEncC[1] += 0x80; + customMacC[1] += 0x80; + ExpectIntEQ(wc_SHE_SetKdfConstants(&she, + customEncC, WC_SHE_KEY_SZ, + customMacC, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.kdfEncC, customEncC, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.kdfMacC, customMacC, WC_SHE_KEY_SZ), 0); + + /* Override only encC, leave macC unchanged */ + ExpectIntEQ(wc_SHE_SetKdfConstants(&she, + defEncC, WC_SHE_KEY_SZ, NULL, 0), 0); + ExpectIntEQ(XMEMCMP(she.kdfEncC, defEncC, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.kdfMacC, customMacC, WC_SHE_KEY_SZ), 0); + + /* Bad args: NULL she */ + ExpectIntEQ(wc_SHE_SetKdfConstants(NULL, + defEncC, WC_SHE_KEY_SZ, defMacC, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: wrong size */ + ExpectIntEQ(wc_SHE_SetKdfConstants(&she, + defEncC, WC_SHE_KEY_SZ - 1, NULL, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetKdfConstants */ + +/* + * Testing wc_SHE_SetM2Header() and wc_SHE_SetM4Header() + */ +int test_wc_SHE_SetM2M4Header(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she, sheOvr; + byte uid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + byte authKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + byte newKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + byte customHeader[WC_SHE_KEY_SZ] = {0}; + byte m1Def[WC_SHE_M1_SZ], m2Def[WC_SHE_M2_SZ], m3Def[WC_SHE_M3_SZ]; + byte m1Ovr[WC_SHE_M1_SZ], m2Ovr[WC_SHE_M2_SZ], m3Ovr[WC_SHE_M3_SZ]; + + /* --- SetM2Header bad args --- */ + ExpectIntEQ(wc_SHE_SetM2Header(NULL, customHeader, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetM4Header(NULL, customHeader, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* NULL header */ + ExpectIntEQ(wc_SHE_SetM2Header(&she, NULL, WC_SHE_KEY_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Wrong size */ + ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ - 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ + 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Valid set */ + XMEMSET(customHeader, 0xAA, WC_SHE_KEY_SZ); + ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.m2pHeader, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.m2pOverride, 1); + + ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(XMEMCMP(she.m4pHeader, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.m4pOverride, 1); + + wc_SHE_Free(&she); + + /* --- Override produces different M2 than default --- */ + /* Default path: counter=1, flags=0, auto-built headers */ + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); + ExpectIntEQ(wc_SHE_SetAuthKey(&she, 1, authKey, sizeof(authKey)), 0); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); + ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); + ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); + ExpectIntEQ(wc_SHE_ExportKey(&she, + m1Def, WC_SHE_M1_SZ, m2Def, WC_SHE_M2_SZ, + m3Def, WC_SHE_M3_SZ, NULL, 0, NULL, 0, NULL), 0); + wc_SHE_Free(&she); + + /* Override path: same inputs but custom m2pHeader */ + ExpectIntEQ(wc_SHE_Init(&sheOvr, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_SetUID(&sheOvr, uid, sizeof(uid), NULL), 0); + ExpectIntEQ(wc_SHE_SetAuthKey(&sheOvr, 1, authKey, sizeof(authKey)), 0); + ExpectIntEQ(wc_SHE_SetNewKey(&sheOvr, 4, newKey, sizeof(newKey)), 0); + ExpectIntEQ(wc_SHE_SetCounter(&sheOvr, 1), 0); + ExpectIntEQ(wc_SHE_SetFlags(&sheOvr, 0), 0); + /* Set a different header ΓÇö should produce different M2/M3 */ + XMEMSET(customHeader, 0, WC_SHE_KEY_SZ); + customHeader[0] = 0xFF; /* different from auto-built */ + ExpectIntEQ(wc_SHE_SetM2Header(&sheOvr, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&sheOvr), 0); + ExpectIntEQ(wc_SHE_ExportKey(&sheOvr, + m1Ovr, WC_SHE_M1_SZ, m2Ovr, WC_SHE_M2_SZ, + m3Ovr, WC_SHE_M3_SZ, NULL, 0, NULL, 0, NULL), 0); + + /* M1 should be same (UID|IDs unchanged), M2 should differ */ + ExpectIntEQ(XMEMCMP(m1Def, m1Ovr, WC_SHE_M1_SZ), 0); + ExpectIntNE(XMEMCMP(m2Def, m2Ovr, WC_SHE_M2_SZ), 0); + + wc_SHE_Free(&sheOvr); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_SetM2M4Header */ + +/* + * Testing wc_SHE_GenerateM1M2M3() + */ +int test_wc_SHE_GenerateM1M2M3(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + byte uid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + byte authKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + byte newKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); + ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, + authKey, sizeof(authKey)), 0); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); + ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); + ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); + + /* Generate should succeed and set generated flag */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); + ExpectIntEQ(she.generated, 1); + + /* Bad args */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_GenerateM1M2M3 */ + +/* + * Testing wc_She_AesMp16() — Miyaguchi-Preneel compression + */ +int test_wc_She_AesMp16(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + Aes aes; + byte out[WC_SHE_KEY_SZ]; + byte input[WC_SHE_KEY_SZ * 2] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x01, 0x53, 0x48, 0x45, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0 + }; + /* 17 bytes — not block-aligned, triggers zero-padding path */ + byte shortInput[17] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xAA + }; + + ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); + + /* Valid block-aligned input */ + ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), out), 0); + + /* Non-block-aligned input — exercises zero-padding */ + ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_She_AesMp16(&aes, shortInput, sizeof(shortInput), out), 0); + + /* Bad args: NULL aes */ + ExpectIntEQ(wc_She_AesMp16(NULL, input, sizeof(input), out), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: NULL input */ + ExpectIntEQ(wc_She_AesMp16(&aes, NULL, sizeof(input), out), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: zero size */ + ExpectIntEQ(wc_She_AesMp16(&aes, input, 0, out), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: NULL output */ + ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_AesFree(&aes); +#endif + return EXPECT_RESULT(); +} /* END test_wc_She_AesMp16 */ + +/* + * Testing wc_SHE_ExportKey() + */ +int test_wc_SHE_ExportKey(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + byte uid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + byte authKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + byte newKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* Export before generate should return BAD_STATE_E */ + ExpectIntEQ(wc_SHE_ExportKey(&she, + m1, WC_SHE_M1_SZ, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL), + WC_NO_ERR_TRACE(BAD_STATE_E)); + + /* NULL she should return BAD_FUNC_ARG */ + ExpectIntEQ(wc_SHE_ExportKey(NULL, + m1, WC_SHE_M1_SZ, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Set up, generate, and compute verification */ + ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); + ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, + authKey, sizeof(authKey)), 0); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); + ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); + ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); + ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0); + + /* Export only M1/M2/M3 */ + ExpectIntEQ(wc_SHE_ExportKey(&she, + m1, WC_SHE_M1_SZ, + m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ, + NULL, 0, NULL, 0, NULL), 0); + + /* Export only M4/M5 */ + ExpectIntEQ(wc_SHE_ExportKey(&she, + NULL, 0, NULL, 0, NULL, 0, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ, NULL), 0); + + /* Export all M1-M5 */ + ExpectIntEQ(wc_SHE_ExportKey(&she, + m1, WC_SHE_M1_SZ, + m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ, NULL), 0); + + /* Buffer too small */ + ExpectIntEQ(wc_SHE_ExportKey(&she, + m1, 1, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL), + WC_NO_ERR_TRACE(BUFFER_E)); + + /* Export M4/M5 when generated but not verified — BAD_STATE_E */ + { + wc_SHE badShe; + ExpectIntEQ(wc_SHE_Init(&badShe, NULL, INVALID_DEVID), 0); + badShe.generated = 1; /* fake generated state */ + badShe.verified = 0; /* but not verified */ + ExpectIntEQ(wc_SHE_ExportKey(&badShe, + NULL, 0, NULL, 0, NULL, 0, + m4, WC_SHE_M4_SZ, + NULL, 0, NULL), + WC_NO_ERR_TRACE(BAD_STATE_E)); + wc_SHE_Free(&badShe); + } + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_ExportKey */ + +/* + * Testing wc_SHE_GenerateM4M5() + */ +int test_wc_SHE_GenerateM4M5(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + byte uid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + byte authKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + byte newKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + + /* GenerateM4M5 before GenerateM1M2M3 should return BAD_STATE_E */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she), + WC_NO_ERR_TRACE(BAD_STATE_E)); + + /* Set up and generate M1/M2/M3 */ + ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); + ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, + authKey, sizeof(authKey)), 0); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); + ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); + ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); + + /* Now compute M4/M5 */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0); + ExpectIntEQ(she.verified, 1); + + /* Bad args */ + ExpectIntEQ(wc_SHE_GenerateM4M5(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_SHE_Free(&she); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_GenerateM4M5 */ + +#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) && !defined(NO_AES) + +/* Simple SHE callback that falls back to software by resetting devId */ +static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + wc_SHE* she; + int savedDevId; + + (void)ctx; + (void)devIdArg; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLF_CRYPTO_CB_FREE + /* Handle free callback */ + if (info->algo_type == WC_ALGO_TYPE_FREE) { + if (info->free.algo == WC_ALGO_TYPE_SHE) { + she = (wc_SHE*)info->free.obj; + she->devId = INVALID_DEVID; + wc_SHE_Free(she); + return 0; + } + return CRYPTOCB_UNAVAILABLE; + } +#endif + + if (info->algo_type != WC_ALGO_TYPE_SHE) { + return CRYPTOCB_UNAVAILABLE; + } + + she = (wc_SHE*)info->she.she; + if (she == NULL) { + return BAD_FUNC_ARG; + } + + savedDevId = she->devId; + she->devId = INVALID_DEVID; + + switch (info->she.type) { + case WC_SHE_SET_UID: + ret = wc_SHE_SetUID(she, info->she.op.setUid.uid, + info->she.op.setUid.uidSz, + info->she.ctx); + break; + case WC_SHE_GENERATE_M4M5: + ret = wc_SHE_GenerateM4M5(she); + break; + case WC_SHE_EXPORT_KEY: + ret = wc_SHE_ExportKey(she, + info->she.op.exportKey.m1, + info->she.op.exportKey.m1Sz, + info->she.op.exportKey.m2, + info->she.op.exportKey.m2Sz, + info->she.op.exportKey.m3, + info->she.op.exportKey.m3Sz, + info->she.op.exportKey.m4, + info->she.op.exportKey.m4Sz, + info->she.op.exportKey.m5, + info->she.op.exportKey.m5Sz, + info->she.ctx); + break; + default: + ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + break; + } + + she->devId = savedDevId; + return ret; +} + +/* + * Testing SHE callback path for SetUID and GenerateM4M5 + */ +int test_wc_SHE_CryptoCb(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE she; + int sheTestDevId = 54321; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + byte uid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + byte authKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + byte newKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + + /* Register our test callback with a non-INVALID devId */ + ExpectIntEQ(wc_CryptoCb_RegisterDevice(sheTestDevId, + test_she_crypto_cb, NULL), 0); + + /* Init with the test devId so callback path is used */ + ExpectIntEQ(wc_SHE_Init(&she, NULL, sheTestDevId), 0); + + /* SetUID via callback — passes uid through to software */ + ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); + ExpectIntEQ(XMEMCMP(she.uid, uid, WC_SHE_UID_SZ), 0); + + /* Set remaining inputs (software only) */ + ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, + authKey, sizeof(authKey)), 0); + ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); + ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); + ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); + + /* GenerateLoadKey — software, callback not involved */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); + + /* GenerateM4M5 via callback — falls back to software */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0); + ExpectIntEQ(she.verified, 1); + + /* ExportKey via callback path */ + ExpectIntEQ(wc_SHE_ExportKey(&she, + NULL, 0, NULL, 0, NULL, 0, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ, NULL), 0); + + /* Export all M1-M5 via callback */ + { + byte cm1[WC_SHE_M1_SZ]; + byte cm2[WC_SHE_M2_SZ]; + byte cm3[WC_SHE_M3_SZ]; + ExpectIntEQ(wc_SHE_ExportKey(&she, + cm1, WC_SHE_M1_SZ, + cm2, WC_SHE_M2_SZ, + cm3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ, NULL), 0); + } + + wc_SHE_Free(&she); + wc_CryptoCb_UnRegisterDevice(sheTestDevId); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SHE_CryptoCb */ + +#endif /* WOLF_CRYPTO_CB && WOLFSSL_SHE && !NO_AES */ + diff --git a/tests/api/test_she.h b/tests/api/test_she.h new file mode 100644 index 00000000000..61334aaaa33 --- /dev/null +++ b/tests/api/test_she.h @@ -0,0 +1,70 @@ +/* test_she.h + * + * 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 + */ + +#ifndef WOLFCRYPT_TEST_SHE_H +#define WOLFCRYPT_TEST_SHE_H + +#include + +int test_wc_SHE_Init(void); +int test_wc_SHE_Init_Id(void); +int test_wc_SHE_Init_Label(void); +int test_wc_SHE_Free(void); +int test_wc_SHE_SetUID(void); +int test_wc_SHE_SetAuthKey(void); +int test_wc_SHE_SetNewKey(void); +int test_wc_SHE_SetCounter(void); +int test_wc_SHE_SetFlags(void); +int test_wc_SHE_SetKdfConstants(void); +int test_wc_SHE_SetM2M4Header(void); +int test_wc_SHE_GenerateM1M2M3(void); +int test_wc_She_AesMp16(void); +int test_wc_SHE_GenerateM4M5(void); +int test_wc_SHE_ExportKey(void); +#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) +int test_wc_SHE_CryptoCb(void); +#endif + +#define TEST_SHE_DECLS \ + TEST_DECL_GROUP("she", test_wc_SHE_Init), \ + TEST_DECL_GROUP("she", test_wc_SHE_Init_Id), \ + TEST_DECL_GROUP("she", test_wc_SHE_Init_Label), \ + TEST_DECL_GROUP("she", test_wc_SHE_Free), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetUID), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetAuthKey), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetNewKey), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetCounter), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetFlags), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetKdfConstants), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetM2M4Header), \ + TEST_DECL_GROUP("she", test_wc_SHE_GenerateM1M2M3), \ + TEST_DECL_GROUP("she", test_wc_She_AesMp16), \ + TEST_DECL_GROUP("she", test_wc_SHE_GenerateM4M5), \ + TEST_DECL_GROUP("she", test_wc_SHE_ExportKey) + +#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) +#define TEST_SHE_CB_DECLS \ + TEST_DECL_GROUP("she", test_wc_SHE_CryptoCb) +#else +#define TEST_SHE_CB_DECLS +#endif + +#endif /* WOLFCRYPT_TEST_SHE_H */ diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 069dd4e0c6f..af389213f11 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -2035,6 +2035,124 @@ int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, } #endif /* WOLFSSL_CMAC */ +#ifdef WOLFSSL_SHE +int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, word32 uidSz, + const void* ctx) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_SET_UID; + cryptoInfo.she.ctx = ctx; + cryptoInfo.she.op.setUid.uid = uid; + cryptoInfo.she.op.setUid.uidSz = uidSz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, const void* ctx) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_GENERATE_M1M2M3; + cryptoInfo.she.ctx = ctx; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, const void* ctx) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_GENERATE_M4M5; + cryptoInfo.she.ctx = ctx; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_SheExportKey(wc_SHE* she, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const void* ctx) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_EXPORT_KEY; + cryptoInfo.she.ctx = ctx; + cryptoInfo.she.op.exportKey.m1 = m1; + cryptoInfo.she.op.exportKey.m1Sz = m1Sz; + cryptoInfo.she.op.exportKey.m2 = m2; + cryptoInfo.she.op.exportKey.m2Sz = m2Sz; + cryptoInfo.she.op.exportKey.m3 = m3; + cryptoInfo.she.op.exportKey.m3Sz = m3Sz; + cryptoInfo.she.op.exportKey.m4 = m4; + cryptoInfo.she.op.exportKey.m4Sz = m4Sz; + cryptoInfo.she.op.exportKey.m5 = m5; + cryptoInfo.she.op.exportKey.m5Sz = m5Sz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* WOLFSSL_SHE */ + /* returns the default dev id for the current build */ int wc_CryptoCb_DefaultDevID(void) { diff --git a/wolfcrypt/src/she.c b/wolfcrypt/src/she.c new file mode 100644 index 00000000000..06c4f1b44aa --- /dev/null +++ b/wolfcrypt/src/she.c @@ -0,0 +1,702 @@ +/* she.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 2 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 + */ + +/* + * SHE (Secure Hardware Extension) key update message generation. + * + * Software-only computation of M1/M2/M3 for CMD_LOAD_KEY and optional + * M4/M5 verification. Ported from the wolfHSM reference implementation + * (src/wh_she_crypto.c) and adapted to wolfSSL conventions. + */ + +#include + +#ifdef WOLFSSL_SHE + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include +#include +#ifdef WOLF_CRYPTO_CB + #include +#endif + +/* -------------------------------------------------------------------------- */ +/* Miyaguchi-Preneel AES-128 compression (internal) */ +/* */ +/* H_0 = 0 */ +/* H_i = E_{H_{i-1}}(M_i) XOR M_i XOR H_{i-1} */ +/* */ +/* Only valid for AES-128 where key size == block size. */ +/* */ +/* Ported from wolfHSM wh_She_AesMp16_ex() in src/wh_she_crypto.c. */ +/* The caller (GenerateM1M2M3 / GenerateM4M5) owns the Aes object. */ +/* -------------------------------------------------------------------------- */ +int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out) +{ + int ret; + int i = 0; + int j; + byte paddedInput[AES_BLOCK_SIZE]; + byte prev[WC_SHE_KEY_SZ] = {0}; + + if (aes == NULL || in == NULL || inSz == 0 || out == NULL) { + return BAD_FUNC_ARG; + } + + /* Set initial key = H_0 = all zeros */ + ret = wc_AesSetKeyDirect(aes, prev, AES_BLOCK_SIZE, NULL, + AES_ENCRYPTION); + + while (ret == 0 && i < (int)inSz) { + /* Copy next input block, zero-padding if short */ + if ((int)inSz - i < (int)AES_BLOCK_SIZE) { + XMEMCPY(paddedInput, in + i, inSz - i); + XMEMSET(paddedInput + (inSz - i), 0, + AES_BLOCK_SIZE - (inSz - i)); + } + else { + XMEMCPY(paddedInput, in + i, AES_BLOCK_SIZE); + } + + /* E_{H_{i-1}}(M_i) */ + ret = wc_AesEncryptDirect(aes, out, paddedInput); + + if (ret == 0) { + /* H_i = E_{H_{i-1}}(M_i) XOR M_i XOR H_{i-1} */ + for (j = 0; j < (int)AES_BLOCK_SIZE; j++) { + out[j] ^= paddedInput[j]; + out[j] ^= prev[j]; + } + + /* Save H_i as the previous output */ + XMEMCPY(prev, out, AES_BLOCK_SIZE); + + /* Set key = H_i for next block */ + ret = wc_AesSetKeyDirect(aes, out, AES_BLOCK_SIZE, + NULL, AES_ENCRYPTION); + + i += AES_BLOCK_SIZE; + } + } + + return ret; +} + +/* -------------------------------------------------------------------------- */ +/* Context init */ +/* */ +/* Zero-initialize the SHE context and store the heap hint and device ID */ +/* for use by subsequent crypto operations. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_Init(wc_SHE* she, void* heap, int devId) +{ + const byte encC[] = WC_SHE_KEY_UPDATE_ENC_C; + const byte macC[] = WC_SHE_KEY_UPDATE_MAC_C; + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(she, 0, sizeof(wc_SHE)); + she->heap = heap; + she->devId = devId; + XMEMCPY(she->kdfEncC, encC, WC_SHE_KEY_SZ); + XMEMCPY(she->kdfMacC, macC, WC_SHE_KEY_SZ); + /* m2pHeader/m4pHeader are zero from XMEMSET ΓÇö correct for counter=0 */ + + return 0; +} + +#ifdef WOLF_PRIVATE_KEY_ID +/* -------------------------------------------------------------------------- */ +/* Context init with opaque hardware key identifier */ +/* */ +/* Like wc_SHE_Init but also stores an opaque byte-string key ID that */ +/* crypto callback backends can use to look up the authorizing key in */ +/* hardware (e.g. an HSM slot reference or PKCS#11 object handle). */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_Init_Id(wc_SHE* she, unsigned char* id, int len, + void* heap, int devId) +{ + int ret; + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + ret = wc_SHE_Init(she, heap, devId); + if (ret != 0) { + return ret; + } + + if (len < 0 || len > WC_SHE_MAX_ID_LEN) { + return BUFFER_E; + } + + XMEMCPY(she->id, id, (size_t)len); + she->idLen = len; + she->labelLen = 0; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* Context init with human-readable key label */ +/* */ +/* Like wc_SHE_Init but also stores a NUL-terminated string label that */ +/* crypto callback backends can use for string-based key lookup. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_Init_Label(wc_SHE* she, const char* label, + void* heap, int devId) +{ + int ret; + size_t labelLen; + + if (she == NULL || label == NULL) { + return BAD_FUNC_ARG; + } + + ret = wc_SHE_Init(she, heap, devId); + if (ret != 0) { + return ret; + } + + labelLen = XSTRLEN(label); + if (labelLen == 0 || labelLen > WC_SHE_MAX_LABEL_LEN) { + return BUFFER_E; + } + + XMEMCPY(she->label, label, labelLen); + she->labelLen = (int)labelLen; + she->idLen = 0; + + return 0; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* -------------------------------------------------------------------------- */ +/* Context free */ +/* */ +/* Scrub all key material and reset the SHE context to zero. */ +/* Safe to call on a NULL or already-freed context. */ +/* -------------------------------------------------------------------------- */ +void wc_SHE_Free(wc_SHE* she) +{ + if (she == NULL) { + return; + } + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) + if (she->devId != INVALID_DEVID) { + int ret = wc_CryptoCb_Free(she->devId, WC_ALGO_TYPE_SHE, + 0, 0, she); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return; + } + /* fall-through when unavailable */ + } +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_FREE */ + + ForceZero(she, sizeof(wc_SHE)); +} + +/* -------------------------------------------------------------------------- */ +/* Setter functions */ +/* -------------------------------------------------------------------------- */ + +int wc_SHE_SetUID(wc_SHE* she, const byte* uid, word32 uidSz, + const void* ctx) +{ +#ifdef WOLF_CRYPTO_CB + int ret; +#endif + + if (she == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLF_CRYPTO_CB + /* Try callback first if a device is registered */ + if (she->devId != INVALID_DEVID) { + ret = wc_CryptoCb_SheSetUid(she, uid, uidSz, ctx); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + /* fall-through to software path */ + } +#else + (void)ctx; +#endif + + /* Software path: copy caller-provided UID */ + if (uid == NULL || uidSz != WC_SHE_UID_SZ) { + return BAD_FUNC_ARG; + } + + XMEMCPY(she->uid, uid, WC_SHE_UID_SZ); + return 0; +} + +int wc_SHE_SetAuthKey(wc_SHE* she, byte authKeyId, + const byte* authKey, word32 keySz) +{ + if (she == NULL || authKey == NULL || keySz != WC_SHE_KEY_SZ) { + return BAD_FUNC_ARG; + } + + she->authKeyId = authKeyId; + XMEMCPY(she->authKey, authKey, WC_SHE_KEY_SZ); + return 0; +} + +int wc_SHE_SetNewKey(wc_SHE* she, byte targetKeyId, + const byte* newKey, word32 keySz) +{ + if (she == NULL || newKey == NULL || keySz != WC_SHE_KEY_SZ) { + return BAD_FUNC_ARG; + } + + she->targetKeyId = targetKeyId; + XMEMCPY(she->newKey, newKey, WC_SHE_KEY_SZ); + return 0; +} + +int wc_SHE_SetCounter(wc_SHE* she, word32 counter) +{ + if (she == NULL) { + return BAD_FUNC_ARG; + } + + she->counter = counter; + return 0; +} + +int wc_SHE_SetFlags(wc_SHE* she, byte flags) +{ + if (she == NULL) { + return BAD_FUNC_ARG; + } + + she->flags = flags; + return 0; +} + +int wc_SHE_SetKdfConstants(wc_SHE* she, + const byte* encC, word32 encCSz, + const byte* macC, word32 macCSz) +{ + if (she == NULL) { + return BAD_FUNC_ARG; + } + + if (encC != NULL) { + if (encCSz != WC_SHE_KEY_SZ) { + return BAD_FUNC_ARG; + } + XMEMCPY(she->kdfEncC, encC, WC_SHE_KEY_SZ); + } + + if (macC != NULL) { + if (macCSz != WC_SHE_KEY_SZ) { + return BAD_FUNC_ARG; + } + XMEMCPY(she->kdfMacC, macC, WC_SHE_KEY_SZ); + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* Portable big-endian 32-bit store */ +/* -------------------------------------------------------------------------- */ +static WC_INLINE void she_store_be32(byte* dst, word32 val) +{ + dst[0] = (byte)(val >> 24); + dst[1] = (byte)(val >> 16); + dst[2] = (byte)(val >> 8); + dst[3] = (byte)(val); +} + +/* Build M2P/M4P headers from counter and flags using standard SHE packing. + * M2P header: counter(28b) | flags(4b) | zeros(96b) = 16 bytes + * M4P header: counter(28b) | 1(1b) | zeros(99b) = 16 bytes + * Called internally by GenerateM1M2M3/GenerateM4M5 unless overridden. */ +static void she_build_headers(wc_SHE* she) +{ + word32 field; + + if (!she->m2pOverride) { + XMEMSET(she->m2pHeader, 0, WC_SHE_KEY_SZ); + field = (she->counter << WC_SHE_M2_COUNT_SHIFT) | + (she->flags << WC_SHE_M2_FLAGS_SHIFT); + she_store_be32(she->m2pHeader, field); + } + + if (!she->m4pOverride) { + XMEMSET(she->m4pHeader, 0, WC_SHE_KEY_SZ); + field = (she->counter << WC_SHE_M4_COUNT_SHIFT) | WC_SHE_M4_COUNT_PAD; + she_store_be32(she->m4pHeader, field); + } +} + +int wc_SHE_SetM2Header(wc_SHE* she, const byte* header, word32 headerSz) +{ + if (she == NULL || header == NULL || headerSz != WC_SHE_KEY_SZ) { + return BAD_FUNC_ARG; + } + + XMEMCPY(she->m2pHeader, header, WC_SHE_KEY_SZ); + she->m2pOverride = 1; + return 0; +} + +int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz) +{ + if (she == NULL || header == NULL || headerSz != WC_SHE_KEY_SZ) { + return BAD_FUNC_ARG; + } + + XMEMCPY(she->m4pHeader, header, WC_SHE_KEY_SZ); + she->m4pOverride = 1; + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* M1/M2/M3 generation */ +/* */ +/* Derives K1 and K2 from AuthKey via Miyaguchi-Preneel, then builds: */ +/* M1 = UID | TargetKeyID | AuthKeyID */ +/* M2 = AES-CBC(K1, IV=0, counter|flags|pad|newkey) */ +/* M3 = AES-CMAC(K2, M1 | M2) */ +/* */ +/* Ported from wolfHSM wh_She_GenerateLoadableKey() in wh_she_crypto.c. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_GenerateM1M2M3(wc_SHE* she) +{ + int ret = 0; + byte k1[WC_SHE_KEY_SZ]; + byte k2[WC_SHE_KEY_SZ]; + byte kdfInput[WC_SHE_KEY_SZ * 2]; + word32 cmacSz = AES_BLOCK_SIZE; + WC_DECLARE_VAR(aes, Aes, 1, 0); + WC_DECLARE_VAR(cmac, Cmac, 1, 0); + + if (she == NULL) { + return BAD_FUNC_ARG; + } + + /* Build M2P/M4P headers from counter/flags (skipped if overridden) */ + she_build_headers(she); + +#ifdef WOLF_CRYPTO_CB + /* Try callback first ΓÇö hardware may generate M1/M2/M3 directly */ + if (she->devId != INVALID_DEVID) { + ret = wc_CryptoCb_SheGenerateM1M2M3(she, NULL); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0) { + she->generated = 1; + } + return ret; + } + /* fall-through to software path */ + ret = 0; + } +#endif + + WC_ALLOC_VAR(aes, Aes, 1, she->heap); + if (!WC_VAR_OK(aes)) { + return MEMORY_E; + } + + WC_ALLOC_VAR(cmac, Cmac, 1, she->heap); + if (!WC_VAR_OK(cmac)) { + WC_FREE_VAR(aes, she->heap); + return MEMORY_E; + } + + /* Init AES once — used by both MP16 and CBC */ + ret = wc_AesInit(aes, she->heap, she->devId); + if (ret != 0) { + WC_FREE_VAR(aes, she->heap); + WC_FREE_VAR(cmac, she->heap); + return ret; + } + + /* ---- Derive K1 = AES-MP(AuthKey || CENC) ---- */ + XMEMCPY(kdfInput, she->authKey, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfEncC, WC_SHE_KEY_SZ); + ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k1); + + /* ---- Build M1: UID(15B) | TargetKeyID(4b) | AuthKeyID(4b) ---- */ + if (ret == 0) { + XMEMCPY(she->m1, she->uid, WC_SHE_UID_SZ); + she->m1[WC_SHE_M1_KID_OFFSET] = + (byte)((she->targetKeyId << WC_SHE_M1_KID_SHIFT) | + (she->authKeyId << WC_SHE_M1_AID_SHIFT)); + } + + /* ---- Build cleartext M2 and encrypt with K1 ---- */ + if (ret == 0) { + /* M2P = m2pHeader(16B) | newKey(16B) */ + XMEMCPY(she->m2, she->m2pHeader, WC_SHE_KEY_SZ); + XMEMCPY(she->m2 + WC_SHE_M2_KEY_OFFSET, she->newKey, WC_SHE_KEY_SZ); + + /* Encrypt M2 in-place with AES-128-CBC, IV = 0 */ + ret = wc_AesSetKey(aes, k1, WC_SHE_KEY_SZ, NULL, AES_ENCRYPTION); + if (ret == 0) { + ret = wc_AesCbcEncrypt(aes, she->m2, she->m2, WC_SHE_M2_SZ); + } + } + + /* ---- Derive K2 = AES-MP(AuthKey || CMAC) ---- */ + if (ret == 0) { + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfMacC, WC_SHE_KEY_SZ); + ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k2); + } + + /* ---- Build M3 = AES-CMAC(K2, M1 || M2) ---- */ + if (ret == 0) { + ret = wc_InitCmac_ex(cmac, k2, WC_SHE_KEY_SZ, WC_CMAC_AES, + NULL, she->heap, she->devId); + } + if (ret == 0) { + ret = wc_CmacUpdate(cmac, she->m1, WC_SHE_M1_SZ); + } + if (ret == 0) { + ret = wc_CmacUpdate(cmac, she->m2, WC_SHE_M2_SZ); + } + if (ret == 0) { + cmacSz = AES_BLOCK_SIZE; + ret = wc_CmacFinal(cmac, she->m3, &cmacSz); + } + + if (ret == 0) { + she->generated = 1; + } + + /* Scrub temporary key material */ + ForceZero(k1, sizeof(k1)); + ForceZero(k2, sizeof(k2)); + ForceZero(kdfInput, sizeof(kdfInput)); + + wc_AesFree(aes); + WC_FREE_VAR(aes, she->heap); + WC_FREE_VAR(cmac, she->heap); + return ret; +} + +/* -------------------------------------------------------------------------- */ +/* M4/M5 verification computation */ +/* */ +/* Derives K3 and K4 from NewKey via Miyaguchi-Preneel, then builds: */ +/* M4 = UID | KeyID | AuthID | AES-ECB(K3, counter|pad) */ +/* M5 = AES-CMAC(K4, M4) */ +/* */ +/* These are the expected proof messages that SHE hardware should return. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_GenerateM4M5(wc_SHE* she) +{ + int ret = 0; + byte k3[WC_SHE_KEY_SZ]; + byte k4[WC_SHE_KEY_SZ]; + byte kdfInput[WC_SHE_KEY_SZ * 2]; + word32 cmacSz; + WC_DECLARE_VAR(aes, Aes, 1, 0); + WC_DECLARE_VAR(cmac, Cmac, 1, 0); + + if (she == NULL) { + return BAD_FUNC_ARG; + } + if (!she->generated) { + return BAD_STATE_E; + } + +#ifdef WOLF_CRYPTO_CB + /* Try callback first — sends M1/M2/M3 to HW, receives M4/M5 */ + if (she->devId != INVALID_DEVID) { + ret = wc_CryptoCb_SheGenerateM4M5(she, NULL); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0) { + she->verified = 1; + } + return ret; + } + /* fall-through to software path */ + } +#endif + + WC_ALLOC_VAR(aes, Aes, 1, she->heap); + if (!WC_VAR_OK(aes)) { + return MEMORY_E; + } + + WC_ALLOC_VAR(cmac, Cmac, 1, she->heap); + if (!WC_VAR_OK(cmac)) { + WC_FREE_VAR(aes, she->heap); + return MEMORY_E; + } + + /* Init AES once — used by both MP16 and ECB */ + ret = wc_AesInit(aes, she->heap, she->devId); + if (ret != 0) { + WC_FREE_VAR(aes, she->heap); + WC_FREE_VAR(cmac, she->heap); + return ret; + } + + /* ---- Derive K3 = AES-MP(NewKey || CENC) ---- */ + XMEMCPY(kdfInput, she->newKey, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfEncC, WC_SHE_KEY_SZ); + ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k3); + + /* ---- Build M4: UID|IDs header + AES-ECB(K3, m4pHeader) ---- */ + if (ret == 0) { + XMEMSET(she->m4, 0, WC_SHE_M4_SZ); + + XMEMCPY(she->m4, she->uid, WC_SHE_UID_SZ); + she->m4[WC_SHE_M4_KID_OFFSET] = + (byte)((she->targetKeyId << WC_SHE_M4_KID_SHIFT) | + (she->authKeyId << WC_SHE_M4_AID_SHIFT)); + + /* Copy pre-built M4P header (counter|pad) into M4 counter block */ + XMEMCPY(she->m4 + WC_SHE_M4_COUNT_OFFSET, she->m4pHeader, + WC_SHE_KEY_SZ); + + /* Encrypt the 16-byte counter block in-place with AES-ECB */ + ret = wc_AesSetKey(aes, k3, WC_SHE_KEY_SZ, NULL, AES_ENCRYPTION); + if (ret == 0) { + ret = wc_AesEncryptDirect(aes, + she->m4 + WC_SHE_M4_COUNT_OFFSET, + she->m4 + WC_SHE_M4_COUNT_OFFSET); + } + } + + /* ---- Derive K4 = AES-MP(NewKey || CMAC) ---- */ + if (ret == 0) { + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfMacC, WC_SHE_KEY_SZ); + ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k4); + } + + /* ---- Build M5 = AES-CMAC(K4, M4) ---- */ + if (ret == 0) { + cmacSz = AES_BLOCK_SIZE; + ret = wc_AesCmacGenerate_ex(cmac, she->m5, &cmacSz, + she->m4, WC_SHE_M4_SZ, k4, WC_SHE_KEY_SZ, + she->heap, she->devId); + } + + if (ret == 0) { + she->verified = 1; + } + + ForceZero(k3, sizeof(k3)); + ForceZero(k4, sizeof(k4)); + ForceZero(kdfInput, sizeof(kdfInput)); + + wc_AesFree(aes); + WC_FREE_VAR(aes, she->heap); + WC_FREE_VAR(cmac, she->heap); + return ret; +} + +/* -------------------------------------------------------------------------- */ +/* Export Key (callback optional) */ +/* */ +/* Software: copies computed messages from context into caller buffers. */ +/* Any pointer may be NULL to skip that message. */ +/* M1/M2/M3 require generated state, M4/M5 require verified state. */ +/* Callback: asks hardware to export the key as M1-M5. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_ExportKey(wc_SHE* she, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const void* ctx) +{ + if (she == NULL) { + return BAD_FUNC_ARG; + } + + /* Verify buffer sizes for any non-NULL pointers */ + if ((m1 != NULL && m1Sz < WC_SHE_M1_SZ) || + (m2 != NULL && m2Sz < WC_SHE_M2_SZ) || + (m3 != NULL && m3Sz < WC_SHE_M3_SZ) || + (m4 != NULL && m4Sz < WC_SHE_M4_SZ) || + (m5 != NULL && m5Sz < WC_SHE_M5_SZ)) { + return BUFFER_E; + } + +#ifdef WOLF_CRYPTO_CB + if (she->devId != INVALID_DEVID) { + int ret = wc_CryptoCb_SheExportKey(she, + m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz, ctx); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + /* fall-through to software path */ + } +#endif + (void)ctx; + + /* Export M1/M2/M3 if requested */ + if (m1 != NULL || m2 != NULL || m3 != NULL) { + if (!she->generated) { + return BAD_STATE_E; + } + if (m1 != NULL) { + XMEMCPY(m1, she->m1, WC_SHE_M1_SZ); + } + if (m2 != NULL) { + XMEMCPY(m2, she->m2, WC_SHE_M2_SZ); + } + if (m3 != NULL) { + XMEMCPY(m3, she->m3, WC_SHE_M3_SZ); + } + } + + /* Export M4/M5 if requested */ + if (m4 != NULL || m5 != NULL) { + if (!she->verified) { + return BAD_STATE_E; + } + if (m4 != NULL) { + XMEMCPY(m4, she->m4, WC_SHE_M4_SZ); + } + if (m5 != NULL) { + XMEMCPY(m5, she->m5, WC_SHE_M5_SZ); + } + } + + return 0; +} + +#endif /* WOLFSSL_SHE */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 5499ec89471..72b736649f1 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -348,6 +348,9 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #include #include #include +#ifdef WOLFSSL_SHE + #include +#endif #include #include #include @@ -682,6 +685,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes192_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes256_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesofb_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cmac_test(void); +#ifdef WOLFSSL_SHE +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void); +#endif #ifdef HAVE_ASCON WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void); @@ -2873,6 +2879,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("CMAC test passed!\n"); #endif +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + if ( (ret = she_test()) != 0) + TEST_FAIL("SHE test failed!\n", ret); + else + TEST_PASS("SHE test passed!\n"); +#endif + #if defined(WOLFSSL_SIPHASH) if ( (ret = siphash_test()) != 0) TEST_FAIL("SipHash test failed!\n", ret); @@ -56138,6 +56151,171 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cmac_test(void) #endif /* !NO_AES && WOLFSSL_CMAC */ +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) +{ + wc_test_ret_t ret = 0; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + WC_DECLARE_VAR(she, wc_SHE, 1, HEAP_HINT); + + /* SHE specification test vector (from wolfHSM wh_test_she.c) */ + WOLFSSL_SMALL_STACK_STATIC const byte sheUid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + WOLFSSL_SMALL_STACK_STATIC const byte vectorAuthKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + WOLFSSL_SMALL_STACK_STATIC const byte vectorNewKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }; + WOLFSSL_SMALL_STACK_STATIC const byte expM1[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41 + }; + WOLFSSL_SMALL_STACK_STATIC const byte expM2[] = { + 0x2b, 0x11, 0x1e, 0x2d, 0x93, 0xf4, 0x86, 0x56, + 0x6b, 0xcb, 0xba, 0x1d, 0x7f, 0x7a, 0x97, 0x97, + 0xc9, 0x46, 0x43, 0xb0, 0x50, 0xfc, 0x5d, 0x4d, + 0x7d, 0xe1, 0x4c, 0xff, 0x68, 0x22, 0x03, 0xc3 + }; + WOLFSSL_SMALL_STACK_STATIC const byte expM3[] = { + 0xb9, 0xd7, 0x45, 0xe5, 0xac, 0xe7, 0xd4, 0x18, + 0x60, 0xbc, 0x63, 0xc2, 0xb9, 0xf5, 0xbb, 0x46 + }; + WOLFSSL_SMALL_STACK_STATIC const byte expM4[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, + 0xb4, 0x72, 0xe8, 0xd8, 0x72, 0x7d, 0x70, 0xd5, + 0x72, 0x95, 0xe7, 0x48, 0x49, 0xa2, 0x79, 0x17 + }; + WOLFSSL_SMALL_STACK_STATIC const byte expM5[] = { + 0x82, 0x0d, 0x8d, 0x95, 0xdc, 0x11, 0xb4, 0x66, + 0x88, 0x78, 0x16, 0x0c, 0xb2, 0xa4, 0xe2, 0x3e + }; + + WOLFSSL_ENTER("she_test"); + + WC_ALLOC_VAR(she, wc_SHE, 1, HEAP_HINT); + if (!WC_VAR_OK(she)) { + return WC_TEST_RET_ENC_EC(MEMORY_E); + } + + /* ---- Init ---- */ + ret = wc_SHE_Init(she, HEAP_HINT, devId); + if (ret != 0) { + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + /* ---- Set inputs from test vector ---- */ + ret = wc_SHE_SetUID(she, sheUid, sizeof(sheUid), NULL); + if (ret != 0) { + goto exit_SHE_Test; + } + + ret = wc_SHE_SetAuthKey(she, WC_SHE_MASTER_ECU_KEY_ID, + vectorAuthKey, sizeof(vectorAuthKey)); + if (ret != 0) { + goto exit_SHE_Test; + } + + ret = wc_SHE_SetNewKey(she, 4, vectorNewKey, sizeof(vectorNewKey)); + if (ret != 0) { + goto exit_SHE_Test; + } + + ret = wc_SHE_SetCounter(she, 1); + if (ret != 0) { + goto exit_SHE_Test; + } + + ret = wc_SHE_SetFlags(she, 0); + if (ret != 0) { + goto exit_SHE_Test; + } + + /* ---- Generate M1/M2/M3 ---- */ + ret = wc_SHE_GenerateM1M2M3(she); + if (ret != 0) { + goto exit_SHE_Test; + } + + /* ---- Export M1/M2/M3 ---- */ + ret = wc_SHE_ExportKey(she, + m1, WC_SHE_M1_SZ, + m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ, + NULL, 0, + NULL, 0, + NULL); + if (ret != 0) { + goto exit_SHE_Test; + } + + /* ---- Check M1 ---- */ + if (XMEMCMP(m1, expM1, WC_SHE_M1_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Check M2 ---- */ + if (XMEMCMP(m2, expM2, WC_SHE_M2_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Check M3 ---- */ + if (XMEMCMP(m3, expM3, WC_SHE_M3_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Compute M4/M5 ---- */ + ret = wc_SHE_GenerateM4M5(she); + if (ret != 0) { + goto exit_SHE_Test; + } + + /* ---- Export M4/M5 ---- */ + ret = wc_SHE_ExportKey(she, + NULL, 0, + NULL, 0, + NULL, 0, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ, + NULL); + if (ret != 0) { + goto exit_SHE_Test; + } + + /* ---- Check M4 ---- */ + if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Check M5 ---- */ + if (XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + +exit_SHE_Test: + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return ret; +} + +#endif /* WOLFSSL_SHE && !NO_AES */ + #if defined(WOLFSSL_SIPHASH) #if WOLFSSL_SIPHASH_CROUNDS == 2 && WOLFSSL_SIPHASH_DROUNDS == 4 @@ -66111,6 +66289,16 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) break; } } + else if (info->free.algo == WC_ALGO_TYPE_SHE) { +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + wc_SHE* she = (wc_SHE*)info->free.obj; + she->devId = INVALID_DEVID; + wc_SHE_Free(she); + ret = 0; +#else + ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); +#endif + } else { ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); } @@ -66216,7 +66404,53 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) } #endif /* HAVE_CMAC_KDF */ } +#if defined(WOLFSSL_SHE) && !defined(NO_AES) + else if (info->algo_type == WC_ALGO_TYPE_SHE) { + wc_SHE* she = (wc_SHE*)info->she.she; + int savedDevId; + if (she == NULL) { + return NOT_COMPILED_IN; + } + + /* Save and override devId so re-call uses software path */ + savedDevId = she->devId; + she->devId = INVALID_DEVID; + + switch (info->she.type) { + case WC_SHE_SET_UID: + ret = wc_SHE_SetUID(she, info->she.op.setUid.uid, + info->she.op.setUid.uidSz, + info->she.ctx); + break; + case WC_SHE_GENERATE_M4M5: + /* Re-call with software devId — fills she->m4/m5 */ + ret = wc_SHE_GenerateM4M5(she); + break; + case WC_SHE_EXPORT_KEY: + /* Fall back to software export */ + ret = wc_SHE_ExportKey(she, + info->she.op.exportKey.m1, + info->she.op.exportKey.m1Sz, + info->she.op.exportKey.m2, + info->she.op.exportKey.m2Sz, + info->she.op.exportKey.m3, + info->she.op.exportKey.m3Sz, + info->she.op.exportKey.m4, + info->she.op.exportKey.m4Sz, + info->she.op.exportKey.m5, + info->she.op.exportKey.m5Sz, + info->she.ctx); + break; + default: + ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); + break; + } + + /* Restore devId */ + she->devId = savedDevId; + } +#endif /* WOLFSSL_SHE && !NO_AES */ (void)devIdArg; (void)myCtx; diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index d4f30642f54..ba322cf14d1 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -65,6 +65,9 @@ #ifdef WOLFSSL_CMAC #include #endif +#ifdef WOLFSSL_SHE + #include +#endif #ifdef HAVE_ED25519 #include #endif @@ -458,6 +461,31 @@ typedef struct wc_CryptoInfo { int type; } cmac; #endif +#ifdef WOLFSSL_SHE + struct { + void* she; /* wc_SHE* context */ + int type; /* enum wc_SheType - discriminator */ + const void* ctx; /* read-only caller context */ + union { + struct { + const byte* uid; /* caller-provided UID (may be NULL) */ + word32 uidSz; /* size of uid buffer */ + } setUid; + struct { + byte* m1; /* output: M1 */ + word32 m1Sz; + byte* m2; /* output: M2 */ + word32 m2Sz; + byte* m3; /* output: M3 */ + word32 m3Sz; + byte* m4; /* output: M4 */ + word32 m4Sz; + byte* m5; /* output: M5 */ + word32 m5Sz; + } exportKey; + } op; + } she; +#endif #ifndef NO_CERTS struct { const byte *id; @@ -758,6 +786,22 @@ WOLFSSL_LOCAL int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, void* ctx); #endif +#ifdef WOLFSSL_SHE +WOLFSSL_LOCAL int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, + word32 uidSz, const void* ctx); +WOLFSSL_LOCAL int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, + const void* ctx); +WOLFSSL_LOCAL int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, + const void* ctx); +WOLFSSL_LOCAL int wc_CryptoCb_SheExportKey(wc_SHE* she, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const void* ctx); +#endif + #ifndef NO_CERTS WOLFSSL_LOCAL int wc_CryptoCb_GetCert(int devId, const char *label, word32 labelLen, const byte *id, word32 idLen, byte** out, diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 85313cb158d..02e300de0cb 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -10,6 +10,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/poly1305.h \ wolfssl/wolfcrypt/camellia.h \ wolfssl/wolfcrypt/cmac.h \ + wolfssl/wolfcrypt/she.h \ wolfssl/wolfcrypt/coding.h \ wolfssl/wolfcrypt/compress.h \ wolfssl/wolfcrypt/des3.h \ diff --git a/wolfssl/wolfcrypt/she.h b/wolfssl/wolfcrypt/she.h new file mode 100644 index 00000000000..0b49a5c6773 --- /dev/null +++ b/wolfssl/wolfcrypt/she.h @@ -0,0 +1,207 @@ +/* she.h + * + * 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 2 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 + */ + + +#ifndef WOLF_CRYPT_SHE_H +#define WOLF_CRYPT_SHE_H + +#include + +#ifdef WOLFSSL_SHE + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#define WC_SHE_KEY_SZ 16 +#define WC_SHE_UID_SZ 15 + +#define WC_SHE_M1_SZ 16 +#define WC_SHE_M2_SZ 32 +#define WC_SHE_M3_SZ 16 +#define WC_SHE_M4_SZ 32 +#define WC_SHE_M5_SZ 16 + +/* crypto callback sub-types for WC_ALGO_TYPE_SHE */ +enum wc_SheType { + WC_SHE_SET_UID = 1, + WC_SHE_GENERATE_M1M2M3 = 2, + WC_SHE_GENERATE_M4M5 = 3, + WC_SHE_EXPORT_KEY = 4 +}; + +/* test flags (only used for KATs) */ +#define WC_SHE_MASTER_ECU_KEY_ID 1 +#define WC_SHE_FLAG_WRITE_PROTECT 0x01 +#define WC_SHE_FLAG_BOOT_PROTECT 0x02 + +/* internal field offsets and shifts for message construction */ +#define WC_SHE_M1_KID_OFFSET 15 +#define WC_SHE_M1_KID_SHIFT 4 +#define WC_SHE_M1_AID_SHIFT 0 + +#define WC_SHE_M2_COUNT_SHIFT 4 +#define WC_SHE_M2_FLAGS_SHIFT 0 +#define WC_SHE_M2_KEY_OFFSET 16 + +#define WC_SHE_M4_KID_OFFSET 15 +#define WC_SHE_M4_KID_SHIFT 4 +#define WC_SHE_M4_AID_SHIFT 0 +#define WC_SHE_M4_COUNT_OFFSET 16 +#define WC_SHE_M4_COUNT_SHIFT 4 +#define WC_SHE_M4_COUNT_PAD 0x8 + +/* SHE KDF constants (Miyaguchi-Preneel input) */ +#define WC_SHE_KEY_UPDATE_ENC_C { \ + 0x01, 0x01, 0x53, 0x48, \ + 0x45, 0x00, 0x80, 0x00, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0xB0 \ +} + +#define WC_SHE_KEY_UPDATE_MAC_C { \ + 0x01, 0x02, 0x53, 0x48, \ + 0x45, 0x00, 0x80, 0x00, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0xB0 \ +} + +enum { + WC_SHE_MAX_ID_LEN = 32, + WC_SHE_MAX_LABEL_LEN = 32 +}; + +typedef struct wc_SHE { + byte uid[WC_SHE_UID_SZ]; + byte authKeyId; + byte targetKeyId; + byte authKey[WC_SHE_KEY_SZ]; + byte newKey[WC_SHE_KEY_SZ]; + word32 counter; + byte flags; + + byte kdfEncC[WC_SHE_KEY_SZ]; /* KDF encryption constant (CENC) */ + byte kdfMacC[WC_SHE_KEY_SZ]; /* KDF authentication constant (CMAC) */ + byte m2pHeader[WC_SHE_KEY_SZ]; /* M2P cleartext header (counter|flags|pad) */ + byte m4pHeader[WC_SHE_KEY_SZ]; /* M4P cleartext header (counter|pad) */ + byte m2pOverride; /* set by SetM2Header to skip auto-build */ + byte m4pOverride; /* set by SetM4Header to skip auto-build */ + + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + + byte generated; + byte verified; + + void* heap; + int devId; +#ifdef WOLF_CRYPTO_CB + void* devCtx; +#endif +#ifdef WOLF_PRIVATE_KEY_ID + byte id[WC_SHE_MAX_ID_LEN]; + int idLen; + char label[WC_SHE_MAX_LABEL_LEN]; + int labelLen; +#endif +} wc_SHE; + + +/* Initialize SHE context, store heap hint and device ID */ +WOLFSSL_API int wc_SHE_Init(wc_SHE* she, void* heap, int devId); + +#ifdef WOLF_PRIVATE_KEY_ID +/* Initialize with opaque hardware key identifier */ +WOLFSSL_API int wc_SHE_Init_Id(wc_SHE* she, unsigned char* id, int len, + void* heap, int devId); +/* Initialize with human-readable key label */ +WOLFSSL_API int wc_SHE_Init_Label(wc_SHE* she, const char* label, + void* heap, int devId); +#endif + +/* Scrub key material and zero the context */ +WOLFSSL_API void wc_SHE_Free(wc_SHE* she); + +/* Set UID; callback optional (WC_SHE_SET_UID) */ +WOLFSSL_API int wc_SHE_SetUID(wc_SHE* she, const byte* uid, word32 uidSz, + const void* ctx); + +/* Set authorizing key slot ID and value */ +WOLFSSL_API int wc_SHE_SetAuthKey(wc_SHE* she, byte authKeyId, + const byte* authKey, word32 keySz); + +/* Set target key slot ID and new key value */ +WOLFSSL_API int wc_SHE_SetNewKey(wc_SHE* she, byte targetKeyId, + const byte* newKey, word32 keySz); + +/* Set monotonic counter value for M2 */ +WOLFSSL_API int wc_SHE_SetCounter(wc_SHE* she, word32 counter); + +/* Set flag byte for M2 */ +WOLFSSL_API int wc_SHE_SetFlags(wc_SHE* she, byte flags); + +/* Set KDF constants (CENC/CMAC) used for key derivation. + * Defaults are set by Init. Either pointer may be NULL to skip. */ +WOLFSSL_API int wc_SHE_SetKdfConstants(wc_SHE* she, + const byte* encC, word32 encCSz, + const byte* macC, word32 macCSz); + +/* Override M2P cleartext header (first 16 bytes before KID'). + * Skips auto-build from counter/flags in GenerateM1M2M3. */ +WOLFSSL_API int wc_SHE_SetM2Header(wc_SHE* she, + const byte* header, word32 headerSz); + +/* Override M4P cleartext header (16-byte counter block). + * Skips auto-build from counter in GenerateM4M5. */ +WOLFSSL_API int wc_SHE_SetM4Header(wc_SHE* she, + const byte* header, word32 headerSz); + +/* Generate M1/M2/M3 from the current context */ +WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she); + +/* Miyaguchi-Preneel AES-128 compression (internal, exposed for testing) */ +WOLFSSL_TEST_VIS int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, + byte* out); + +/* Generate M4/M5 verification messages; callback optional (WC_SHE_GENERATE_M4M5) */ +WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she); + +/* Export M1-M5 into caller buffers; NULL to skip; callback optional (WC_SHE_EXPORT_KEY) */ +WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const void* ctx); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* WOLFSSL_SHE */ +#endif /* WOLF_CRYPT_SHE_H */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index ec1e87a00b4..f1232f796ec 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1424,7 +1424,8 @@ enum wc_AlgoType { WC_ALGO_TYPE_KDF = 9, WC_ALGO_TYPE_COPY = 10, WC_ALGO_TYPE_FREE = 11, - WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_FREE + WC_ALGO_TYPE_SHE = 12, + WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_SHE }; /* KDF types */ From cf5a5a2f5b3fd5bd63d26ab15a0586ac1634de06 Mon Sep 17 00:00:00 2001 From: night1rider Date: Wed, 18 Mar 2026 17:59:55 -0600 Subject: [PATCH 02/12] fix macro guarding in tests/api.c --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 58e4b18bd40..e7481e6c30a 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35177,7 +35177,7 @@ TEST_CASE testCases[] = { TEST_CMAC_DECLS, /* SHE */ TEST_SHE_DECLS, -#ifdef WOLF_CRYPTO_CB +#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) TEST_SHE_CB_DECLS, #endif From 5665fa438546500d558f883da7770b06b9424283 Mon Sep 17 00:00:00 2001 From: night1rider Date: Fri, 20 Mar 2026 17:34:17 -0600 Subject: [PATCH 03/12] SHE API: remove key storage from context, add direct output params --- .github/workflows/os-check.yml | 7 +- .wolfssl_known_macro_extras | 5 + CMakeLists.txt | 12 +- configure.ac | 18 +- tests/api.c | 3 + tests/api/test_she.c | 929 ++++++++++++--------------------- tests/api/test_she.h | 48 +- wolfcrypt/src/cryptocb.c | 83 ++- wolfcrypt/src/she.c | 403 +++++++------- wolfcrypt/test/test.c | 275 ++++++++-- wolfssl/wolfcrypt/cryptocb.h | 65 ++- wolfssl/wolfcrypt/she.h | 124 +++-- 12 files changed, 1039 insertions(+), 933 deletions(-) diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 7575e0ecbe2..01f775152cb 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -42,8 +42,11 @@ jobs: '--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation --enable-psk --enable-aesccm --enable-nullcipher CPPFLAGS=-DWOLFSSL_STATIC_RSA', - '--enable-she --enable-cmac', - '--enable-she --enable-cmac --enable-cryptocb --enable-cryptocbutils', + '--enable-she=standard --enable-cmac', + '--enable-she=extended --enable-cmac --enable-cryptocb --enable-cryptocbutils', + '--enable-she=standard --enable-cmac CPPFLAGS=''-DNO_WC_SHE_IMPORT_M123'' ', + '--enable-she=extended --enable-cmac --enable-cryptocb --enable-cryptocbutils + CPPFLAGS=''-DNO_WC_SHE_GETUID -DNO_WC_SHE_GETCOUNTER -DNO_WC_SHE_EXPORTKEY'' ', '--enable-all CPPFLAGS=''-DNO_AES_192 -DNO_AES_256'' ', '--enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CPPFLAGS=-DWOLFSSL_DH_EXTRA', diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index fb5da292555..1aae33177b7 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -444,6 +444,10 @@ NO_TKERNEL_MEM_POOL NO_TLSX_PSKKEM_PLAIN_ANNOUNCE NO_VERIFY_OID NO_WC_DHGENERATEPUBLIC +NO_WC_SHE_EXPORTKEY +NO_WC_SHE_GETCOUNTER +NO_WC_SHE_GETUID +NO_WC_SHE_IMPORT_M123 NO_WC_SSIZE_TYPE NO_WOLFSSL_ALLOC_ALIGN NO_WOLFSSL_AUTOSAR_CRYIF @@ -884,6 +888,7 @@ WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT WOLFSSL_SERVER_EXAMPLE WOLFSSL_SETTINGS_FILE WOLFSSL_SHE +WOLFSSL_SHE_EXTENDED WOLFSSL_SH224 WOLFSSL_SHA256_ALT_CH_MAJ WOLFSSL_SHA512_HASHTYPE diff --git a/CMakeLists.txt b/CMakeLists.txt index 53bf54436c6..a21eb8d311e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1641,11 +1641,12 @@ if(WOLFSSL_CMAC) endif() # SHE (Secure Hardware Extension) key update message generation +# standard: core SHE support, extended: adds custom KDF/header overrides add_option("WOLFSSL_SHE" - "Enable SHE key update support (default: disabled)" - "no" "yes;no") + "Enable SHE key update support (standard|extended|no)" + "no" "standard;extended;no") -if(WOLFSSL_SHE) +if(WOLFSSL_SHE STREQUAL "standard" OR WOLFSSL_SHE STREQUAL "extended") if (NOT WOLFSSL_AES) message(FATAL_ERROR "Cannot use SHE without AES.") else() @@ -1654,6 +1655,11 @@ if(WOLFSSL_SHE) endif() endif() +if(WOLFSSL_SHE STREQUAL "extended") + list(APPEND WOLFSSL_DEFINITIONS + "-DWOLFSSL_SHE_EXTENDED") +endif() + # TODO: - RC2 # - FIPS, again (there's more logic for FIPS in configure.ac) # - Selftest diff --git a/configure.ac b/configure.ac index 119cfe4ed91..17422d936bc 100644 --- a/configure.ac +++ b/configure.ac @@ -5945,14 +5945,24 @@ AS_IF([test "x$ENABLED_CMAC" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT"]) # SHE (Secure Hardware Extension) key update message generation +# --enable-she=standard: standard SHE support +# --enable-she=extended: standard + extended overrides (custom KDF/headers) AC_ARG_ENABLE([she], - [AS_HELP_STRING([--enable-she],[Enable SHE key update support (default: disabled)])], + [AS_HELP_STRING([--enable-she@<:@=standard|extended@:>@], + [Enable SHE key update support (default: disabled)])], [ ENABLED_SHE=$enableval ], [ ENABLED_SHE=no ] ) -AS_IF([test "x$ENABLED_SHE" = "xyes"], - [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE"]) +if test "x$ENABLED_SHE" = "xstandard" || test "x$ENABLED_SHE" = "xextended" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE" +fi + +if test "x$ENABLED_SHE" = "xextended" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE_EXTENDED" +fi # AES-XTS AC_ARG_ENABLE([aesxts], @@ -11552,7 +11562,7 @@ AM_CONDITIONAL([BUILD_FIPS_V6],[test $HAVE_FIPS_VERSION = 6]) AM_CONDITIONAL([BUILD_FIPS_V6_PLUS],[test $HAVE_FIPS_VERSION -ge 6]) AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) -AM_CONDITIONAL([BUILD_SHE],[test "x$ENABLED_SHE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_SHE],[test "x$ENABLED_SHE" = "xstandard" || test "x$ENABLED_SHE" = "xextended" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SELFTEST],[test "x$ENABLED_SELFTEST" = "xyes"]) AM_CONDITIONAL([BUILD_SHA224],[test "x$ENABLED_SHA224" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SHA3],[test "x$ENABLED_SHA3" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) diff --git a/tests/api.c b/tests/api.c index e7481e6c30a..a92883434c9 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35177,6 +35177,9 @@ TEST_CASE testCases[] = { TEST_CMAC_DECLS, /* SHE */ TEST_SHE_DECLS, +#ifdef WOLFSSL_SHE_EXTENDED + TEST_SHE_EXT_DECLS, +#endif #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) TEST_SHE_CB_DECLS, #endif diff --git a/tests/api/test_she.c b/tests/api/test_she.c index 25cc0ae8830..2d988266466 100644 --- a/tests/api/test_she.c +++ b/tests/api/test_she.c @@ -36,69 +36,53 @@ #include #include -/* - * Testing wc_SHE_Init() - */ +/* Common test vector data */ +#if defined(WOLFSSL_SHE) && !defined(NO_AES) +static const byte sheTestUid[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 +}; +static const byte sheTestAuthKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; +static const byte sheTestNewKey[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 +}; +static const byte sheTestExpM1[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41 +}; +static const byte sheTestExpM4[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, + 0xb4, 0x72, 0xe8, 0xd8, 0x72, 0x7d, 0x70, 0xd5, + 0x72, 0x95, 0xe7, 0x48, 0x49, 0xa2, 0x79, 0x17 +}; +static const byte sheTestExpM5[] = { + 0x82, 0x0d, 0x8d, 0x95, 0xdc, 0x11, 0xb4, 0x66, + 0x88, 0x78, 0x16, 0x0c, 0xb2, 0xa4, 0xe2, 0x3e +}; +#endif + int test_wc_SHE_Init(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) wc_SHE she; - /* Valid init with default heap/devId */ ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - - /* Verify heap and devId are stored correctly */ ExpectTrue(she.heap == NULL); ExpectIntEQ(she.devId, INVALID_DEVID); - - /* Verify state flags are zeroed */ - ExpectIntEQ(she.generated, 0); - ExpectIntEQ(she.verified, 0); - - /* Verify key material is zeroed */ - { - byte zeros[WC_SHE_KEY_SZ] = {0}; - ExpectIntEQ(XMEMCMP(she.authKey, zeros, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.newKey, zeros, WC_SHE_KEY_SZ), 0); - } - wc_SHE_Free(&she); - /* Test bad args: NULL pointer */ ExpectIntEQ(wc_SHE_Init(NULL, NULL, INVALID_DEVID), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); -#endif - return EXPECT_RESULT(); -} /* END test_wc_SHE_Init */ - -/* - * Testing wc_SHE_Free() - */ -int test_wc_SHE_Free(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) - wc_SHE she; - - /* Init, then free — should scrub key material */ - ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - wc_SHE_Free(&she); - - /* After free, context should be zeroed */ - ExpectIntEQ(she.devId, 0); - ExpectIntEQ(she.generated, 0); - ExpectIntEQ(she.verified, 0); - - /* Free with NULL should not crash */ - wc_SHE_Free(NULL); + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_Free */ +} -/* - * Testing wc_SHE_Init_Id() - */ int test_wc_SHE_Init_Id(void) { EXPECT_DECLS; @@ -106,317 +90,276 @@ int test_wc_SHE_Init_Id(void) wc_SHE she; unsigned char testId[] = {0x01, 0x02, 0x03, 0x04}; - /* Valid init with a 4-byte key ID */ ExpectIntEQ(wc_SHE_Init_Id(&she, testId, (int)sizeof(testId), NULL, INVALID_DEVID), 0); - - /* Verify the ID was copied and length is set */ ExpectIntEQ(she.idLen, (int)sizeof(testId)); - ExpectIntEQ(XMEMCMP(she.id, testId, sizeof(testId)), 0); - - /* Verify label length is cleared */ - ExpectIntEQ(she.labelLen, 0); - - /* Verify heap and devId are stored */ - ExpectTrue(she.heap == NULL); - ExpectIntEQ(she.devId, INVALID_DEVID); - wc_SHE_Free(&she); - /* Test bad args: NULL she pointer */ ExpectIntEQ(wc_SHE_Init_Id(NULL, testId, (int)sizeof(testId), NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Test bad args: ID length too large */ ExpectIntEQ(wc_SHE_Init_Id(&she, testId, WC_SHE_MAX_ID_LEN + 1, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BUFFER_E)); - - /* Test bad args: negative ID length */ ExpectIntEQ(wc_SHE_Init_Id(&she, testId, -1, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BUFFER_E)); - - /* Test zero-length ID is valid */ - ExpectIntEQ(wc_SHE_Init_Id(&she, testId, 0, NULL, INVALID_DEVID), 0); - ExpectIntEQ(she.idLen, 0); - wc_SHE_Free(&she); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_Init_Id */ +} -/* - * Testing wc_SHE_Init_Label() - */ int test_wc_SHE_Init_Label(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) && defined(WOLF_PRIVATE_KEY_ID) wc_SHE she; - const char* testLabel = "my_she_key"; - - /* Valid init with a label string */ - ExpectIntEQ(wc_SHE_Init_Label(&she, testLabel, NULL, INVALID_DEVID), 0); - - /* Verify the label was copied and length is set */ - ExpectIntEQ(she.labelLen, (int)XSTRLEN(testLabel)); - ExpectIntEQ(XMEMCMP(she.label, testLabel, XSTRLEN(testLabel)), 0); - - /* Verify ID length is cleared */ - ExpectIntEQ(she.idLen, 0); - - /* Verify heap and devId are stored */ - ExpectTrue(she.heap == NULL); - ExpectIntEQ(she.devId, INVALID_DEVID); + ExpectIntEQ(wc_SHE_Init_Label(&she, "test", NULL, INVALID_DEVID), 0); + ExpectIntEQ(she.labelLen, 4); wc_SHE_Free(&she); - /* Test bad args: NULL she pointer */ - ExpectIntEQ(wc_SHE_Init_Label(NULL, testLabel, NULL, INVALID_DEVID), + ExpectIntEQ(wc_SHE_Init_Label(NULL, "test", NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Test bad args: NULL label */ ExpectIntEQ(wc_SHE_Init_Label(&she, NULL, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Test bad args: empty label */ ExpectIntEQ(wc_SHE_Init_Label(&she, "", NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BUFFER_E)); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_Init_Label */ +} -/* - * Testing wc_SHE_SetUID() - */ -int test_wc_SHE_SetUID(void) +int test_wc_SHE_Free(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) wc_SHE she; - byte uid[WC_SHE_UID_SZ] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - - /* Valid UID */ - ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ, NULL), 0); - ExpectIntEQ(XMEMCMP(she.uid, uid, WC_SHE_UID_SZ), 0); - - /* Bad args */ - ExpectIntEQ(wc_SHE_SetUID(NULL, uid, WC_SHE_UID_SZ, NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetUID(&she, NULL, WC_SHE_UID_SZ, NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ - 1, NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ + 1, NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_SHE_Free(&she); + ExpectIntEQ(she.devId, 0); + + wc_SHE_Free(NULL); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_SetUID */ +} -/* - * Testing wc_SHE_SetAuthKey() - */ -int test_wc_SHE_SetAuthKey(void) +int test_wc_SHE_ImportM1M2M3(void) { EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) +#if defined(WOLFSSL_SHE) && !defined(NO_AES) && \ + (defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123)) wc_SHE she; - byte key[WC_SHE_KEY_SZ] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; + byte m1[WC_SHE_M1_SZ] = {0}; + byte m2[WC_SHE_M2_SZ] = {0}; + byte m3[WC_SHE_M3_SZ] = {0}; ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_ImportM1M2M3(&she, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), 0); + ExpectIntEQ(she.generated, 1); - /* Valid auth key */ - ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, - key, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(she.authKeyId, WC_SHE_MASTER_ECU_KEY_ID); - ExpectIntEQ(XMEMCMP(she.authKey, key, WC_SHE_KEY_SZ), 0); - - /* Bad args */ - ExpectIntEQ(wc_SHE_SetAuthKey(NULL, 0, key, WC_SHE_KEY_SZ), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetAuthKey(&she, 0, NULL, WC_SHE_KEY_SZ), + ExpectIntEQ(wc_SHE_ImportM1M2M3(NULL, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetAuthKey(&she, 0, key, WC_SHE_KEY_SZ - 1), + ExpectIntEQ(wc_SHE_ImportM1M2M3(&she, + m1, WC_SHE_M1_SZ - 1, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_SHE_Free(&she); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_SetAuthKey */ +} -/* - * Testing wc_SHE_SetNewKey() - */ -int test_wc_SHE_SetNewKey(void) +int test_wc_She_AesMp16(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) - wc_SHE she; - byte key[WC_SHE_KEY_SZ] = { - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + Aes aes; + byte out[WC_SHE_KEY_SZ]; + byte input[WC_SHE_KEY_SZ * 2] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x01, 0x53, 0x48, 0x45, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0 + }; + byte shortInput[17] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xAA }; - ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), out), 0); - /* Valid new key */ - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, key, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(she.targetKeyId, 4); - ExpectIntEQ(XMEMCMP(she.newKey, key, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_She_AesMp16(&aes, shortInput, sizeof(shortInput), out), 0); - /* Bad args */ - ExpectIntEQ(wc_SHE_SetNewKey(NULL, 4, key, WC_SHE_KEY_SZ), + ExpectIntEQ(wc_She_AesMp16(NULL, input, sizeof(input), out), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, NULL, WC_SHE_KEY_SZ), + ExpectIntEQ(wc_She_AesMp16(&aes, NULL, sizeof(input), out), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, key, 0), + ExpectIntEQ(wc_She_AesMp16(&aes, input, 0, out), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_SHE_Free(&she); + wc_AesFree(&aes); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_SetNewKey */ +} -/* - * Testing wc_SHE_SetCounter() - */ -int test_wc_SHE_SetCounter(void) +int test_wc_SHE_GenerateM1M2M3(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) wc_SHE she; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); - ExpectIntEQ(she.counter, 1); - - ExpectIntEQ(wc_SHE_SetCounter(&she, 0x0FFFFFFF), 0); - ExpectIntEQ(she.counter, 0x0FFFFFFF); + /* Generate and verify M1 against test vector */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), + 1, 0, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), 0); + ExpectIntEQ(XMEMCMP(m1, sheTestExpM1, WC_SHE_M1_SZ), 0); /* Bad args */ - ExpectIntEQ(wc_SHE_SetCounter(NULL, 1), + ExpectIntEQ(wc_SHE_GenerateM1M2M3(NULL, + sheTestUid, sizeof(sheTestUid), + 1, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), + 1, 0, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_SHE_Free(&she); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_SetCounter */ +} -/* - * Testing wc_SHE_SetFlags() - */ -int test_wc_SHE_SetFlags(void) +int test_wc_SHE_GenerateM4M5(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) wc_SHE she; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); - ExpectIntEQ(she.flags, 0); - - ExpectIntEQ(wc_SHE_SetFlags(&she, WC_SHE_FLAG_WRITE_PROTECT | - WC_SHE_FLAG_BOOT_PROTECT), 0); - ExpectIntEQ(she.flags, WC_SHE_FLAG_WRITE_PROTECT | - WC_SHE_FLAG_BOOT_PROTECT); + /* Generate and verify against test vector */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + sheTestNewKey, sizeof(sheTestNewKey), 1, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), 0); + ExpectIntEQ(XMEMCMP(m4, sheTestExpM4, WC_SHE_M4_SZ), 0); + ExpectIntEQ(XMEMCMP(m5, sheTestExpM5, WC_SHE_M5_SZ), 0); /* Bad args */ - ExpectIntEQ(wc_SHE_SetFlags(NULL, 0), + ExpectIntEQ(wc_SHE_GenerateM4M5(NULL, + sheTestUid, sizeof(sheTestUid), + 1, 4, sheTestNewKey, sizeof(sheTestNewKey), 1, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_SHE_Free(&she); #endif return EXPECT_RESULT(); -} /* END test_wc_SHE_SetFlags */ +} + +#if defined(WOLFSSL_SHE_EXTENDED) && defined(WOLFSSL_SHE) && !defined(NO_AES) -/* - * Testing wc_SHE_SetKdfConstants() - */ int test_wc_SHE_SetKdfConstants(void) { EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) wc_SHE she; - const byte defEncC[] = WC_SHE_KEY_UPDATE_ENC_C; - const byte defMacC[] = WC_SHE_KEY_UPDATE_MAC_C; - byte customEncC[WC_SHE_KEY_SZ]; - byte customMacC[WC_SHE_KEY_SZ]; + byte m1Def[WC_SHE_M1_SZ]; + byte m2Def[WC_SHE_M2_SZ]; + byte m3Def[WC_SHE_M3_SZ]; + byte m1Cust[WC_SHE_M1_SZ]; + byte m2Cust[WC_SHE_M2_SZ]; + byte m3Cust[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + byte customEncC[WC_SHE_KEY_SZ] = {0}; + byte customMacC[WC_SHE_KEY_SZ] = {0}; - ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + customEncC[0] = 0xFF; + customMacC[0] = 0xFE; - /* Init should set defaults */ - ExpectIntEQ(XMEMCMP(she.kdfEncC, defEncC, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.kdfMacC, defMacC, WC_SHE_KEY_SZ), 0); + /* Generate with defaults */ + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, + m1Def, WC_SHE_M1_SZ, m2Def, WC_SHE_M2_SZ, + m3Def, WC_SHE_M3_SZ), 0); + wc_SHE_Free(&she); - /* Override both */ - XMEMCPY(customEncC, defEncC, WC_SHE_KEY_SZ); - XMEMCPY(customMacC, defMacC, WC_SHE_KEY_SZ); - customEncC[1] += 0x80; - customMacC[1] += 0x80; + /* Generate with custom KDF constants */ + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SHE_SetKdfConstants(&she, customEncC, WC_SHE_KEY_SZ, customMacC, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.kdfEncC, customEncC, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.kdfMacC, customMacC, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.kdfEncOverride, 1); + ExpectIntEQ(she.kdfMacOverride, 1); - /* Override only encC, leave macC unchanged */ - ExpectIntEQ(wc_SHE_SetKdfConstants(&she, - defEncC, WC_SHE_KEY_SZ, NULL, 0), 0); - ExpectIntEQ(XMEMCMP(she.kdfEncC, defEncC, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.kdfMacC, customMacC, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, + m1Cust, WC_SHE_M1_SZ, m2Cust, WC_SHE_M2_SZ, + m3Cust, WC_SHE_M3_SZ), 0); - /* Bad args: NULL she */ + /* M1 same, M2 should differ */ + ExpectIntEQ(XMEMCMP(m1Def, m1Cust, WC_SHE_M1_SZ), 0); + ExpectIntNE(XMEMCMP(m2Def, m2Cust, WC_SHE_M2_SZ), 0); + + /* Bad args */ ExpectIntEQ(wc_SHE_SetKdfConstants(NULL, - defEncC, WC_SHE_KEY_SZ, defMacC, WC_SHE_KEY_SZ), + customEncC, WC_SHE_KEY_SZ, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Bad args: wrong size */ ExpectIntEQ(wc_SHE_SetKdfConstants(&she, - defEncC, WC_SHE_KEY_SZ - 1, NULL, 0), + customEncC, WC_SHE_KEY_SZ - 1, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_SetKdfConstants(&she, + NULL, 0, customMacC, WC_SHE_KEY_SZ - 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Test KDF override in M4M5 path */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + sheTestNewKey, sizeof(sheTestNewKey), 1, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), 0); wc_SHE_Free(&she); -#endif return EXPECT_RESULT(); -} /* END test_wc_SHE_SetKdfConstants */ +} -/* - * Testing wc_SHE_SetM2Header() and wc_SHE_SetM4Header() - */ int test_wc_SHE_SetM2M4Header(void) { EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) - wc_SHE she, sheOvr; - byte uid[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - byte authKey[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - byte newKey[] = { - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 - }; + wc_SHE she; byte customHeader[WC_SHE_KEY_SZ] = {0}; - byte m1Def[WC_SHE_M1_SZ], m2Def[WC_SHE_M2_SZ], m3Def[WC_SHE_M3_SZ]; - byte m1Ovr[WC_SHE_M1_SZ], m2Ovr[WC_SHE_M2_SZ], m3Ovr[WC_SHE_M3_SZ]; + byte m1Def[WC_SHE_M1_SZ]; + byte m2Def[WC_SHE_M2_SZ]; + byte m3Def[WC_SHE_M3_SZ]; + byte m1Ovr[WC_SHE_M1_SZ]; + byte m2Ovr[WC_SHE_M2_SZ]; + byte m3Ovr[WC_SHE_M3_SZ]; + byte m4Def[WC_SHE_M4_SZ]; + byte m5Def[WC_SHE_M5_SZ]; + byte m4Ovr[WC_SHE_M4_SZ]; + byte m5Ovr[WC_SHE_M5_SZ]; - /* --- SetM2Header bad args --- */ + /* Bad args */ ExpectIntEQ(wc_SHE_SetM2Header(NULL, customHeader, WC_SHE_KEY_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SHE_SetM4Header(NULL, customHeader, WC_SHE_KEY_SZ), @@ -424,314 +367,73 @@ int test_wc_SHE_SetM2M4Header(void) ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - /* NULL header */ ExpectIntEQ(wc_SHE_SetM2Header(&she, NULL, WC_SHE_KEY_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Wrong size */ ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ + 1), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Valid set */ - XMEMSET(customHeader, 0xAA, WC_SHE_KEY_SZ); - ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.m2pHeader, customHeader, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(she.m2pOverride, 1); - - ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(XMEMCMP(she.m4pHeader, customHeader, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(she.m4pOverride, 1); + /* Generate M1M2M3 with defaults */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, + m1Def, WC_SHE_M1_SZ, m2Def, WC_SHE_M2_SZ, + m3Def, WC_SHE_M3_SZ), 0); wc_SHE_Free(&she); - /* --- Override produces different M2 than default --- */ - /* Default path: counter=1, flags=0, auto-built headers */ + /* Generate with overridden M2 header */ ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); - ExpectIntEQ(wc_SHE_SetAuthKey(&she, 1, authKey, sizeof(authKey)), 0); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); - ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); - ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); - ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); - ExpectIntEQ(wc_SHE_ExportKey(&she, - m1Def, WC_SHE_M1_SZ, m2Def, WC_SHE_M2_SZ, - m3Def, WC_SHE_M3_SZ, NULL, 0, NULL, 0, NULL), 0); - wc_SHE_Free(&she); + customHeader[0] = 0xFF; + ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.m2pOverride, 1); - /* Override path: same inputs but custom m2pHeader */ - ExpectIntEQ(wc_SHE_Init(&sheOvr, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_SHE_SetUID(&sheOvr, uid, sizeof(uid), NULL), 0); - ExpectIntEQ(wc_SHE_SetAuthKey(&sheOvr, 1, authKey, sizeof(authKey)), 0); - ExpectIntEQ(wc_SHE_SetNewKey(&sheOvr, 4, newKey, sizeof(newKey)), 0); - ExpectIntEQ(wc_SHE_SetCounter(&sheOvr, 1), 0); - ExpectIntEQ(wc_SHE_SetFlags(&sheOvr, 0), 0); - /* Set a different header ΓÇö should produce different M2/M3 */ - XMEMSET(customHeader, 0, WC_SHE_KEY_SZ); - customHeader[0] = 0xFF; /* different from auto-built */ - ExpectIntEQ(wc_SHE_SetM2Header(&sheOvr, customHeader, WC_SHE_KEY_SZ), 0); - ExpectIntEQ(wc_SHE_GenerateM1M2M3(&sheOvr), 0); - ExpectIntEQ(wc_SHE_ExportKey(&sheOvr, + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, m1Ovr, WC_SHE_M1_SZ, m2Ovr, WC_SHE_M2_SZ, - m3Ovr, WC_SHE_M3_SZ, NULL, 0, NULL, 0, NULL), 0); + m3Ovr, WC_SHE_M3_SZ), 0); - /* M1 should be same (UID|IDs unchanged), M2 should differ */ ExpectIntEQ(XMEMCMP(m1Def, m1Ovr, WC_SHE_M1_SZ), 0); ExpectIntNE(XMEMCMP(m2Def, m2Ovr, WC_SHE_M2_SZ), 0); - - wc_SHE_Free(&sheOvr); -#endif - return EXPECT_RESULT(); -} /* END test_wc_SHE_SetM2M4Header */ - -/* - * Testing wc_SHE_GenerateM1M2M3() - */ -int test_wc_SHE_GenerateM1M2M3(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) - wc_SHE she; - byte uid[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - byte authKey[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - byte newKey[] = { - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 - }; - - ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); - ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, - authKey, sizeof(authKey)), 0); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); - ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); - ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); - - /* Generate should succeed and set generated flag */ - ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); - ExpectIntEQ(she.generated, 1); - - /* Bad args */ - ExpectIntEQ(wc_SHE_GenerateM1M2M3(NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_SHE_Free(&she); -#endif - return EXPECT_RESULT(); -} /* END test_wc_SHE_GenerateM1M2M3 */ - -/* - * Testing wc_She_AesMp16() — Miyaguchi-Preneel compression - */ -int test_wc_She_AesMp16(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) - Aes aes; - byte out[WC_SHE_KEY_SZ]; - byte input[WC_SHE_KEY_SZ * 2] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x01, 0x01, 0x53, 0x48, 0x45, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0 - }; - /* 17 bytes — not block-aligned, triggers zero-padding path */ - byte shortInput[17] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0xAA - }; - - ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); - - /* Valid block-aligned input */ - ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), out), 0); - - /* Non-block-aligned input — exercises zero-padding */ - ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_She_AesMp16(&aes, shortInput, sizeof(shortInput), out), 0); - - /* Bad args: NULL aes */ - ExpectIntEQ(wc_She_AesMp16(NULL, input, sizeof(input), out), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Bad args: NULL input */ - ExpectIntEQ(wc_She_AesMp16(&aes, NULL, sizeof(input), out), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Bad args: zero size */ - ExpectIntEQ(wc_She_AesMp16(&aes, input, 0, out), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Bad args: NULL output */ - ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - wc_AesFree(&aes); -#endif - return EXPECT_RESULT(); -} /* END test_wc_She_AesMp16 */ - -/* - * Testing wc_SHE_ExportKey() - */ -int test_wc_SHE_ExportKey(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) - wc_SHE she; - byte m1[WC_SHE_M1_SZ]; - byte m2[WC_SHE_M2_SZ]; - byte m3[WC_SHE_M3_SZ]; - byte m4[WC_SHE_M4_SZ]; - byte m5[WC_SHE_M5_SZ]; - byte uid[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - byte authKey[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - byte newKey[] = { - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 - }; + /* Test M4 header override */ ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); - - /* Export before generate should return BAD_STATE_E */ - ExpectIntEQ(wc_SHE_ExportKey(&she, - m1, WC_SHE_M1_SZ, NULL, 0, NULL, 0, - NULL, 0, NULL, 0, NULL), - WC_NO_ERR_TRACE(BAD_STATE_E)); - - /* NULL she should return BAD_FUNC_ARG */ - ExpectIntEQ(wc_SHE_ExportKey(NULL, - m1, WC_SHE_M1_SZ, NULL, 0, NULL, 0, - NULL, 0, NULL, 0, NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - /* Set up, generate, and compute verification */ - ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); - ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, - authKey, sizeof(authKey)), 0); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); - ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); - ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); - ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); - ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0); - - /* Export only M1/M2/M3 */ - ExpectIntEQ(wc_SHE_ExportKey(&she, - m1, WC_SHE_M1_SZ, - m2, WC_SHE_M2_SZ, - m3, WC_SHE_M3_SZ, - NULL, 0, NULL, 0, NULL), 0); - - /* Export only M4/M5 */ - ExpectIntEQ(wc_SHE_ExportKey(&she, - NULL, 0, NULL, 0, NULL, 0, - m4, WC_SHE_M4_SZ, - m5, WC_SHE_M5_SZ, NULL), 0); - - /* Export all M1-M5 */ - ExpectIntEQ(wc_SHE_ExportKey(&she, - m1, WC_SHE_M1_SZ, - m2, WC_SHE_M2_SZ, - m3, WC_SHE_M3_SZ, - m4, WC_SHE_M4_SZ, - m5, WC_SHE_M5_SZ, NULL), 0); - - /* Buffer too small */ - ExpectIntEQ(wc_SHE_ExportKey(&she, - m1, 1, NULL, 0, NULL, 0, - NULL, 0, NULL, 0, NULL), - WC_NO_ERR_TRACE(BUFFER_E)); - - /* Export M4/M5 when generated but not verified — BAD_STATE_E */ - { - wc_SHE badShe; - ExpectIntEQ(wc_SHE_Init(&badShe, NULL, INVALID_DEVID), 0); - badShe.generated = 1; /* fake generated state */ - badShe.verified = 0; /* but not verified */ - ExpectIntEQ(wc_SHE_ExportKey(&badShe, - NULL, 0, NULL, 0, NULL, 0, - m4, WC_SHE_M4_SZ, - NULL, 0, NULL), - WC_NO_ERR_TRACE(BAD_STATE_E)); - wc_SHE_Free(&badShe); - } - + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + sheTestNewKey, sizeof(sheTestNewKey), 1, + m4Def, WC_SHE_M4_SZ, m5Def, WC_SHE_M5_SZ), 0); wc_SHE_Free(&she); -#endif - return EXPECT_RESULT(); -} /* END test_wc_SHE_ExportKey */ - -/* - * Testing wc_SHE_GenerateM4M5() - */ -int test_wc_SHE_GenerateM4M5(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) - wc_SHE she; - byte uid[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - byte authKey[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - byte newKey[] = { - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 - }; ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + XMEMSET(customHeader, 0xBB, WC_SHE_KEY_SZ); + ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ), 0); + ExpectIntEQ(she.m4pOverride, 1); - /* GenerateM4M5 before GenerateM1M2M3 should return BAD_STATE_E */ - ExpectIntEQ(wc_SHE_GenerateM4M5(&she), - WC_NO_ERR_TRACE(BAD_STATE_E)); - - /* Set up and generate M1/M2/M3 */ - ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); - ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, - authKey, sizeof(authKey)), 0); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); - ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); - ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); - ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); - - /* Now compute M4/M5 */ - ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0); - ExpectIntEQ(she.verified, 1); - - /* Bad args */ - ExpectIntEQ(wc_SHE_GenerateM4M5(NULL), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + sheTestNewKey, sizeof(sheTestNewKey), 1, + m4Ovr, WC_SHE_M4_SZ, m5Ovr, WC_SHE_M5_SZ), 0); + ExpectIntNE(XMEMCMP(m4Def, m4Ovr, WC_SHE_M4_SZ), 0); wc_SHE_Free(&she); -#endif + return EXPECT_RESULT(); -} /* END test_wc_SHE_GenerateM4M5 */ +} + +#endif /* WOLFSSL_SHE_EXTENDED && WOLFSSL_SHE && !NO_AES */ #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) && !defined(NO_AES) -/* Simple SHE callback that falls back to software by resetting devId */ +/* SHE callback — re-calls with software devId */ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) { - int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); wc_SHE* she; int savedDevId; + int ret; (void)ctx; (void)devIdArg; @@ -741,7 +443,6 @@ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) } #ifdef WOLF_CRYPTO_CB_FREE - /* Handle free callback */ if (info->algo_type == WC_ALGO_TYPE_FREE) { if (info->free.algo == WC_ALGO_TYPE_SHE) { she = (wc_SHE*)info->free.obj; @@ -767,26 +468,68 @@ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) switch (info->she.type) { case WC_SHE_SET_UID: - ret = wc_SHE_SetUID(she, info->she.op.setUid.uid, - info->she.op.setUid.uidSz, - info->she.ctx); + ret = 0; + break; + case WC_SHE_GET_COUNTER: + { + static word32 simCounter = 0; + if (info->she.op.getCounter.counter != NULL) { + *info->she.op.getCounter.counter = ++simCounter; + } + ret = 0; + break; + } + case WC_SHE_GENERATE_M1M2M3: + ret = wc_SHE_GenerateM1M2M3(she, + info->she.op.generateM1M2M3.uid, + info->she.op.generateM1M2M3.uidSz, + info->she.op.generateM1M2M3.authKeyId, + info->she.op.generateM1M2M3.authKey, + info->she.op.generateM1M2M3.authKeySz, + info->she.op.generateM1M2M3.targetKeyId, + info->she.op.generateM1M2M3.newKey, + info->she.op.generateM1M2M3.newKeySz, + info->she.op.generateM1M2M3.counter, + info->she.op.generateM1M2M3.flags, + info->she.op.generateM1M2M3.m1, + info->she.op.generateM1M2M3.m1Sz, + info->she.op.generateM1M2M3.m2, + info->she.op.generateM1M2M3.m2Sz, + info->she.op.generateM1M2M3.m3, + info->she.op.generateM1M2M3.m3Sz); break; case WC_SHE_GENERATE_M4M5: - ret = wc_SHE_GenerateM4M5(she); + ret = wc_SHE_GenerateM4M5(she, + info->she.op.generateM4M5.uid, + info->she.op.generateM4M5.uidSz, + info->she.op.generateM4M5.authKeyId, + info->she.op.generateM4M5.targetKeyId, + info->she.op.generateM4M5.newKey, + info->she.op.generateM4M5.newKeySz, + info->she.op.generateM4M5.counter, + info->she.op.generateM4M5.m4, + info->she.op.generateM4M5.m4Sz, + info->she.op.generateM4M5.m5, + info->she.op.generateM4M5.m5Sz); break; case WC_SHE_EXPORT_KEY: - ret = wc_SHE_ExportKey(she, - info->she.op.exportKey.m1, - info->she.op.exportKey.m1Sz, - info->she.op.exportKey.m2, - info->she.op.exportKey.m2Sz, - info->she.op.exportKey.m3, - info->she.op.exportKey.m3Sz, - info->she.op.exportKey.m4, - info->she.op.exportKey.m4Sz, - info->she.op.exportKey.m5, - info->she.op.exportKey.m5Sz, - info->she.ctx); + /* Simulate hardware export — fill with test pattern */ + if (info->she.op.exportKey.m1 != NULL) { + XMEMSET(info->she.op.exportKey.m1, 0x11, WC_SHE_M1_SZ); + } + if (info->she.op.exportKey.m2 != NULL) { + XMEMSET(info->she.op.exportKey.m2, 0x22, WC_SHE_M2_SZ); + } + if (info->she.op.exportKey.m3 != NULL) { + XMEMSET(info->she.op.exportKey.m3, 0x33, WC_SHE_M3_SZ); + } + if (info->she.op.exportKey.m4 != NULL) { + XMEMSET(info->she.op.exportKey.m4, 0x44, WC_SHE_M4_SZ); + } + if (info->she.op.exportKey.m5 != NULL) { + XMEMSET(info->she.op.exportKey.m5, 0x55, WC_SHE_M5_SZ); + } + ret = 0; break; default: ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); @@ -797,79 +540,99 @@ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) return ret; } -/* - * Testing SHE callback path for SetUID and GenerateM4M5 - */ int test_wc_SHE_CryptoCb(void) { EXPECT_DECLS; -#if defined(WOLFSSL_SHE) && !defined(NO_AES) wc_SHE she; int sheTestDevId = 54321; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; byte m4[WC_SHE_M4_SZ]; byte m5[WC_SHE_M5_SZ]; - byte uid[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - byte authKey[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - byte newKey[] = { - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 - }; - /* Register our test callback with a non-INVALID devId */ ExpectIntEQ(wc_CryptoCb_RegisterDevice(sheTestDevId, test_she_crypto_cb, NULL), 0); - - /* Init with the test devId so callback path is used */ ExpectIntEQ(wc_SHE_Init(&she, NULL, sheTestDevId), 0); - /* SetUID via callback — passes uid through to software */ - ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0); - ExpectIntEQ(XMEMCMP(she.uid, uid, WC_SHE_UID_SZ), 0); - - /* Set remaining inputs (software only) */ - ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID, - authKey, sizeof(authKey)), 0); - ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0); - ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0); - ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0); - - /* GenerateLoadKey — software, callback not involved */ - ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0); + /* Generate M1/M2/M3 via callback */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), 0); + ExpectIntEQ(XMEMCMP(m1, sheTestExpM1, WC_SHE_M1_SZ), 0); + + /* Generate M4/M5 via callback */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + sheTestNewKey, sizeof(sheTestNewKey), 1, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), 0); + ExpectIntEQ(XMEMCMP(m4, sheTestExpM4, WC_SHE_M4_SZ), 0); + ExpectIntEQ(XMEMCMP(m5, sheTestExpM5, WC_SHE_M5_SZ), 0); + + /* ExportKey via callback — simulated hardware */ +#if !defined(NO_WC_SHE_EXPORTKEY) + { + byte em1[WC_SHE_M1_SZ]; + byte em2[WC_SHE_M2_SZ]; + byte em3[WC_SHE_M3_SZ]; + byte em4[WC_SHE_M4_SZ]; + byte em5[WC_SHE_M5_SZ]; + byte pat[WC_SHE_M1_SZ]; - /* GenerateM4M5 via callback — falls back to software */ - ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0); - ExpectIntEQ(she.verified, 1); + ExpectIntEQ(wc_SHE_ExportKey(&she, + em1, WC_SHE_M1_SZ, em2, WC_SHE_M2_SZ, + em3, WC_SHE_M3_SZ, em4, WC_SHE_M4_SZ, + em5, WC_SHE_M5_SZ, NULL), 0); + + /* Verify callback filled with test pattern */ + XMEMSET(pat, 0x11, WC_SHE_M1_SZ); + ExpectIntEQ(XMEMCMP(em1, pat, WC_SHE_M1_SZ), 0); + + /* Bad args */ + ExpectIntEQ(wc_SHE_ExportKey(NULL, + em1, WC_SHE_M1_SZ, em2, WC_SHE_M2_SZ, + em3, WC_SHE_M3_SZ, em4, WC_SHE_M4_SZ, + em5, WC_SHE_M5_SZ, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + } +#endif - /* ExportKey via callback path */ - ExpectIntEQ(wc_SHE_ExportKey(&she, - NULL, 0, NULL, 0, NULL, 0, - m4, WC_SHE_M4_SZ, - m5, WC_SHE_M5_SZ, NULL), 0); +#if !defined(NO_WC_SHE_GETUID) + { + byte cbUid[WC_SHE_UID_SZ]; + ExpectIntEQ(wc_SHE_GetUID(&she, cbUid, WC_SHE_UID_SZ, NULL), 0); + ExpectIntEQ(wc_SHE_GetUID(NULL, cbUid, WC_SHE_UID_SZ, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GetUID(&she, NULL, WC_SHE_UID_SZ, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + } +#endif - /* Export all M1-M5 via callback */ +#if !defined(NO_WC_SHE_GETCOUNTER) { - byte cm1[WC_SHE_M1_SZ]; - byte cm2[WC_SHE_M2_SZ]; - byte cm3[WC_SHE_M3_SZ]; - ExpectIntEQ(wc_SHE_ExportKey(&she, - cm1, WC_SHE_M1_SZ, - cm2, WC_SHE_M2_SZ, - cm3, WC_SHE_M3_SZ, - m4, WC_SHE_M4_SZ, - m5, WC_SHE_M5_SZ, NULL), 0); + word32 cnt1 = 0; + word32 cnt2 = 0; + + /* Callback should return incrementing counter */ + ExpectIntEQ(wc_SHE_GetCounter(&she, &cnt1, NULL), 0); + ExpectIntEQ(wc_SHE_GetCounter(&she, &cnt2, NULL), 0); + ExpectTrue(cnt2 > cnt1); + + /* Bad args */ + ExpectIntEQ(wc_SHE_GetCounter(NULL, &cnt1, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GetCounter(&she, NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); } +#endif wc_SHE_Free(&she); wc_CryptoCb_UnRegisterDevice(sheTestDevId); -#endif + return EXPECT_RESULT(); -} /* END test_wc_SHE_CryptoCb */ +} #endif /* WOLF_CRYPTO_CB && WOLFSSL_SHE && !NO_AES */ - diff --git a/tests/api/test_she.h b/tests/api/test_she.h index 61334aaaa33..79395d6e681 100644 --- a/tests/api/test_she.h +++ b/tests/api/test_she.h @@ -28,37 +28,35 @@ int test_wc_SHE_Init(void); int test_wc_SHE_Init_Id(void); int test_wc_SHE_Init_Label(void); int test_wc_SHE_Free(void); -int test_wc_SHE_SetUID(void); -int test_wc_SHE_SetAuthKey(void); -int test_wc_SHE_SetNewKey(void); -int test_wc_SHE_SetCounter(void); -int test_wc_SHE_SetFlags(void); -int test_wc_SHE_SetKdfConstants(void); -int test_wc_SHE_SetM2M4Header(void); -int test_wc_SHE_GenerateM1M2M3(void); +int test_wc_SHE_ImportM1M2M3(void); int test_wc_She_AesMp16(void); +int test_wc_SHE_GenerateM1M2M3(void); int test_wc_SHE_GenerateM4M5(void); -int test_wc_SHE_ExportKey(void); +#ifdef WOLFSSL_SHE_EXTENDED +int test_wc_SHE_SetKdfConstants(void); +int test_wc_SHE_SetM2M4Header(void); +#endif #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) int test_wc_SHE_CryptoCb(void); #endif -#define TEST_SHE_DECLS \ - TEST_DECL_GROUP("she", test_wc_SHE_Init), \ - TEST_DECL_GROUP("she", test_wc_SHE_Init_Id), \ - TEST_DECL_GROUP("she", test_wc_SHE_Init_Label), \ - TEST_DECL_GROUP("she", test_wc_SHE_Free), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetUID), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetAuthKey), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetNewKey), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetCounter), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetFlags), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetKdfConstants), \ - TEST_DECL_GROUP("she", test_wc_SHE_SetM2M4Header), \ - TEST_DECL_GROUP("she", test_wc_SHE_GenerateM1M2M3), \ - TEST_DECL_GROUP("she", test_wc_She_AesMp16), \ - TEST_DECL_GROUP("she", test_wc_SHE_GenerateM4M5), \ - TEST_DECL_GROUP("she", test_wc_SHE_ExportKey) +#define TEST_SHE_DECLS \ + TEST_DECL_GROUP("she", test_wc_SHE_Init), \ + TEST_DECL_GROUP("she", test_wc_SHE_Init_Id), \ + TEST_DECL_GROUP("she", test_wc_SHE_Init_Label), \ + TEST_DECL_GROUP("she", test_wc_SHE_Free), \ + TEST_DECL_GROUP("she", test_wc_SHE_ImportM1M2M3), \ + TEST_DECL_GROUP("she", test_wc_She_AesMp16), \ + TEST_DECL_GROUP("she", test_wc_SHE_GenerateM1M2M3), \ + TEST_DECL_GROUP("she", test_wc_SHE_GenerateM4M5) + +#ifdef WOLFSSL_SHE_EXTENDED +#define TEST_SHE_EXT_DECLS \ + TEST_DECL_GROUP("she", test_wc_SHE_SetKdfConstants), \ + TEST_DECL_GROUP("she", test_wc_SHE_SetM2M4Header) +#else +#define TEST_SHE_EXT_DECLS +#endif #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) #define TEST_SHE_CB_DECLS \ diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index af389213f11..3dfa947ab15 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -2064,7 +2064,39 @@ int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, word32 uidSz, return wc_CryptoCb_TranslateErrorCode(ret); } -int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, const void* ctx) +int wc_CryptoCb_SheGetCounter(wc_SHE* she, word32* counter, const void* ctx) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (she == NULL || counter == NULL) { + return BAD_FUNC_ARG; + } + + dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_GET_COUNTER; + cryptoInfo.she.ctx = ctx; + cryptoInfo.she.op.getCounter.counter = counter; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, + const byte* uid, word32 uidSz, + byte authKeyId, const byte* authKey, word32 authKeySz, + byte targetKeyId, const byte* newKey, word32 newKeySz, + word32 counter, byte flags, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz) { int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); CryptoCb* dev; @@ -2077,10 +2109,25 @@ int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, const void* ctx) if (dev && dev->cb) { wc_CryptoInfo cryptoInfo; XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); - cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; - cryptoInfo.she.she = she; - cryptoInfo.she.type = WC_SHE_GENERATE_M1M2M3; - cryptoInfo.she.ctx = ctx; + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_GENERATE_M1M2M3; + cryptoInfo.she.op.generateM1M2M3.uid = uid; + cryptoInfo.she.op.generateM1M2M3.uidSz = uidSz; + cryptoInfo.she.op.generateM1M2M3.authKeyId = authKeyId; + cryptoInfo.she.op.generateM1M2M3.authKey = authKey; + cryptoInfo.she.op.generateM1M2M3.authKeySz = authKeySz; + cryptoInfo.she.op.generateM1M2M3.targetKeyId = targetKeyId; + cryptoInfo.she.op.generateM1M2M3.newKey = newKey; + cryptoInfo.she.op.generateM1M2M3.newKeySz = newKeySz; + cryptoInfo.she.op.generateM1M2M3.counter = counter; + cryptoInfo.she.op.generateM1M2M3.flags = flags; + cryptoInfo.she.op.generateM1M2M3.m1 = m1; + cryptoInfo.she.op.generateM1M2M3.m1Sz = m1Sz; + cryptoInfo.she.op.generateM1M2M3.m2 = m2; + cryptoInfo.she.op.generateM1M2M3.m2Sz = m2Sz; + cryptoInfo.she.op.generateM1M2M3.m3 = m3; + cryptoInfo.she.op.generateM1M2M3.m3Sz = m3Sz; ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); } @@ -2088,7 +2135,13 @@ int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, const void* ctx) return wc_CryptoCb_TranslateErrorCode(ret); } -int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, const void* ctx) +int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, + const byte* uid, word32 uidSz, + byte authKeyId, byte targetKeyId, + const byte* newKey, word32 newKeySz, + word32 counter, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz) { int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); CryptoCb* dev; @@ -2101,10 +2154,20 @@ int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, const void* ctx) if (dev && dev->cb) { wc_CryptoInfo cryptoInfo; XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); - cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; - cryptoInfo.she.she = she; - cryptoInfo.she.type = WC_SHE_GENERATE_M4M5; - cryptoInfo.she.ctx = ctx; + cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; + cryptoInfo.she.she = she; + cryptoInfo.she.type = WC_SHE_GENERATE_M4M5; + cryptoInfo.she.op.generateM4M5.uid = uid; + cryptoInfo.she.op.generateM4M5.uidSz = uidSz; + cryptoInfo.she.op.generateM4M5.authKeyId = authKeyId; + cryptoInfo.she.op.generateM4M5.targetKeyId = targetKeyId; + cryptoInfo.she.op.generateM4M5.newKey = newKey; + cryptoInfo.she.op.generateM4M5.newKeySz = newKeySz; + cryptoInfo.she.op.generateM4M5.counter = counter; + cryptoInfo.she.op.generateM4M5.m4 = m4; + cryptoInfo.she.op.generateM4M5.m4Sz = m4Sz; + cryptoInfo.she.op.generateM4M5.m5 = m5; + cryptoInfo.she.op.generateM4M5.m5Sz = m5Sz; ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); } diff --git a/wolfcrypt/src/she.c b/wolfcrypt/src/she.c index 06c4f1b44aa..2539efa7f49 100644 --- a/wolfcrypt/src/she.c +++ b/wolfcrypt/src/she.c @@ -116,19 +116,14 @@ int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out) /* -------------------------------------------------------------------------- */ int wc_SHE_Init(wc_SHE* she, void* heap, int devId) { - const byte encC[] = WC_SHE_KEY_UPDATE_ENC_C; - const byte macC[] = WC_SHE_KEY_UPDATE_MAC_C; - if (she == NULL) { return BAD_FUNC_ARG; } - XMEMSET(she, 0, sizeof(wc_SHE)); + ForceZero(she, sizeof(wc_SHE)); she->heap = heap; she->devId = devId; - XMEMCPY(she->kdfEncC, encC, WC_SHE_KEY_SZ); - XMEMCPY(she->kdfMacC, macC, WC_SHE_KEY_SZ); - /* m2pHeader/m4pHeader are zero from XMEMSET ΓÇö correct for counter=0 */ + /* kdfEncOverride/kdfMacOverride are zero from XMEMSET — defaults used */ return 0; } @@ -227,85 +222,45 @@ void wc_SHE_Free(wc_SHE* she) } /* -------------------------------------------------------------------------- */ -/* Setter functions */ +/* GetUID — callback required */ +/* */ +/* Dispatches to callback to fetch UID from hardware. */ +/* Buffer size validation is the callback's responsibility. */ +/* Returns CRYPTOCB_UNAVAILABLE if no callback. */ /* -------------------------------------------------------------------------- */ - -int wc_SHE_SetUID(wc_SHE* she, const byte* uid, word32 uidSz, +#if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETUID) +int wc_SHE_GetUID(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx) { -#ifdef WOLF_CRYPTO_CB - int ret; -#endif - - if (she == NULL) { + if (she == NULL || uid == NULL) { return BAD_FUNC_ARG; } -#ifdef WOLF_CRYPTO_CB - /* Try callback first if a device is registered */ - if (she->devId != INVALID_DEVID) { - ret = wc_CryptoCb_SheSetUid(she, uid, uidSz, ctx); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - return ret; - } - /* fall-through to software path */ - } -#else - (void)ctx; -#endif - - /* Software path: copy caller-provided UID */ - if (uid == NULL || uidSz != WC_SHE_UID_SZ) { - return BAD_FUNC_ARG; - } - - XMEMCPY(she->uid, uid, WC_SHE_UID_SZ); - return 0; -} - -int wc_SHE_SetAuthKey(wc_SHE* she, byte authKeyId, - const byte* authKey, word32 keySz) -{ - if (she == NULL || authKey == NULL || keySz != WC_SHE_KEY_SZ) { - return BAD_FUNC_ARG; - } - - she->authKeyId = authKeyId; - XMEMCPY(she->authKey, authKey, WC_SHE_KEY_SZ); - return 0; + return wc_CryptoCb_SheSetUid(she, uid, uidSz, ctx); } +#endif /* WOLF_CRYPTO_CB && !NO_WC_SHE_GETUID */ -int wc_SHE_SetNewKey(wc_SHE* she, byte targetKeyId, - const byte* newKey, word32 keySz) -{ - if (she == NULL || newKey == NULL || keySz != WC_SHE_KEY_SZ) { - return BAD_FUNC_ARG; - } - - she->targetKeyId = targetKeyId; - XMEMCPY(she->newKey, newKey, WC_SHE_KEY_SZ); - return 0; -} - -int wc_SHE_SetCounter(wc_SHE* she, word32 counter) +/* -------------------------------------------------------------------------- */ +/* GetCounter — callback required */ +/* */ +/* Dispatches to callback to read current counter from hardware. */ +/* Returns CRYPTOCB_UNAVAILABLE if no callback. */ +/* -------------------------------------------------------------------------- */ +#if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETCOUNTER) +int wc_SHE_GetCounter(wc_SHE* she, word32* counter, const void* ctx) { - if (she == NULL) { + if (she == NULL || counter == NULL) { return BAD_FUNC_ARG; } - she->counter = counter; - return 0; + return wc_CryptoCb_SheGetCounter(she, counter, ctx); } +#endif /* WOLF_CRYPTO_CB && !NO_WC_SHE_GETCOUNTER */ -int wc_SHE_SetFlags(wc_SHE* she, byte flags) -{ - if (she == NULL) { - return BAD_FUNC_ARG; - } - - she->flags = flags; - return 0; -} +/* -------------------------------------------------------------------------- */ +/* Extended SHE overrides */ +/* -------------------------------------------------------------------------- */ +#ifdef WOLFSSL_SHE_EXTENDED int wc_SHE_SetKdfConstants(wc_SHE* she, const byte* encC, word32 encCSz, @@ -320,6 +275,7 @@ int wc_SHE_SetKdfConstants(wc_SHE* she, return BAD_FUNC_ARG; } XMEMCPY(she->kdfEncC, encC, WC_SHE_KEY_SZ); + she->kdfEncOverride = 1; } if (macC != NULL) { @@ -327,11 +283,44 @@ int wc_SHE_SetKdfConstants(wc_SHE* she, return BAD_FUNC_ARG; } XMEMCPY(she->kdfMacC, macC, WC_SHE_KEY_SZ); + she->kdfMacOverride = 1; } return 0; } +#endif /* WOLFSSL_SHE_EXTENDED */ + +/* -------------------------------------------------------------------------- */ +/* GetUID */ + +#if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) +/* -------------------------------------------------------------------------- */ +/* Import M1/M2/M3 */ +/* */ +/* Copy externally-provided M1/M2/M3 into context and set generated flag. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_ImportM1M2M3(wc_SHE* she, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz) +{ + if (she == NULL || m1 == NULL || m2 == NULL || m3 == NULL) { + return BAD_FUNC_ARG; + } + if (m1Sz != WC_SHE_M1_SZ || m2Sz != WC_SHE_M2_SZ || + m3Sz != WC_SHE_M3_SZ) { + return BAD_FUNC_ARG; + } + + XMEMCPY(she->m1, m1, WC_SHE_M1_SZ); + XMEMCPY(she->m2, m2, WC_SHE_M2_SZ); + XMEMCPY(she->m3, m3, WC_SHE_M3_SZ); + she->generated = 1; + return 0; +} +#endif /* WOLF_CRYPTO_CB || !NO_WC_SHE_IMPORT_M123 */ + /* -------------------------------------------------------------------------- */ /* Portable big-endian 32-bit store */ /* -------------------------------------------------------------------------- */ @@ -343,28 +332,45 @@ static WC_INLINE void she_store_be32(byte* dst, word32 val) dst[3] = (byte)(val); } -/* Build M2P/M4P headers from counter and flags using standard SHE packing. +/* Build M2P and M4P headers from counter and flags using standard SHE packing. * M2P header: counter(28b) | flags(4b) | zeros(96b) = 16 bytes * M4P header: counter(28b) | 1(1b) | zeros(99b) = 16 bytes - * Called internally by GenerateM1M2M3/GenerateM4M5 unless overridden. */ -static void she_build_headers(wc_SHE* she) + * Writes to caller-provided buffers. Skipped if WOLFSSL_SHE_EXTENDED + * override is active on the context. */ +static void she_build_headers(wc_SHE* she, word32 counter, byte flags, + byte* m2pHeader, byte* m4pHeader) { word32 field; - if (!she->m2pOverride) { - XMEMSET(she->m2pHeader, 0, WC_SHE_KEY_SZ); - field = (she->counter << WC_SHE_M2_COUNT_SHIFT) | - (she->flags << WC_SHE_M2_FLAGS_SHIFT); - she_store_be32(she->m2pHeader, field); +#ifdef WOLFSSL_SHE_EXTENDED + if (she->m2pOverride) { + XMEMCPY(m2pHeader, she->m2pHeader, WC_SHE_KEY_SZ); + } + else +#endif + { + XMEMSET(m2pHeader, 0, WC_SHE_KEY_SZ); + field = (counter << WC_SHE_M2_COUNT_SHIFT) | + (flags << WC_SHE_M2_FLAGS_SHIFT); + she_store_be32(m2pHeader, field); } - if (!she->m4pOverride) { - XMEMSET(she->m4pHeader, 0, WC_SHE_KEY_SZ); - field = (she->counter << WC_SHE_M4_COUNT_SHIFT) | WC_SHE_M4_COUNT_PAD; - she_store_be32(she->m4pHeader, field); +#ifdef WOLFSSL_SHE_EXTENDED + if (she->m4pOverride) { + XMEMCPY(m4pHeader, she->m4pHeader, WC_SHE_KEY_SZ); + } + else +#endif + { + XMEMSET(m4pHeader, 0, WC_SHE_KEY_SZ); + field = (counter << WC_SHE_M4_COUNT_SHIFT) | WC_SHE_M4_COUNT_PAD; + she_store_be32(m4pHeader, field); } + + (void)she; } +#ifdef WOLFSSL_SHE_EXTENDED int wc_SHE_SetM2Header(wc_SHE* she, const byte* header, word32 headerSz) { if (she == NULL || header == NULL || headerSz != WC_SHE_KEY_SZ) { @@ -386,6 +392,7 @@ int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz) she->m4pOverride = 1; return 0; } +#endif /* WOLFSSL_SHE_EXTENDED */ /* -------------------------------------------------------------------------- */ /* M1/M2/M3 generation */ @@ -397,31 +404,43 @@ int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz) /* */ /* Ported from wolfHSM wh_She_GenerateLoadableKey() in wh_she_crypto.c. */ /* -------------------------------------------------------------------------- */ -int wc_SHE_GenerateM1M2M3(wc_SHE* she) +int wc_SHE_GenerateM1M2M3(wc_SHE* she, + const byte* uid, word32 uidSz, + byte authKeyId, const byte* authKey, word32 authKeySz, + byte targetKeyId, const byte* newKey, word32 newKeySz, + word32 counter, byte flags, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz) { int ret = 0; + byte m2pHeader[WC_SHE_KEY_SZ]; + byte m4pHeader[WC_SHE_KEY_SZ]; byte k1[WC_SHE_KEY_SZ]; byte k2[WC_SHE_KEY_SZ]; byte kdfInput[WC_SHE_KEY_SZ * 2]; + byte encC[] = WC_SHE_KEY_UPDATE_ENC_C; + byte macC[] = WC_SHE_KEY_UPDATE_MAC_C; word32 cmacSz = AES_BLOCK_SIZE; WC_DECLARE_VAR(aes, Aes, 1, 0); WC_DECLARE_VAR(cmac, Cmac, 1, 0); + /* Validate SHE context first — required for both callback and software */ if (she == NULL) { return BAD_FUNC_ARG; } - /* Build M2P/M4P headers from counter/flags (skipped if overridden) */ - she_build_headers(she); - #ifdef WOLF_CRYPTO_CB - /* Try callback first ΓÇö hardware may generate M1/M2/M3 directly */ + /* Try callback first — callback handles its own parameter validation. + * This allows callers to pass NULL authKey/newKey when a secure element + * holds the keys and the callback talks to it directly. */ if (she->devId != INVALID_DEVID) { - ret = wc_CryptoCb_SheGenerateM1M2M3(she, NULL); + ret = wc_CryptoCb_SheGenerateM1M2M3(she, uid, uidSz, + authKeyId, authKey, authKeySz, + targetKeyId, newKey, newKeySz, + counter, flags, + m1, m1Sz, m2, m2Sz, m3, m3Sz); if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - if (ret == 0) { - she->generated = 1; - } return ret; } /* fall-through to software path */ @@ -429,6 +448,29 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she) } #endif + /* Software path — validate all parameters */ + if (uid == NULL || uidSz != WC_SHE_UID_SZ || + authKey == NULL || authKeySz != WC_SHE_KEY_SZ || + newKey == NULL || newKeySz != WC_SHE_KEY_SZ || + m1 == NULL || m1Sz < WC_SHE_M1_SZ || + m2 == NULL || m2Sz < WC_SHE_M2_SZ || + m3 == NULL || m3Sz < WC_SHE_M3_SZ) { + return BAD_FUNC_ARG; + } + + /* Override KDF constants if explicitly set */ +#ifdef WOLFSSL_SHE_EXTENDED + if (she->kdfEncOverride) { + XMEMCPY(encC, she->kdfEncC, WC_SHE_KEY_SZ); + } + if (she->kdfMacOverride) { + XMEMCPY(macC, she->kdfMacC, WC_SHE_KEY_SZ); + } +#endif + + /* Build M2P/M4P headers from counter/flags (skipped if overridden) */ + she_build_headers(she, counter, flags, m2pHeader, m4pHeader); + WC_ALLOC_VAR(aes, Aes, 1, she->heap); if (!WC_VAR_OK(aes)) { return MEMORY_E; @@ -449,34 +491,34 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she) } /* ---- Derive K1 = AES-MP(AuthKey || CENC) ---- */ - XMEMCPY(kdfInput, she->authKey, WC_SHE_KEY_SZ); - XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfEncC, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput, authKey, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, encC, WC_SHE_KEY_SZ); ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k1); /* ---- Build M1: UID(15B) | TargetKeyID(4b) | AuthKeyID(4b) ---- */ if (ret == 0) { - XMEMCPY(she->m1, she->uid, WC_SHE_UID_SZ); - she->m1[WC_SHE_M1_KID_OFFSET] = - (byte)((she->targetKeyId << WC_SHE_M1_KID_SHIFT) | - (she->authKeyId << WC_SHE_M1_AID_SHIFT)); + XMEMCPY(m1, uid, WC_SHE_UID_SZ); + m1[WC_SHE_M1_KID_OFFSET] = + (byte)((targetKeyId << WC_SHE_M1_KID_SHIFT) | + (authKeyId << WC_SHE_M1_AID_SHIFT)); } /* ---- Build cleartext M2 and encrypt with K1 ---- */ if (ret == 0) { /* M2P = m2pHeader(16B) | newKey(16B) */ - XMEMCPY(she->m2, she->m2pHeader, WC_SHE_KEY_SZ); - XMEMCPY(she->m2 + WC_SHE_M2_KEY_OFFSET, she->newKey, WC_SHE_KEY_SZ); + XMEMCPY(m2, m2pHeader, WC_SHE_KEY_SZ); + XMEMCPY(m2 + WC_SHE_M2_KEY_OFFSET, newKey, WC_SHE_KEY_SZ); /* Encrypt M2 in-place with AES-128-CBC, IV = 0 */ ret = wc_AesSetKey(aes, k1, WC_SHE_KEY_SZ, NULL, AES_ENCRYPTION); if (ret == 0) { - ret = wc_AesCbcEncrypt(aes, she->m2, she->m2, WC_SHE_M2_SZ); + ret = wc_AesCbcEncrypt(aes, m2, m2, WC_SHE_M2_SZ); } } - /* ---- Derive K2 = AES-MP(AuthKey || CMAC) ---- */ + /* ---- Derive K2 = AES-MP(AuthKey || CMAC_C) ---- */ if (ret == 0) { - XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfMacC, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, macC, WC_SHE_KEY_SZ); ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k2); } @@ -486,18 +528,14 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she) NULL, she->heap, she->devId); } if (ret == 0) { - ret = wc_CmacUpdate(cmac, she->m1, WC_SHE_M1_SZ); + ret = wc_CmacUpdate(cmac, m1, WC_SHE_M1_SZ); } if (ret == 0) { - ret = wc_CmacUpdate(cmac, she->m2, WC_SHE_M2_SZ); + ret = wc_CmacUpdate(cmac, m2, WC_SHE_M2_SZ); } if (ret == 0) { cmacSz = AES_BLOCK_SIZE; - ret = wc_CmacFinal(cmac, she->m3, &cmacSz); - } - - if (ret == 0) { - she->generated = 1; + ret = wc_CmacFinal(cmac, m3, &cmacSz); } /* Scrub temporary key material */ @@ -520,37 +558,68 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she) /* */ /* These are the expected proof messages that SHE hardware should return. */ /* -------------------------------------------------------------------------- */ -int wc_SHE_GenerateM4M5(wc_SHE* she) +int wc_SHE_GenerateM4M5(wc_SHE* she, + const byte* uid, word32 uidSz, + byte authKeyId, byte targetKeyId, + const byte* newKey, word32 newKeySz, + word32 counter, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz) { int ret = 0; + byte m2pHeader[WC_SHE_KEY_SZ]; + byte m4pHeader[WC_SHE_KEY_SZ]; byte k3[WC_SHE_KEY_SZ]; byte k4[WC_SHE_KEY_SZ]; byte kdfInput[WC_SHE_KEY_SZ * 2]; + byte encC[] = WC_SHE_KEY_UPDATE_ENC_C; + byte macC[] = WC_SHE_KEY_UPDATE_MAC_C; word32 cmacSz; WC_DECLARE_VAR(aes, Aes, 1, 0); WC_DECLARE_VAR(cmac, Cmac, 1, 0); + /* Validate SHE context first */ if (she == NULL) { return BAD_FUNC_ARG; } - if (!she->generated) { - return BAD_STATE_E; - } #ifdef WOLF_CRYPTO_CB - /* Try callback first — sends M1/M2/M3 to HW, receives M4/M5 */ + /* Try callback first — useful for uploading M1/M2/M3 to an HSM which + * loads the key and returns the correct M4/M5 proof values. The callback + * handles its own parameter validation. */ if (she->devId != INVALID_DEVID) { - ret = wc_CryptoCb_SheGenerateM4M5(she, NULL); + ret = wc_CryptoCb_SheGenerateM4M5(she, uid, uidSz, + authKeyId, targetKeyId, + newKey, newKeySz, counter, + m4, m4Sz, m5, m5Sz); if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - if (ret == 0) { - she->verified = 1; - } return ret; } /* fall-through to software path */ } #endif + /* Software path — validate all parameters */ + if (uid == NULL || uidSz != WC_SHE_UID_SZ || + newKey == NULL || newKeySz != WC_SHE_KEY_SZ || + m4 == NULL || m4Sz < WC_SHE_M4_SZ || + m5 == NULL || m5Sz < WC_SHE_M5_SZ) { + return BAD_FUNC_ARG; + } + + /* Override KDF constants if explicitly set */ +#ifdef WOLFSSL_SHE_EXTENDED + if (she->kdfEncOverride) { + XMEMCPY(encC, she->kdfEncC, WC_SHE_KEY_SZ); + } + if (she->kdfMacOverride) { + XMEMCPY(macC, she->kdfMacC, WC_SHE_KEY_SZ); + } +#endif + + /* Build headers from counter (skipped if overridden) */ + she_build_headers(she, counter, 0, m2pHeader, m4pHeader); + WC_ALLOC_VAR(aes, Aes, 1, she->heap); if (!WC_VAR_OK(aes)) { return MEMORY_E; @@ -571,50 +640,46 @@ int wc_SHE_GenerateM4M5(wc_SHE* she) } /* ---- Derive K3 = AES-MP(NewKey || CENC) ---- */ - XMEMCPY(kdfInput, she->newKey, WC_SHE_KEY_SZ); - XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfEncC, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput, newKey, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, encC, WC_SHE_KEY_SZ); ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k3); /* ---- Build M4: UID|IDs header + AES-ECB(K3, m4pHeader) ---- */ if (ret == 0) { - XMEMSET(she->m4, 0, WC_SHE_M4_SZ); + XMEMSET(m4, 0, WC_SHE_M4_SZ); - XMEMCPY(she->m4, she->uid, WC_SHE_UID_SZ); - she->m4[WC_SHE_M4_KID_OFFSET] = - (byte)((she->targetKeyId << WC_SHE_M4_KID_SHIFT) | - (she->authKeyId << WC_SHE_M4_AID_SHIFT)); + XMEMCPY(m4, uid, WC_SHE_UID_SZ); + m4[WC_SHE_M4_KID_OFFSET] = + (byte)((targetKeyId << WC_SHE_M4_KID_SHIFT) | + (authKeyId << WC_SHE_M4_AID_SHIFT)); /* Copy pre-built M4P header (counter|pad) into M4 counter block */ - XMEMCPY(she->m4 + WC_SHE_M4_COUNT_OFFSET, she->m4pHeader, + XMEMCPY(m4 + WC_SHE_M4_COUNT_OFFSET, m4pHeader, WC_SHE_KEY_SZ); /* Encrypt the 16-byte counter block in-place with AES-ECB */ ret = wc_AesSetKey(aes, k3, WC_SHE_KEY_SZ, NULL, AES_ENCRYPTION); if (ret == 0) { ret = wc_AesEncryptDirect(aes, - she->m4 + WC_SHE_M4_COUNT_OFFSET, - she->m4 + WC_SHE_M4_COUNT_OFFSET); + m4 + WC_SHE_M4_COUNT_OFFSET, + m4 + WC_SHE_M4_COUNT_OFFSET); } } - /* ---- Derive K4 = AES-MP(NewKey || CMAC) ---- */ + /* ---- Derive K4 = AES-MP(NewKey || CMAC_C) ---- */ if (ret == 0) { - XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfMacC, WC_SHE_KEY_SZ); + XMEMCPY(kdfInput + WC_SHE_KEY_SZ, macC, WC_SHE_KEY_SZ); ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k4); } /* ---- Build M5 = AES-CMAC(K4, M4) ---- */ if (ret == 0) { cmacSz = AES_BLOCK_SIZE; - ret = wc_AesCmacGenerate_ex(cmac, she->m5, &cmacSz, - she->m4, WC_SHE_M4_SZ, k4, WC_SHE_KEY_SZ, + ret = wc_AesCmacGenerate_ex(cmac, m5, &cmacSz, + m4, WC_SHE_M4_SZ, k4, WC_SHE_KEY_SZ, she->heap, she->devId); } - if (ret == 0) { - she->verified = 1; - } - ForceZero(k3, sizeof(k3)); ForceZero(k4, sizeof(k4)); ForceZero(kdfInput, sizeof(kdfInput)); @@ -633,6 +698,12 @@ int wc_SHE_GenerateM4M5(wc_SHE* she) /* M1/M2/M3 require generated state, M4/M5 require verified state. */ /* Callback: asks hardware to export the key as M1-M5. */ /* -------------------------------------------------------------------------- */ +#if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_EXPORTKEY) +/* -------------------------------------------------------------------------- */ +/* Export Key — callback required */ +/* */ +/* Asks hardware to export a key slot as M1-M5 in SHE loadable format. */ +/* -------------------------------------------------------------------------- */ int wc_SHE_ExportKey(wc_SHE* she, byte* m1, word32 m1Sz, byte* m2, word32 m2Sz, @@ -645,58 +716,10 @@ int wc_SHE_ExportKey(wc_SHE* she, return BAD_FUNC_ARG; } - /* Verify buffer sizes for any non-NULL pointers */ - if ((m1 != NULL && m1Sz < WC_SHE_M1_SZ) || - (m2 != NULL && m2Sz < WC_SHE_M2_SZ) || - (m3 != NULL && m3Sz < WC_SHE_M3_SZ) || - (m4 != NULL && m4Sz < WC_SHE_M4_SZ) || - (m5 != NULL && m5Sz < WC_SHE_M5_SZ)) { - return BUFFER_E; - } - -#ifdef WOLF_CRYPTO_CB - if (she->devId != INVALID_DEVID) { - int ret = wc_CryptoCb_SheExportKey(she, - m1, m1Sz, m2, m2Sz, m3, m3Sz, - m4, m4Sz, m5, m5Sz, ctx); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - return ret; - } - /* fall-through to software path */ - } -#endif - (void)ctx; - - /* Export M1/M2/M3 if requested */ - if (m1 != NULL || m2 != NULL || m3 != NULL) { - if (!she->generated) { - return BAD_STATE_E; - } - if (m1 != NULL) { - XMEMCPY(m1, she->m1, WC_SHE_M1_SZ); - } - if (m2 != NULL) { - XMEMCPY(m2, she->m2, WC_SHE_M2_SZ); - } - if (m3 != NULL) { - XMEMCPY(m3, she->m3, WC_SHE_M3_SZ); - } - } - - /* Export M4/M5 if requested */ - if (m4 != NULL || m5 != NULL) { - if (!she->verified) { - return BAD_STATE_E; - } - if (m4 != NULL) { - XMEMCPY(m4, she->m4, WC_SHE_M4_SZ); - } - if (m5 != NULL) { - XMEMCPY(m5, she->m5, WC_SHE_M5_SZ); - } - } - - return 0; + return wc_CryptoCb_SheExportKey(she, + m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz, ctx); } +#endif /* WOLF_CRYPTO_CB && !NO_WC_SHE_EXPORTKEY */ #endif /* WOLFSSL_SHE */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 72b736649f1..a7273142b2b 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -56162,6 +56162,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) byte m4[WC_SHE_M4_SZ]; byte m5[WC_SHE_M5_SZ]; WC_DECLARE_VAR(she, wc_SHE, 1, HEAP_HINT); + WC_DECLARE_VAR(she2, wc_SHE, 1, HEAP_HINT); /* SHE specification test vector (from wolfHSM wh_test_she.c) */ WOLFSSL_SMALL_STACK_STATIC const byte sheUid[] = { @@ -56215,102 +56216,220 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) return WC_TEST_RET_ENC_EC(ret); } - /* ---- Set inputs from test vector ---- */ - ret = wc_SHE_SetUID(she, sheUid, sizeof(sheUid), NULL); + /* ---- Generate M1/M2/M3 from test vector inputs ---- */ + ret = wc_SHE_GenerateM1M2M3(she, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, vectorAuthKey, sizeof(vectorAuthKey), + 4, vectorNewKey, sizeof(vectorNewKey), + 1, 0, + m1, WC_SHE_M1_SZ, + m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ); if (ret != 0) { goto exit_SHE_Test; } - ret = wc_SHE_SetAuthKey(she, WC_SHE_MASTER_ECU_KEY_ID, - vectorAuthKey, sizeof(vectorAuthKey)); - if (ret != 0) { + /* ---- Check M1 ---- */ + if (XMEMCMP(m1, expM1, WC_SHE_M1_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } - ret = wc_SHE_SetNewKey(she, 4, vectorNewKey, sizeof(vectorNewKey)); + /* ---- Check M2 ---- */ + if (XMEMCMP(m2, expM2, WC_SHE_M2_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Check M3 ---- */ + if (XMEMCMP(m3, expM3, WC_SHE_M3_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Compute and export M4/M5 ---- */ + wc_SHE_Free(she); + ret = wc_SHE_Init(she, HEAP_HINT, devId); + if (ret != 0) { + goto exit_SHE_Test; + } + ret = wc_SHE_GenerateM4M5(she, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + vectorNewKey, sizeof(vectorNewKey), + 1, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ); if (ret != 0) { goto exit_SHE_Test; } - ret = wc_SHE_SetCounter(she, 1); + /* ---- Check M4 ---- */ + if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Check M5 ---- */ + if (XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- Import M1/M2/M3 and generate M4/M5 (only NewKey needed) ---- */ + wc_SHE_Free(she); + ret = wc_SHE_Init(she, HEAP_HINT, devId); if (ret != 0) { goto exit_SHE_Test; } - ret = wc_SHE_SetFlags(she, 0); + /* Import M1/M2/M3, then generate M4/M5 via one-shot */ + ret = wc_SHE_ImportM1M2M3(she, + expM1, WC_SHE_M1_SZ, + expM2, WC_SHE_M2_SZ, + expM3, WC_SHE_M3_SZ); + if (ret != 0) { + goto exit_SHE_Test; + } + ret = wc_SHE_GenerateM4M5(she, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + vectorNewKey, sizeof(vectorNewKey), + 1, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ); if (ret != 0) { goto exit_SHE_Test; } - /* ---- Generate M1/M2/M3 ---- */ - ret = wc_SHE_GenerateM1M2M3(she); + if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + if (XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + + /* ---- One-shot M1/M2/M3 ---- */ + wc_SHE_Free(she); + ret = wc_SHE_Init(she, HEAP_HINT, devId); if (ret != 0) { goto exit_SHE_Test; } - /* ---- Export M1/M2/M3 ---- */ - ret = wc_SHE_ExportKey(she, - m1, WC_SHE_M1_SZ, - m2, WC_SHE_M2_SZ, - m3, WC_SHE_M3_SZ, - NULL, 0, - NULL, 0, - NULL); + ret = wc_SHE_GenerateM1M2M3(she, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, vectorAuthKey, sizeof(vectorAuthKey), + 4, vectorNewKey, sizeof(vectorNewKey), + 1, 0, + m1, WC_SHE_M1_SZ, + m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ); if (ret != 0) { goto exit_SHE_Test; } - /* ---- Check M1 ---- */ if (XMEMCMP(m1, expM1, WC_SHE_M1_SZ) != 0) { ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } - - /* ---- Check M2 ---- */ if (XMEMCMP(m2, expM2, WC_SHE_M2_SZ) != 0) { ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } - - /* ---- Check M3 ---- */ if (XMEMCMP(m3, expM3, WC_SHE_M3_SZ) != 0) { ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } - /* ---- Compute M4/M5 ---- */ - ret = wc_SHE_GenerateM4M5(she); + /* ---- One-shot M4/M5 ---- */ + wc_SHE_Free(she); + ret = wc_SHE_Init(she, HEAP_HINT, devId); if (ret != 0) { goto exit_SHE_Test; } - /* ---- Export M4/M5 ---- */ - ret = wc_SHE_ExportKey(she, - NULL, 0, - NULL, 0, - NULL, 0, - m4, WC_SHE_M4_SZ, - m5, WC_SHE_M5_SZ, - NULL); + ret = wc_SHE_GenerateM4M5(she, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + vectorNewKey, sizeof(vectorNewKey), + 1, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ); if (ret != 0) { goto exit_SHE_Test; } - /* ---- Check M4 ---- */ if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0) { ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } - - /* ---- Check M5 ---- */ if (XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } + /* ---- Independence test: two separate contexts, M1M2M3 and M4M5 ---- */ + wc_SHE_Free(she); + ret = wc_SHE_Init(she, HEAP_HINT, devId); + if (ret != 0) { + goto exit_SHE_Test; + } + + WC_ALLOC_VAR(she2, wc_SHE, 1, HEAP_HINT); + if (!WC_VAR_OK(she2)) { + ret = WC_TEST_RET_ENC_EC(MEMORY_E); + goto exit_SHE_Test; + } + ret = wc_SHE_Init(she2, HEAP_HINT, devId); + if (ret != 0) { + WC_FREE_VAR(she2, HEAP_HINT); + goto exit_SHE_Test; + } + + /* Generate M1/M2/M3 on first context */ + ret = wc_SHE_GenerateM1M2M3(she, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, vectorAuthKey, sizeof(vectorAuthKey), + 4, vectorNewKey, sizeof(vectorNewKey), + 1, 0, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ); + if (ret != 0) { + wc_SHE_Free(she2); + WC_FREE_VAR(she2, HEAP_HINT); + goto exit_SHE_Test; + } + + /* Generate M4/M5 on second context — completely independent */ + ret = wc_SHE_GenerateM4M5(she2, + sheUid, sizeof(sheUid), + WC_SHE_MASTER_ECU_KEY_ID, 4, + vectorNewKey, sizeof(vectorNewKey), + 1, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ); + + wc_SHE_Free(she2); + WC_FREE_VAR(she2, HEAP_HINT); + + if (ret != 0) { + goto exit_SHE_Test; + } + + /* Verify both match the test vector */ + if (XMEMCMP(m1, expM1, WC_SHE_M1_SZ) != 0 || + XMEMCMP(m2, expM2, WC_SHE_M2_SZ) != 0 || + XMEMCMP(m3, expM3, WC_SHE_M3_SZ) != 0 || + XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0 || + XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + exit_SHE_Test: wc_SHE_Free(she); WC_FREE_VAR(she, HEAP_HINT); + WC_FREE_VAR(she2, HEAP_HINT); return ret; } @@ -66419,28 +66538,76 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) switch (info->she.type) { case WC_SHE_SET_UID: - ret = wc_SHE_SetUID(she, info->she.op.setUid.uid, - info->she.op.setUid.uidSz, - info->she.ctx); + /* Test callback: just acknowledge, UID is in caller's buffer */ + ret = 0; + break; + case WC_SHE_GET_COUNTER: + { + static word32 simCounter = 0; + if (info->she.op.getCounter.counter != NULL) { + *info->she.op.getCounter.counter = ++simCounter; + } + ret = 0; + break; + } + case WC_SHE_GENERATE_M1M2M3: + /* Re-call with software devId using params from callback */ + ret = wc_SHE_GenerateM1M2M3(she, + info->she.op.generateM1M2M3.uid, + info->she.op.generateM1M2M3.uidSz, + info->she.op.generateM1M2M3.authKeyId, + info->she.op.generateM1M2M3.authKey, + info->she.op.generateM1M2M3.authKeySz, + info->she.op.generateM1M2M3.targetKeyId, + info->she.op.generateM1M2M3.newKey, + info->she.op.generateM1M2M3.newKeySz, + info->she.op.generateM1M2M3.counter, + info->she.op.generateM1M2M3.flags, + info->she.op.generateM1M2M3.m1, + info->she.op.generateM1M2M3.m1Sz, + info->she.op.generateM1M2M3.m2, + info->she.op.generateM1M2M3.m2Sz, + info->she.op.generateM1M2M3.m3, + info->she.op.generateM1M2M3.m3Sz); break; case WC_SHE_GENERATE_M4M5: - /* Re-call with software devId — fills she->m4/m5 */ - ret = wc_SHE_GenerateM4M5(she); + /* Re-call with software devId using params from callback */ + ret = wc_SHE_GenerateM4M5(she, + info->she.op.generateM4M5.uid, + info->she.op.generateM4M5.uidSz, + info->she.op.generateM4M5.authKeyId, + info->she.op.generateM4M5.targetKeyId, + info->she.op.generateM4M5.newKey, + info->she.op.generateM4M5.newKeySz, + info->she.op.generateM4M5.counter, + info->she.op.generateM4M5.m4, + info->she.op.generateM4M5.m4Sz, + info->she.op.generateM4M5.m5, + info->she.op.generateM4M5.m5Sz); break; case WC_SHE_EXPORT_KEY: - /* Fall back to software export */ - ret = wc_SHE_ExportKey(she, - info->she.op.exportKey.m1, - info->she.op.exportKey.m1Sz, - info->she.op.exportKey.m2, - info->she.op.exportKey.m2Sz, - info->she.op.exportKey.m3, - info->she.op.exportKey.m3Sz, - info->she.op.exportKey.m4, - info->she.op.exportKey.m4Sz, - info->she.op.exportKey.m5, - info->she.op.exportKey.m5Sz, - info->she.ctx); + /* Simulate hardware export — fill with test pattern */ + if (info->she.op.exportKey.m1 != NULL) { + XMEMSET(info->she.op.exportKey.m1, 0x11, + WC_SHE_M1_SZ); + } + if (info->she.op.exportKey.m2 != NULL) { + XMEMSET(info->she.op.exportKey.m2, 0x22, + WC_SHE_M2_SZ); + } + if (info->she.op.exportKey.m3 != NULL) { + XMEMSET(info->she.op.exportKey.m3, 0x33, + WC_SHE_M3_SZ); + } + if (info->she.op.exportKey.m4 != NULL) { + XMEMSET(info->she.op.exportKey.m4, 0x44, + WC_SHE_M4_SZ); + } + if (info->she.op.exportKey.m5 != NULL) { + XMEMSET(info->she.op.exportKey.m5, 0x55, + WC_SHE_M5_SZ); + } + ret = 0; break; default: ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index ba322cf14d1..f9c04bb5f03 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -468,19 +468,53 @@ typedef struct wc_CryptoInfo { const void* ctx; /* read-only caller context */ union { struct { - const byte* uid; /* caller-provided UID (may be NULL) */ - word32 uidSz; /* size of uid buffer */ + const byte* uid; + word32 uidSz; } setUid; struct { - byte* m1; /* output: M1 */ + word32* counter; + } getCounter; + struct { + const byte* uid; + word32 uidSz; + byte authKeyId; + const byte* authKey; + word32 authKeySz; + byte targetKeyId; + const byte* newKey; + word32 newKeySz; + word32 counter; + byte flags; + byte* m1; + word32 m1Sz; + byte* m2; + word32 m2Sz; + byte* m3; + word32 m3Sz; + } generateM1M2M3; + struct { + const byte* uid; + word32 uidSz; + byte authKeyId; + byte targetKeyId; + const byte* newKey; + word32 newKeySz; + word32 counter; + byte* m4; + word32 m4Sz; + byte* m5; + word32 m5Sz; + } generateM4M5; + struct { + byte* m1; word32 m1Sz; - byte* m2; /* output: M2 */ + byte* m2; word32 m2Sz; - byte* m3; /* output: M3 */ + byte* m3; word32 m3Sz; - byte* m4; /* output: M4 */ + byte* m4; word32 m4Sz; - byte* m5; /* output: M5 */ + byte* m5; word32 m5Sz; } exportKey; } op; @@ -789,10 +823,23 @@ WOLFSSL_LOCAL int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, #ifdef WOLFSSL_SHE WOLFSSL_LOCAL int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, word32 uidSz, const void* ctx); +WOLFSSL_LOCAL int wc_CryptoCb_SheGetCounter(wc_SHE* she, word32* counter, + const void* ctx); WOLFSSL_LOCAL int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, - const void* ctx); + const byte* uid, word32 uidSz, + byte authKeyId, const byte* authKey, word32 authKeySz, + byte targetKeyId, const byte* newKey, word32 newKeySz, + word32 counter, byte flags, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz); WOLFSSL_LOCAL int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, - const void* ctx); + const byte* uid, word32 uidSz, + byte authKeyId, byte targetKeyId, + const byte* newKey, word32 newKeySz, + word32 counter, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz); WOLFSSL_LOCAL int wc_CryptoCb_SheExportKey(wc_SHE* she, byte* m1, word32 m1Sz, byte* m2, word32 m2Sz, diff --git a/wolfssl/wolfcrypt/she.h b/wolfssl/wolfcrypt/she.h index 0b49a5c6773..2c7377d7375 100644 --- a/wolfssl/wolfcrypt/she.h +++ b/wolfssl/wolfcrypt/she.h @@ -46,9 +46,10 @@ /* crypto callback sub-types for WC_ALGO_TYPE_SHE */ enum wc_SheType { WC_SHE_SET_UID = 1, - WC_SHE_GENERATE_M1M2M3 = 2, - WC_SHE_GENERATE_M4M5 = 3, - WC_SHE_EXPORT_KEY = 4 + WC_SHE_GET_COUNTER = 2, + WC_SHE_GENERATE_M1M2M3 = 3, + WC_SHE_GENERATE_M4M5 = 4, + WC_SHE_EXPORT_KEY = 5 }; /* test flags (only used for KATs) */ @@ -93,29 +94,26 @@ enum { }; typedef struct wc_SHE { - byte uid[WC_SHE_UID_SZ]; - byte authKeyId; - byte targetKeyId; - byte authKey[WC_SHE_KEY_SZ]; - byte newKey[WC_SHE_KEY_SZ]; - word32 counter; - byte flags; - - byte kdfEncC[WC_SHE_KEY_SZ]; /* KDF encryption constant (CENC) */ - byte kdfMacC[WC_SHE_KEY_SZ]; /* KDF authentication constant (CMAC) */ - byte m2pHeader[WC_SHE_KEY_SZ]; /* M2P cleartext header (counter|flags|pad) */ - byte m4pHeader[WC_SHE_KEY_SZ]; /* M4P cleartext header (counter|pad) */ - byte m2pOverride; /* set by SetM2Header to skip auto-build */ - byte m4pOverride; /* set by SetM4Header to skip auto-build */ +#ifdef WOLFSSL_SHE_EXTENDED + /* Custom KDF constants and header overrides. + * Useful for some HSMs that support multiple key groups with + * different derivation constants. */ + byte kdfEncC[WC_SHE_KEY_SZ]; + byte kdfMacC[WC_SHE_KEY_SZ]; + byte m2pHeader[WC_SHE_KEY_SZ]; + byte m4pHeader[WC_SHE_KEY_SZ]; + byte kdfEncOverride; + byte kdfMacOverride; + byte m2pOverride; + byte m4pOverride; +#endif +#if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) byte m1[WC_SHE_M1_SZ]; byte m2[WC_SHE_M2_SZ]; byte m3[WC_SHE_M3_SZ]; - byte m4[WC_SHE_M4_SZ]; - byte m5[WC_SHE_M5_SZ]; - byte generated; - byte verified; +#endif void* heap; int devId; @@ -143,54 +141,69 @@ WOLFSSL_API int wc_SHE_Init_Label(wc_SHE* she, const char* label, void* heap, int devId); #endif -/* Scrub key material and zero the context */ +/* Scrub and zero the context */ WOLFSSL_API void wc_SHE_Free(wc_SHE* she); -/* Set UID; callback optional (WC_SHE_SET_UID) */ -WOLFSSL_API int wc_SHE_SetUID(wc_SHE* she, const byte* uid, word32 uidSz, +/* Get UID from hardware; callback required (WC_SHE_SET_UID) */ +#if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETUID) +WOLFSSL_API int wc_SHE_GetUID(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx); +#endif -/* Set authorizing key slot ID and value */ -WOLFSSL_API int wc_SHE_SetAuthKey(wc_SHE* she, byte authKeyId, - const byte* authKey, word32 keySz); - -/* Set target key slot ID and new key value */ -WOLFSSL_API int wc_SHE_SetNewKey(wc_SHE* she, byte targetKeyId, - const byte* newKey, word32 keySz); - -/* Set monotonic counter value for M2 */ -WOLFSSL_API int wc_SHE_SetCounter(wc_SHE* she, word32 counter); - -/* Set flag byte for M2 */ -WOLFSSL_API int wc_SHE_SetFlags(wc_SHE* she, byte flags); +/* Get counter from hardware; callback required */ +#if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETCOUNTER) +WOLFSSL_API int wc_SHE_GetCounter(wc_SHE* she, word32* counter, + const void* ctx); +#endif -/* Set KDF constants (CENC/CMAC) used for key derivation. - * Defaults are set by Init. Either pointer may be NULL to skip. */ +/* Custom KDF constants and header overrides. + * Useful for some HSMs that support multiple key groups with + * different derivation constants. */ +#ifdef WOLFSSL_SHE_EXTENDED +/* Set KDF constants (CENC/CMAC). Defaults set by Init. NULL to skip. */ WOLFSSL_API int wc_SHE_SetKdfConstants(wc_SHE* she, const byte* encC, word32 encCSz, const byte* macC, word32 macCSz); -/* Override M2P cleartext header (first 16 bytes before KID'). - * Skips auto-build from counter/flags in GenerateM1M2M3. */ +/* Override M2P cleartext header. Skips auto-build from counter/flags. */ WOLFSSL_API int wc_SHE_SetM2Header(wc_SHE* she, const byte* header, word32 headerSz); -/* Override M4P cleartext header (16-byte counter block). - * Skips auto-build from counter in GenerateM4M5. */ +/* Override M4P cleartext header. Skips auto-build from counter. */ WOLFSSL_API int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz); +#endif /* WOLFSSL_SHE_EXTENDED */ + +/* Import externally-provided M1/M2/M3 into context; sets generated flag */ +#if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) +WOLFSSL_API int wc_SHE_ImportM1M2M3(wc_SHE* she, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz); +#endif -/* Generate M1/M2/M3 from the current context */ -WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she); - -/* Miyaguchi-Preneel AES-128 compression (internal, exposed for testing) */ -WOLFSSL_TEST_VIS int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, - byte* out); - -/* Generate M4/M5 verification messages; callback optional (WC_SHE_GENERATE_M4M5) */ -WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she); +/* Generate M1/M2/M3 and write to caller buffers */ +WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she, + const byte* uid, word32 uidSz, + byte authKeyId, const byte* authKey, word32 authKeySz, + byte targetKeyId, const byte* newKey, word32 newKeySz, + word32 counter, byte flags, + byte* m1, word32 m1Sz, + byte* m2, word32 m2Sz, + byte* m3, word32 m3Sz); + +/* Generate M4/M5 and write to caller buffers */ +WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she, + const byte* uid, word32 uidSz, + byte authKeyId, byte targetKeyId, + const byte* newKey, word32 newKeySz, + word32 counter, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz); -/* Export M1-M5 into caller buffers; NULL to skip; callback optional (WC_SHE_EXPORT_KEY) */ +/* Export key from hardware as M1-M5; callback required. + * Some HSMs allow exporting certain key slots (e.g. RAM key) in SHE format. */ +#if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_EXPORTKEY) WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she, byte* m1, word32 m1Sz, byte* m2, word32 m2Sz, @@ -198,6 +211,11 @@ WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she, byte* m4, word32 m4Sz, byte* m5, word32 m5Sz, const void* ctx); +#endif + +/* Internal: Miyaguchi-Preneel AES-128 compression, exposed for testing */ +WOLFSSL_TEST_VIS int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, + byte* out); #ifdef __cplusplus } /* extern "C" */ From 5d69c5bef54d22879251629c98443fb3300dbed2 Mon Sep 17 00:00:00 2001 From: night1rider Date: Fri, 20 Mar 2026 18:27:49 -0600 Subject: [PATCH 04/12] Add more in depth comments in header file for she.h --- .wolfssl_known_macro_extras | 2 +- tests/api/test_she.c | 6 +- wolfcrypt/src/she.c | 22 ++--- wolfcrypt/test/test.c | 8 +- wolfssl/wolfcrypt/she.h | 165 +++++++++++++++++++++++++++++++----- 5 files changed, 163 insertions(+), 40 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 1aae33177b7..b447ec84e9c 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -887,9 +887,9 @@ WOLFSSL_SE050_NO_TRNG WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT WOLFSSL_SERVER_EXAMPLE WOLFSSL_SETTINGS_FILE +WOLFSSL_SH224 WOLFSSL_SHE WOLFSSL_SHE_EXTENDED -WOLFSSL_SH224 WOLFSSL_SHA256_ALT_CH_MAJ WOLFSSL_SHA512_HASHTYPE WOLFSSL_SHUTDOWNONCE diff --git a/tests/api/test_she.c b/tests/api/test_she.c index 2d988266466..2fc226111aa 100644 --- a/tests/api/test_she.c +++ b/tests/api/test_she.c @@ -428,7 +428,7 @@ int test_wc_SHE_SetM2M4Header(void) #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) && !defined(NO_AES) -/* SHE callback — re-calls with software devId */ +/* SHE callback -- re-calls with software devId */ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) { wc_SHE* she; @@ -513,7 +513,7 @@ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->she.op.generateM4M5.m5Sz); break; case WC_SHE_EXPORT_KEY: - /* Simulate hardware export — fill with test pattern */ + /* Simulate hardware export -- fill with test pattern */ if (info->she.op.exportKey.m1 != NULL) { XMEMSET(info->she.op.exportKey.m1, 0x11, WC_SHE_M1_SZ); } @@ -572,7 +572,7 @@ int test_wc_SHE_CryptoCb(void) ExpectIntEQ(XMEMCMP(m4, sheTestExpM4, WC_SHE_M4_SZ), 0); ExpectIntEQ(XMEMCMP(m5, sheTestExpM5, WC_SHE_M5_SZ), 0); - /* ExportKey via callback — simulated hardware */ + /* ExportKey via callback -- simulated hardware */ #if !defined(NO_WC_SHE_EXPORTKEY) { byte em1[WC_SHE_M1_SZ]; diff --git a/wolfcrypt/src/she.c b/wolfcrypt/src/she.c index 2539efa7f49..df44113bb4f 100644 --- a/wolfcrypt/src/she.c +++ b/wolfcrypt/src/she.c @@ -123,7 +123,7 @@ int wc_SHE_Init(wc_SHE* she, void* heap, int devId) ForceZero(she, sizeof(wc_SHE)); she->heap = heap; she->devId = devId; - /* kdfEncOverride/kdfMacOverride are zero from XMEMSET — defaults used */ + /* kdfEncOverride/kdfMacOverride are zero from XMEMSET -- defaults used */ return 0; } @@ -222,7 +222,7 @@ void wc_SHE_Free(wc_SHE* she) } /* -------------------------------------------------------------------------- */ -/* GetUID — callback required */ +/* GetUID -- callback required */ /* */ /* Dispatches to callback to fetch UID from hardware. */ /* Buffer size validation is the callback's responsibility. */ @@ -241,7 +241,7 @@ int wc_SHE_GetUID(wc_SHE* she, byte* uid, word32 uidSz, #endif /* WOLF_CRYPTO_CB && !NO_WC_SHE_GETUID */ /* -------------------------------------------------------------------------- */ -/* GetCounter — callback required */ +/* GetCounter -- callback required */ /* */ /* Dispatches to callback to read current counter from hardware. */ /* Returns CRYPTOCB_UNAVAILABLE if no callback. */ @@ -425,13 +425,13 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, WC_DECLARE_VAR(aes, Aes, 1, 0); WC_DECLARE_VAR(cmac, Cmac, 1, 0); - /* Validate SHE context first — required for both callback and software */ + /* Validate SHE context first -- required for both callback and software */ if (she == NULL) { return BAD_FUNC_ARG; } #ifdef WOLF_CRYPTO_CB - /* Try callback first — callback handles its own parameter validation. + /* Try callback first -- callback handles its own parameter validation. * This allows callers to pass NULL authKey/newKey when a secure element * holds the keys and the callback talks to it directly. */ if (she->devId != INVALID_DEVID) { @@ -448,7 +448,7 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, } #endif - /* Software path — validate all parameters */ + /* Software path -- validate all parameters */ if (uid == NULL || uidSz != WC_SHE_UID_SZ || authKey == NULL || authKeySz != WC_SHE_KEY_SZ || newKey == NULL || newKeySz != WC_SHE_KEY_SZ || @@ -482,7 +482,7 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, return MEMORY_E; } - /* Init AES once — used by both MP16 and CBC */ + /* Init AES once -- used by both MP16 and CBC */ ret = wc_AesInit(aes, she->heap, she->devId); if (ret != 0) { WC_FREE_VAR(aes, she->heap); @@ -584,7 +584,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, } #ifdef WOLF_CRYPTO_CB - /* Try callback first — useful for uploading M1/M2/M3 to an HSM which + /* Try callback first -- useful for uploading M1/M2/M3 to an HSM which * loads the key and returns the correct M4/M5 proof values. The callback * handles its own parameter validation. */ if (she->devId != INVALID_DEVID) { @@ -599,7 +599,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, } #endif - /* Software path — validate all parameters */ + /* Software path -- validate all parameters */ if (uid == NULL || uidSz != WC_SHE_UID_SZ || newKey == NULL || newKeySz != WC_SHE_KEY_SZ || m4 == NULL || m4Sz < WC_SHE_M4_SZ || @@ -631,7 +631,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, return MEMORY_E; } - /* Init AES once — used by both MP16 and ECB */ + /* Init AES once -- used by both MP16 and ECB */ ret = wc_AesInit(aes, she->heap, she->devId); if (ret != 0) { WC_FREE_VAR(aes, she->heap); @@ -700,7 +700,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, /* -------------------------------------------------------------------------- */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_EXPORTKEY) /* -------------------------------------------------------------------------- */ -/* Export Key — callback required */ +/* Export Key -- callback required */ /* */ /* Asks hardware to export a key slot as M1-M5 in SHE loadable format. */ /* -------------------------------------------------------------------------- */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a7273142b2b..7c4a42d15d9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -56276,6 +56276,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) goto exit_SHE_Test; } +#if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) /* ---- Import M1/M2/M3 and generate M4/M5 (only NewKey needed) ---- */ wc_SHE_Free(she); ret = wc_SHE_Init(she, HEAP_HINT, devId); @@ -56283,7 +56284,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) goto exit_SHE_Test; } - /* Import M1/M2/M3, then generate M4/M5 via one-shot */ + /* Import M1/M2/M3, then generate M4/M5 */ ret = wc_SHE_ImportM1M2M3(she, expM1, WC_SHE_M1_SZ, expM2, WC_SHE_M2_SZ, @@ -56310,6 +56311,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) ret = WC_TEST_RET_ENC_NC; goto exit_SHE_Test; } +#endif /* WOLF_CRYPTO_CB || !NO_WC_SHE_IMPORT_M123 */ /* ---- One-shot M1/M2/M3 ---- */ wc_SHE_Free(she); @@ -56401,7 +56403,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) goto exit_SHE_Test; } - /* Generate M4/M5 on second context — completely independent */ + /* Generate M4/M5 on second context -- completely independent */ ret = wc_SHE_GenerateM4M5(she2, sheUid, sizeof(sheUid), WC_SHE_MASTER_ECU_KEY_ID, 4, @@ -66586,7 +66588,7 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->she.op.generateM4M5.m5Sz); break; case WC_SHE_EXPORT_KEY: - /* Simulate hardware export — fill with test pattern */ + /* Simulate hardware export -- fill with test pattern */ if (info->she.op.exportKey.m1 != NULL) { XMEMSET(info->she.op.exportKey.m1, 0x11, WC_SHE_M1_SZ); diff --git a/wolfssl/wolfcrypt/she.h b/wolfssl/wolfcrypt/she.h index 2c7377d7375..ac1b9c4e344 100644 --- a/wolfssl/wolfcrypt/she.h +++ b/wolfssl/wolfcrypt/she.h @@ -34,14 +34,14 @@ extern "C" { #endif -#define WC_SHE_KEY_SZ 16 -#define WC_SHE_UID_SZ 15 +#define WC_SHE_KEY_SZ 16 /* AES-128 key size (128 bits) */ +#define WC_SHE_UID_SZ 15 /* SHE UID size (120 bits) */ -#define WC_SHE_M1_SZ 16 -#define WC_SHE_M2_SZ 32 -#define WC_SHE_M3_SZ 16 -#define WC_SHE_M4_SZ 32 -#define WC_SHE_M5_SZ 16 +#define WC_SHE_M1_SZ 16 /* UID(15B) | KeyID(4b) | AuthID(4b) */ +#define WC_SHE_M2_SZ 32 /* AES-CBC(K1, counter|flags|pad|newkey) */ +#define WC_SHE_M3_SZ 16 /* AES-CMAC(K2, M1|M2) */ +#define WC_SHE_M4_SZ 32 /* UID|IDs + AES-ECB(K3, counter|pad) */ +#define WC_SHE_M5_SZ 16 /* AES-CMAC(K4, M4) */ /* crypto callback sub-types for WC_ALGO_TYPE_SHE */ enum wc_SheType { @@ -129,28 +129,55 @@ typedef struct wc_SHE { } wc_SHE; -/* Initialize SHE context, store heap hint and device ID */ +/* Initialize SHE context, store heap hint and device ID. + * she - pointer to wc_SHE structure to initialize + * heap - heap hint for internal allocations, or NULL + * devId - crypto callback device ID, or INVALID_DEVID for software */ WOLFSSL_API int wc_SHE_Init(wc_SHE* she, void* heap, int devId); #ifdef WOLF_PRIVATE_KEY_ID -/* Initialize with opaque hardware key identifier */ +/* Initialize with opaque hardware key identifier. + * Useful when using callbacks and additional info needs to be attached + * to the SHE context to determine slot or key group information. + * she - pointer to wc_SHE structure to initialize + * id - opaque key identifier bytes + * len - length of id in bytes (0 to WC_SHE_MAX_ID_LEN) + * heap - heap hint for internal allocations, or NULL + * devId - crypto callback device ID */ WOLFSSL_API int wc_SHE_Init_Id(wc_SHE* she, unsigned char* id, int len, void* heap, int devId); -/* Initialize with human-readable key label */ + +/* Initialize with human-readable key label. + * Useful when using callbacks and additional info needs to be attached + * to the SHE context to determine slot or key group information. + * she - pointer to wc_SHE structure to initialize + * label - NUL-terminated key label string + * heap - heap hint for internal allocations, or NULL + * devId - crypto callback device ID */ WOLFSSL_API int wc_SHE_Init_Label(wc_SHE* she, const char* label, void* heap, int devId); #endif -/* Scrub and zero the context */ +/* Scrub all data and zero the context. Safe to call on NULL. */ WOLFSSL_API void wc_SHE_Free(wc_SHE* she); -/* Get UID from hardware; callback required (WC_SHE_SET_UID) */ +/* Get UID from hardware via callback (WC_SHE_SET_UID). + * she - initialized SHE context with a registered callback + * uid - buffer to receive the 120-bit (15-byte) SHE UID + * uidSz - size of uid buffer in bytes + * ctx - read-only caller context passed to the callback + * (e.g. challenge buffer, HSM handle) */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETUID) WOLFSSL_API int wc_SHE_GetUID(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx); #endif -/* Get counter from hardware; callback required */ +/* Get monotonic counter from hardware via callback (WC_SHE_GET_COUNTER). + * she - initialized SHE context with a registered callback + * counter - pointer to receive the current counter value. + * The SHE spec uses a 28-bit counter. The caller should + * increment this value before passing to GenerateM1M2M3/M4M5. + * ctx - read-only caller context passed to the callback */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETCOUNTER) WOLFSSL_API int wc_SHE_GetCounter(wc_SHE* she, word32* counter, const void* ctx); @@ -160,21 +187,47 @@ WOLFSSL_API int wc_SHE_GetCounter(wc_SHE* she, word32* counter, * Useful for some HSMs that support multiple key groups with * different derivation constants. */ #ifdef WOLFSSL_SHE_EXTENDED -/* Set KDF constants (CENC/CMAC). Defaults set by Init. NULL to skip. */ +/* Set KDF constants used in Miyaguchi-Preneel key derivation. + * Defaults are KEY_UPDATE_ENC_C and KEY_UPDATE_MAC_C from the SHE spec. + * Either pointer may be NULL to leave that constant unchanged. + * she - initialized SHE context + * encC - 16-byte encryption derivation constant (CENC), or NULL + * encCSz - must be WC_SHE_KEY_SZ (16) when encC is non-NULL + * macC - 16-byte MAC derivation constant (CMAC), or NULL + * macCSz - must be WC_SHE_KEY_SZ (16) when macC is non-NULL */ WOLFSSL_API int wc_SHE_SetKdfConstants(wc_SHE* she, const byte* encC, word32 encCSz, const byte* macC, word32 macCSz); -/* Override M2P cleartext header. Skips auto-build from counter/flags. */ +/* Override M2 cleartext header (first 16 bytes of M2 before encryption). + * When set, GenerateM1M2M3 uses this instead of auto-building from + * counter and flags. The header is: counter(28b)|flags(4b)|zeros(96b). + * she - initialized SHE context + * header - 16-byte cleartext header block + * headerSz - must be WC_SHE_KEY_SZ (16) */ WOLFSSL_API int wc_SHE_SetM2Header(wc_SHE* she, const byte* header, word32 headerSz); -/* Override M4P cleartext header. Skips auto-build from counter. */ +/* Override M4 cleartext counter block (16-byte block encrypted with K3). + * When set, GenerateM4M5 uses this instead of auto-building from counter. + * The block is: counter(28b)|1(1b)|zeros(99b). + * she - initialized SHE context + * header - 16-byte cleartext counter block + * headerSz - must be WC_SHE_KEY_SZ (16) */ WOLFSSL_API int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz); #endif /* WOLFSSL_SHE_EXTENDED */ -/* Import externally-provided M1/M2/M3 into context; sets generated flag */ +/* Import externally-provided M1/M2/M3 into context. + * Sets the generated flag so the callback for GenerateM4M5 can + * read M1/M2/M3 from the context to send to hardware. + * she - initialized SHE context + * m1 - 16-byte M1 message (UID | KeyID | AuthID) + * m1Sz - must be WC_SHE_M1_SZ (16) + * m2 - 32-byte M2 message (encrypted counter|flags|pad|newkey) + * m2Sz - must be WC_SHE_M2_SZ (32) + * m3 - 16-byte M3 message (CMAC over M1|M2) + * m3Sz - must be WC_SHE_M3_SZ (16) */ #if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) WOLFSSL_API int wc_SHE_ImportM1M2M3(wc_SHE* she, const byte* m1, word32 m1Sz, @@ -182,7 +235,36 @@ WOLFSSL_API int wc_SHE_ImportM1M2M3(wc_SHE* she, const byte* m3, word32 m3Sz); #endif -/* Generate M1/M2/M3 and write to caller buffers */ +/* Generate M1/M2/M3 for the SHE key update protocol and write to + * caller-provided buffers. Callback optional -- if a callback is + * registered it is tried first; if it returns CRYPTOCB_UNAVAILABLE + * the software path runs. This allows a secure element to generate + * M1/M2/M3 when it holds the auth key internally. + * + * she - initialized SHE context + * uid - 15-byte SHE UID (120-bit ECU/module identifier) + * uidSz - must be WC_SHE_UID_SZ (15) + * authKeyId - slot ID of the authorizing key (0-14, e.g. + * MASTER_ECU_KEY=1, KEY_1..KEY_10=4..13) + * authKey - 16-byte value of the authorizing key. Used to derive + * K1 (encryption) and K2 (MAC). May be NULL when the + * callback handles key access. + * authKeySz - must be WC_SHE_KEY_SZ (16) when authKey is non-NULL + * targetKeyId - slot ID of the key being loaded (1-14) + * newKey - 16-byte value of the new key to load. Placed in M2 + * cleartext and used to derive K3/K4 for M4/M5. + * May be NULL when the callback handles key access. + * newKeySz - must be WC_SHE_KEY_SZ (16) when newKey is non-NULL + * counter - 28-bit monotonic counter value. Must be strictly greater + * than the counter stored in the target slot on the SHE. + * flags - key protection flags (lower 4 bits of the counter|flags + * word in M2). + * m1 - output buffer for M1 (16 bytes) + * m1Sz - size of m1 buffer, must be >= WC_SHE_M1_SZ + * m2 - output buffer for M2 (32 bytes) + * m2Sz - size of m2 buffer, must be >= WC_SHE_M2_SZ + * m3 - output buffer for M3 (16 bytes) + * m3Sz - size of m3 buffer, must be >= WC_SHE_M3_SZ */ WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she, const byte* uid, word32 uidSz, byte authKeyId, const byte* authKey, word32 authKeySz, @@ -192,7 +274,25 @@ WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she, byte* m2, word32 m2Sz, byte* m3, word32 m3Sz); -/* Generate M4/M5 and write to caller buffers */ +/* Generate M4/M5 verification messages and write to caller-provided + * buffers. Independent of M1/M2/M3 -- can be called on a separate + * context. Callback optional -- useful for uploading M1/M2/M3 to an + * HSM which loads the key and returns M4/M5 as proof. + * + * she - initialized SHE context + * uid - 15-byte SHE UID (same UID used for M1) + * uidSz - must be WC_SHE_UID_SZ (15) + * authKeyId - slot ID of the authorizing key (same as in M1) + * targetKeyId - slot ID of the key being loaded (same as in M1) + * newKey - 16-byte value of the new key. Used to derive K3 + * (encryption for M4 counter block) and K4 (MAC for M5). + * May be NULL when the callback handles key access. + * newKeySz - must be WC_SHE_KEY_SZ (16) when newKey is non-NULL + * counter - 28-bit monotonic counter (same value as in M2) + * m4 - output buffer for M4 (32 bytes) + * m4Sz - size of m4 buffer, must be >= WC_SHE_M4_SZ + * m5 - output buffer for M5 (16 bytes) + * m5Sz - size of m5 buffer, must be >= WC_SHE_M5_SZ */ WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she, const byte* uid, word32 uidSz, byte authKeyId, byte targetKeyId, @@ -201,8 +301,22 @@ WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she, byte* m4, word32 m4Sz, byte* m5, word32 m5Sz); -/* Export key from hardware as M1-M5; callback required. - * Some HSMs allow exporting certain key slots (e.g. RAM key) in SHE format. */ +/* Export a key from hardware in SHE loadable format (M1-M5). + * Callback required -- dispatches to WC_SHE_EXPORT_KEY. + * Some HSMs allow exporting certain key slots (e.g. RAM key) so they + * can be re-loaded later via the SHE key update protocol. + * she - initialized SHE context with a registered callback + * m1 - output buffer for M1 (16 bytes), or NULL to skip + * m1Sz - size of m1 buffer + * m2 - output buffer for M2 (32 bytes), or NULL to skip + * m2Sz - size of m2 buffer + * m3 - output buffer for M3 (16 bytes), or NULL to skip + * m3Sz - size of m3 buffer + * m4 - output buffer for M4 (32 bytes), or NULL to skip + * m4Sz - size of m4 buffer + * m5 - output buffer for M5 (16 bytes), or NULL to skip + * m5Sz - size of m5 buffer + * ctx - read-only caller context passed to the callback */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_EXPORTKEY) WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she, byte* m1, word32 m1Sz, @@ -213,7 +327,14 @@ WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she, const void* ctx); #endif -/* Internal: Miyaguchi-Preneel AES-128 compression, exposed for testing */ +/* Internal: Miyaguchi-Preneel AES-128 one-way compression. + * H_0 = 0, H_i = E_{H_{i-1}}(M_i) XOR M_i XOR H_{i-1}. + * Only valid for AES-128 where key size equals block size. + * Exposed via WOLFSSL_TEST_VIS for testing. + * aes - caller-owned, already-initialized Aes structure + * in - input data (e.g. BaseKey || KDF_Constant, 32 bytes) + * inSz - length of input in bytes (zero-padded to block boundary) + * out - output buffer for 16-byte compressed result */ WOLFSSL_TEST_VIS int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out); From ba9cf0d43f28ba508ee12988c5f7c5c3330a7513 Mon Sep 17 00:00:00 2001 From: night1rider Date: Tue, 24 Mar 2026 11:19:50 -0600 Subject: [PATCH 05/12] Address comments from bigbrett and Fenrir bot. Rename she.{c,h} to wc_she.{c,h}, fix naming consistency, auto-enable CMAC/AES dependencies, add WC_SHE_SW_DEFAULT opt-inAddress PR #10009 review comments from bigbrett and Fenrir --- .github/workflows/os-check.yml | 4 + .wolfssl_known_macro_extras | 17 ++- configure.ac | 4 +- src/include.am | 8 +- tests/api/test_she.c | 18 +-- tests/api/test_she.h | 4 +- wolfcrypt/src/cryptocb.c | 4 +- wolfcrypt/src/{she.c => wc_she.c} | 133 +++++++++++++++---- wolfcrypt/test/test.c | 182 +++++++++++++++++++++++++- wolfssl/wolfcrypt/cryptocb.h | 4 +- wolfssl/wolfcrypt/include.am | 2 +- wolfssl/wolfcrypt/{she.h => wc_she.h} | 42 +++--- 12 files changed, 343 insertions(+), 79 deletions(-) rename wolfcrypt/src/{she.c => wc_she.c} (85%) rename wolfssl/wolfcrypt/{she.h => wc_she.h} (89%) diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 01f775152cb..284c083e43b 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -42,11 +42,15 @@ jobs: '--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation --enable-psk --enable-aesccm --enable-nullcipher CPPFLAGS=-DWOLFSSL_STATIC_RSA', + '--enable-she=extended --enable-cryptocb --enable-cryptocbutils + CPPFLAGS=''-DWC_SHE_SW_DEFAULT'' ', '--enable-she=standard --enable-cmac', '--enable-she=extended --enable-cmac --enable-cryptocb --enable-cryptocbutils', '--enable-she=standard --enable-cmac CPPFLAGS=''-DNO_WC_SHE_IMPORT_M123'' ', '--enable-she=extended --enable-cmac --enable-cryptocb --enable-cryptocbutils CPPFLAGS=''-DNO_WC_SHE_GETUID -DNO_WC_SHE_GETCOUNTER -DNO_WC_SHE_EXPORTKEY'' ', + '--enable-she=standard --enable-cmac --enable-cryptocb --enable-cryptocbutils + CPPFLAGS=''-DWC_SHE_SW_DEFAULT'' ', '--enable-all CPPFLAGS=''-DNO_AES_192 -DNO_AES_256'' ', '--enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CPPFLAGS=-DWOLFSSL_DH_EXTRA', diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index b447ec84e9c..099591a7a9b 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -659,6 +659,22 @@ WC_RSA_NONBLOCK WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE +<<<<<<< HEAD +======= +WC_SHA384 +WC_SHA384_DIGEST_SIZE +WC_SHA512 +WC_SHE_DEFAULT_COUNTER +WC_SHE_DEFAULT_UID +WC_SHE_SW_DEFAULT +WC_SHE_SW_TEST_AUTH_KEY +WC_SHE_SW_TEST_EXP_M1 +WC_SHE_SW_TEST_EXP_M2 +WC_SHE_SW_TEST_EXP_M3 +WC_SHE_SW_TEST_EXP_M4 +WC_SHE_SW_TEST_EXP_M5 +WC_SHE_SW_TEST_NEW_KEY +>>>>>>> 68515713f0 (Address comments from bigbrett and Fenrir bot. Rename she.{c,h} to wc_she.{c,h}, fix naming consistency, auto-enable CMAC/AES dependencies, add WC_SHE_SW_DEFAULT opt-inAddress PR #10009 review comments from bigbrett and Fenrir) WC_SKIP_INCLUDED_C_FILES WC_SSIZE_TYPE WC_STRICT_SIG @@ -887,7 +903,6 @@ WOLFSSL_SE050_NO_TRNG WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT WOLFSSL_SERVER_EXAMPLE WOLFSSL_SETTINGS_FILE -WOLFSSL_SH224 WOLFSSL_SHE WOLFSSL_SHE_EXTENDED WOLFSSL_SHA256_ALT_CH_MAJ diff --git a/configure.ac b/configure.ac index 17422d936bc..a8ea79f22eb 100644 --- a/configure.ac +++ b/configure.ac @@ -5956,7 +5956,9 @@ AC_ARG_ENABLE([she], if test "x$ENABLED_SHE" = "xstandard" || test "x$ENABLED_SHE" = "xextended" then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT" + ENABLED_CMAC=yes + ENABLED_AESCBC=yes fi if test "x$ENABLED_SHE" = "xextended" diff --git a/src/include.am b/src/include.am index 864261c39c8..5e8515487e7 100644 --- a/src/include.am +++ b/src/include.am @@ -160,7 +160,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif if BUILD_SHE -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_she.c endif src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ @@ -429,7 +429,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif if BUILD_SHE -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_she.c endif src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ @@ -682,7 +682,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif if BUILD_SHE -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_she.c endif if BUILD_CURVE448 @@ -1019,7 +1019,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c endif if BUILD_SHE -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_she.c endif endif !BUILD_FIPS_V2_PLUS diff --git a/tests/api/test_she.c b/tests/api/test_she.c index 2fc226111aa..ab29ec03c9f 100644 --- a/tests/api/test_she.c +++ b/tests/api/test_she.c @@ -28,7 +28,7 @@ #include #endif -#include +#include #include #ifdef WOLF_CRYPTO_CB #include @@ -169,7 +169,7 @@ int test_wc_SHE_ImportM1M2M3(void) return EXPECT_RESULT(); } -int test_wc_She_AesMp16(void) +int test_wc_SHE_AesMp16(void) { EXPECT_DECLS; #if defined(WOLFSSL_SHE) && !defined(NO_AES) @@ -188,18 +188,18 @@ int test_wc_She_AesMp16(void) }; ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), out), 0); + ExpectIntEQ(wc_SHE_AesMp16(&aes, input, sizeof(input), out), 0); ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_She_AesMp16(&aes, shortInput, sizeof(shortInput), out), 0); + ExpectIntEQ(wc_SHE_AesMp16(&aes, shortInput, sizeof(shortInput), out), 0); - ExpectIntEQ(wc_She_AesMp16(NULL, input, sizeof(input), out), + ExpectIntEQ(wc_SHE_AesMp16(NULL, input, sizeof(input), out), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_She_AesMp16(&aes, NULL, sizeof(input), out), + ExpectIntEQ(wc_SHE_AesMp16(&aes, NULL, sizeof(input), out), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_She_AesMp16(&aes, input, 0, out), + ExpectIntEQ(wc_SHE_AesMp16(&aes, input, 0, out), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), NULL), + ExpectIntEQ(wc_SHE_AesMp16(&aes, input, sizeof(input), NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_AesFree(&aes); @@ -467,7 +467,7 @@ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) she->devId = INVALID_DEVID; switch (info->she.type) { - case WC_SHE_SET_UID: + case WC_SHE_GET_UID: ret = 0; break; case WC_SHE_GET_COUNTER: diff --git a/tests/api/test_she.h b/tests/api/test_she.h index 79395d6e681..c1df2266d6b 100644 --- a/tests/api/test_she.h +++ b/tests/api/test_she.h @@ -29,7 +29,7 @@ int test_wc_SHE_Init_Id(void); int test_wc_SHE_Init_Label(void); int test_wc_SHE_Free(void); int test_wc_SHE_ImportM1M2M3(void); -int test_wc_She_AesMp16(void); +int test_wc_SHE_AesMp16(void); int test_wc_SHE_GenerateM1M2M3(void); int test_wc_SHE_GenerateM4M5(void); #ifdef WOLFSSL_SHE_EXTENDED @@ -46,7 +46,7 @@ int test_wc_SHE_CryptoCb(void); TEST_DECL_GROUP("she", test_wc_SHE_Init_Label), \ TEST_DECL_GROUP("she", test_wc_SHE_Free), \ TEST_DECL_GROUP("she", test_wc_SHE_ImportM1M2M3), \ - TEST_DECL_GROUP("she", test_wc_She_AesMp16), \ + TEST_DECL_GROUP("she", test_wc_SHE_AesMp16), \ TEST_DECL_GROUP("she", test_wc_SHE_GenerateM1M2M3), \ TEST_DECL_GROUP("she", test_wc_SHE_GenerateM4M5) diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 3dfa947ab15..cb06ece4c73 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -2036,7 +2036,7 @@ int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, #endif /* WOLFSSL_CMAC */ #ifdef WOLFSSL_SHE -int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, word32 uidSz, +int wc_CryptoCb_SheGetUid(wc_SHE* she, const byte* uid, word32 uidSz, const void* ctx) { int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); @@ -2053,7 +2053,7 @@ int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, word32 uidSz, XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); cryptoInfo.algo_type = WC_ALGO_TYPE_SHE; cryptoInfo.she.she = she; - cryptoInfo.she.type = WC_SHE_SET_UID; + cryptoInfo.she.type = WC_SHE_GET_UID; cryptoInfo.she.ctx = ctx; cryptoInfo.she.op.setUid.uid = uid; cryptoInfo.she.op.setUid.uidSz = uidSz; diff --git a/wolfcrypt/src/she.c b/wolfcrypt/src/wc_she.c similarity index 85% rename from wolfcrypt/src/she.c rename to wolfcrypt/src/wc_she.c index df44113bb4f..777856107e6 100644 --- a/wolfcrypt/src/she.c +++ b/wolfcrypt/src/wc_she.c @@ -1,4 +1,4 @@ -/* she.c +/* wc_she.c * * Copyright (C) 2006-2026 wolfSSL Inc. * @@ -31,6 +31,19 @@ #ifdef WOLFSSL_SHE +#ifdef NO_AES + #error "SHE requires AES (NO_AES is defined)" +#endif +#ifndef HAVE_AES_CBC + #error "SHE requires AES-CBC (HAVE_AES_CBC is not defined)" +#endif +#ifndef WOLFSSL_AES_DIRECT + #error "SHE requires AES direct (WOLFSSL_AES_DIRECT is not defined)" +#endif +#ifndef WOLFSSL_CMAC + #error "SHE requires CMAC (WOLFSSL_CMAC is not defined)" +#endif + #ifdef NO_INLINE #include #else @@ -40,12 +53,32 @@ #include #include -#include +#include #include #ifdef WOLF_CRYPTO_CB #include #endif +#ifdef WC_SHE_SW_DEFAULT +/* Software-only default UID for example usage only. Uses the SHE specification + * test vector UID value. Override by defining WC_SHE_DEFAULT_UID before + * including this file. */ +#ifndef WC_SHE_DEFAULT_UID +#define WC_SHE_DEFAULT_UID { \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 \ +} +#endif +static const byte wc_She_DefaultUid[] = WC_SHE_DEFAULT_UID; + +/* Software-only default counter start value for testing. Uses the SHE + * specification test vector counter value. Override by defining + * WC_SHE_DEFAULT_COUNTER before including this file. */ +#ifndef WC_SHE_DEFAULT_COUNTER +#define WC_SHE_DEFAULT_COUNTER 1 +#endif +#endif /* WC_SHE_SW_DEFAULT */ + /* -------------------------------------------------------------------------- */ /* Miyaguchi-Preneel AES-128 compression (internal) */ /* */ @@ -57,7 +90,7 @@ /* Ported from wolfHSM wh_She_AesMp16_ex() in src/wh_she_crypto.c. */ /* The caller (GenerateM1M2M3 / GenerateM4M5) owns the Aes object. */ /* -------------------------------------------------------------------------- */ -int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out) +int wc_SHE_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out) { int ret; int i = 0; @@ -123,7 +156,6 @@ int wc_SHE_Init(wc_SHE* she, void* heap, int devId) ForceZero(she, sizeof(wc_SHE)); she->heap = heap; she->devId = devId; - /* kdfEncOverride/kdfMacOverride are zero from XMEMSET -- defaults used */ return 0; } @@ -141,19 +173,19 @@ int wc_SHE_Init_Id(wc_SHE* she, unsigned char* id, int len, { int ret; - if (she == NULL) { + if (she == NULL || id == NULL) { return BAD_FUNC_ARG; } + if (len < 0 || len > WC_SHE_MAX_ID_LEN) { + return BUFFER_E; + } + ret = wc_SHE_Init(she, heap, devId); if (ret != 0) { return ret; } - if (len < 0 || len > WC_SHE_MAX_ID_LEN) { - return BUFFER_E; - } - XMEMCPY(she->id, id, (size_t)len); she->idLen = len; she->labelLen = 0; @@ -222,38 +254,74 @@ void wc_SHE_Free(wc_SHE* she) } /* -------------------------------------------------------------------------- */ -/* GetUID -- callback required */ +/* GetUID */ /* */ -/* Dispatches to callback to fetch UID from hardware. */ -/* Buffer size validation is the callback's responsibility. */ +/* When a crypto callback is registered, it can be used to get the UID from */ +/* hardware. The caller can pass a challenge or other context via the void */ +/* ctx parameter (e.g. challenge buffer, HSM handle). */ /* Returns CRYPTOCB_UNAVAILABLE if no callback. */ /* -------------------------------------------------------------------------- */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETUID) int wc_SHE_GetUID(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx) { + int ret; + if (she == NULL || uid == NULL) { return BAD_FUNC_ARG; } - return wc_CryptoCb_SheSetUid(she, uid, uidSz, ctx); + ret = wc_CryptoCb_SheGetUid(she, uid, uidSz, ctx); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + +#ifdef WC_SHE_SW_DEFAULT + /* Software-only default UID for example usage only. */ + if (uidSz < sizeof(wc_She_DefaultUid)) { + return BUFFER_E; + } + XMEMCPY(uid, wc_She_DefaultUid, sizeof(wc_She_DefaultUid)); + ret = 0; +#endif + + return ret; } #endif /* WOLF_CRYPTO_CB && !NO_WC_SHE_GETUID */ /* -------------------------------------------------------------------------- */ -/* GetCounter -- callback required */ +/* GetCounter */ /* */ -/* Dispatches to callback to read current counter from hardware. */ +/* When a crypto callback is registered, it can be used to read the */ +/* monotonic counter from hardware. The caller can pass operational context */ +/* via the void ctx parameter (e.g. read counter/increment, read only). */ /* Returns CRYPTOCB_UNAVAILABLE if no callback. */ /* -------------------------------------------------------------------------- */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETCOUNTER) int wc_SHE_GetCounter(wc_SHE* she, word32* counter, const void* ctx) { + int ret; +#ifdef WC_SHE_SW_DEFAULT + /* Software-only default counter for example usage only. + * Simple static counter that increments on each call. */ + static word32 she_sw_counter = WC_SHE_DEFAULT_COUNTER; +#endif + if (she == NULL || counter == NULL) { return BAD_FUNC_ARG; } - return wc_CryptoCb_SheGetCounter(she, counter, ctx); + ret = wc_CryptoCb_SheGetCounter(she, counter, ctx); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + +#ifdef WC_SHE_SW_DEFAULT + *counter = she_sw_counter++; + ret = 0; +#endif + + return ret; } #endif /* WOLF_CRYPTO_CB && !NO_WC_SHE_GETCOUNTER */ @@ -402,6 +470,12 @@ int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz) /* M2 = AES-CBC(K1, IV=0, counter|flags|pad|newkey) */ /* M3 = AES-CMAC(K2, M1 | M2) */ /* */ +/* When a crypto callback is registered and the SHE context has a valid */ +/* device ID, the callback is tried first. This is useful when a secure */ +/* element or HSM holds the auth key internally and can generate M1/M2/M3 */ +/* directly. If the callback returns CRYPTOCB_UNAVAILABLE, the software */ +/* path runs. */ +/* */ /* Ported from wolfHSM wh_She_GenerateLoadableKey() in wh_she_crypto.c. */ /* -------------------------------------------------------------------------- */ int wc_SHE_GenerateM1M2M3(wc_SHE* she, @@ -493,7 +567,7 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, /* ---- Derive K1 = AES-MP(AuthKey || CENC) ---- */ XMEMCPY(kdfInput, authKey, WC_SHE_KEY_SZ); XMEMCPY(kdfInput + WC_SHE_KEY_SZ, encC, WC_SHE_KEY_SZ); - ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k1); + ret = wc_SHE_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k1); /* ---- Build M1: UID(15B) | TargetKeyID(4b) | AuthKeyID(4b) ---- */ if (ret == 0) { @@ -519,7 +593,7 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, /* ---- Derive K2 = AES-MP(AuthKey || CMAC_C) ---- */ if (ret == 0) { XMEMCPY(kdfInput + WC_SHE_KEY_SZ, macC, WC_SHE_KEY_SZ); - ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k2); + ret = wc_SHE_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k2); } /* ---- Build M3 = AES-CMAC(K2, M1 || M2) ---- */ @@ -557,6 +631,11 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, /* M5 = AES-CMAC(K4, M4) */ /* */ /* These are the expected proof messages that SHE hardware should return. */ +/* */ +/* When a crypto callback is registered and the SHE context has a valid */ +/* device ID, the callback is tried first. This is useful for uploading */ +/* M1/M2/M3 to an HSM which loads the key and returns M4/M5 as proof. */ +/* If the callback returns CRYPTOCB_UNAVAILABLE, the software path runs. */ /* -------------------------------------------------------------------------- */ int wc_SHE_GenerateM4M5(wc_SHE* she, const byte* uid, word32 uidSz, @@ -596,6 +675,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, return ret; } /* fall-through to software path */ + ret = 0; } #endif @@ -642,7 +722,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, /* ---- Derive K3 = AES-MP(NewKey || CENC) ---- */ XMEMCPY(kdfInput, newKey, WC_SHE_KEY_SZ); XMEMCPY(kdfInput + WC_SHE_KEY_SZ, encC, WC_SHE_KEY_SZ); - ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k3); + ret = wc_SHE_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k3); /* ---- Build M4: UID|IDs header + AES-ECB(K3, m4pHeader) ---- */ if (ret == 0) { @@ -669,7 +749,7 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, /* ---- Derive K4 = AES-MP(NewKey || CMAC_C) ---- */ if (ret == 0) { XMEMCPY(kdfInput + WC_SHE_KEY_SZ, macC, WC_SHE_KEY_SZ); - ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k4); + ret = wc_SHE_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k4); } /* ---- Build M5 = AES-CMAC(K4, M4) ---- */ @@ -691,19 +771,14 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, } /* -------------------------------------------------------------------------- */ -/* Export Key (callback optional) */ +/* Export Key */ /* */ -/* Software: copies computed messages from context into caller buffers. */ +/* When a crypto callback is registered, it can be used to export M1-M5 */ +/* from a key slot on an HSM, allowing the key to be re-loaded later via */ +/* the SHE key update protocol. */ /* Any pointer may be NULL to skip that message. */ -/* M1/M2/M3 require generated state, M4/M5 require verified state. */ -/* Callback: asks hardware to export the key as M1-M5. */ /* -------------------------------------------------------------------------- */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_EXPORTKEY) -/* -------------------------------------------------------------------------- */ -/* Export Key -- callback required */ -/* */ -/* Asks hardware to export a key slot as M1-M5 in SHE loadable format. */ -/* -------------------------------------------------------------------------- */ int wc_SHE_ExportKey(wc_SHE* she, byte* m1, word32 m1Sz, byte* m2, word32 m2Sz, diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 7c4a42d15d9..60065dcfdc3 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -349,7 +349,7 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #include #include #ifdef WOLFSSL_SHE - #include + #include #endif #include #include @@ -56153,6 +56153,176 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cmac_test(void) #if defined(WOLFSSL_SHE) && !defined(NO_AES) +#if defined(WC_SHE_SW_DEFAULT) && defined(WOLF_CRYPTO_CB) && \ + !defined(NO_WC_SHE_GETUID) && !defined(NO_WC_SHE_GETCOUNTER) + +#ifndef WC_SHE_SW_TEST_AUTH_KEY +#define WC_SHE_SW_TEST_AUTH_KEY { \ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \ +} +#endif + +#ifndef WC_SHE_SW_TEST_NEW_KEY +#define WC_SHE_SW_TEST_NEW_KEY { \ + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, \ + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 \ +} +#endif + +#ifndef WC_SHE_SW_TEST_EXP_M1 +#define WC_SHE_SW_TEST_EXP_M1 { \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41 \ +} +#endif + +#ifndef WC_SHE_SW_TEST_EXP_M2 +#define WC_SHE_SW_TEST_EXP_M2 { \ + 0x2b, 0x11, 0x1e, 0x2d, 0x93, 0xf4, 0x86, 0x56, \ + 0x6b, 0xcb, 0xba, 0x1d, 0x7f, 0x7a, 0x97, 0x97, \ + 0xc9, 0x46, 0x43, 0xb0, 0x50, 0xfc, 0x5d, 0x4d, \ + 0x7d, 0xe1, 0x4c, 0xff, 0x68, 0x22, 0x03, 0xc3 \ +} +#endif + +#ifndef WC_SHE_SW_TEST_EXP_M3 +#define WC_SHE_SW_TEST_EXP_M3 { \ + 0xb9, 0xd7, 0x45, 0xe5, 0xac, 0xe7, 0xd4, 0x18, \ + 0x60, 0xbc, 0x63, 0xc2, 0xb9, 0xf5, 0xbb, 0x46 \ +} +#endif + +#ifndef WC_SHE_SW_TEST_EXP_M4 +#define WC_SHE_SW_TEST_EXP_M4 { \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, \ + 0xb4, 0x72, 0xe8, 0xd8, 0x72, 0x7d, 0x70, 0xd5, \ + 0x72, 0x95, 0xe7, 0x48, 0x49, 0xa2, 0x79, 0x17 \ +} +#endif + +#ifndef WC_SHE_SW_TEST_EXP_M5 +#define WC_SHE_SW_TEST_EXP_M5 { \ + 0x82, 0x0d, 0x8d, 0x95, 0xdc, 0x11, 0xb4, 0x66, \ + 0x88, 0x78, 0x16, 0x0c, 0xb2, 0xa4, 0xe2, 0x3e \ +} +#endif + +/* Software-only SHE test using the full GetUID -> GetCounter -> GenerateM1M2M3 + * -> GenerateM4M5 API flow. This test allows someone to test a custom vector + * by overriding the WC_SHE_SW_TEST_* and WC_SHE_DEFAULT_* macros, and + * demonstrates the whole SHE API in a software-only configuration. */ +static wc_test_ret_t she_sw_default_test(void) +{ + wc_test_ret_t ret = 0; + byte uid[WC_SHE_UID_SZ]; + word32 counter; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + WC_DECLARE_VAR(she, wc_SHE, 1, HEAP_HINT); + + WOLFSSL_SMALL_STACK_STATIC const byte authKey[] = WC_SHE_SW_TEST_AUTH_KEY; + WOLFSSL_SMALL_STACK_STATIC const byte newKey[] = WC_SHE_SW_TEST_NEW_KEY; + WOLFSSL_SMALL_STACK_STATIC const byte expM1[] = WC_SHE_SW_TEST_EXP_M1; + WOLFSSL_SMALL_STACK_STATIC const byte expM2[] = WC_SHE_SW_TEST_EXP_M2; + WOLFSSL_SMALL_STACK_STATIC const byte expM3[] = WC_SHE_SW_TEST_EXP_M3; + WOLFSSL_SMALL_STACK_STATIC const byte expM4[] = WC_SHE_SW_TEST_EXP_M4; + WOLFSSL_SMALL_STACK_STATIC const byte expM5[] = WC_SHE_SW_TEST_EXP_M5; + + WOLFSSL_ENTER("she_sw_default_test"); + + WC_ALLOC_VAR(she, wc_SHE, 1, HEAP_HINT); + if (!WC_VAR_OK(she)) { + return WC_TEST_RET_ENC_EC(MEMORY_E); + } + + /* Use INVALID_DEVID intentionally -- this test exercises the software-only + * path and should not use any hardware callbacks. */ + ret = wc_SHE_Init(she, HEAP_HINT, INVALID_DEVID); + if (ret != 0) { + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Get UID and counter from software defaults */ + ret = wc_SHE_GetUID(she, uid, WC_SHE_UID_SZ, NULL); + if (ret != 0) { + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + ret = wc_SHE_GetCounter(she, &counter, NULL); + if (ret != 0) { + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Generate M1/M2/M3 using retrieved UID and counter */ + ret = wc_SHE_GenerateM1M2M3(she, + uid, WC_SHE_UID_SZ, + WC_SHE_MASTER_ECU_KEY_ID, authKey, sizeof(authKey), + 4, newKey, sizeof(newKey), + counter, 0, + m1, WC_SHE_M1_SZ, + m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ); + if (ret != 0) { + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Verify M1/M2/M3 match expected values */ + if (XMEMCMP(m1, expM1, WC_SHE_M1_SZ) != 0 || + XMEMCMP(m2, expM2, WC_SHE_M2_SZ) != 0 || + XMEMCMP(m3, expM3, WC_SHE_M3_SZ) != 0) { + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_NC; + } + + /* Generate M4/M5 using same UID and counter */ + wc_SHE_Free(she); + ret = wc_SHE_Init(she, HEAP_HINT, INVALID_DEVID); + if (ret != 0) { + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + ret = wc_SHE_GenerateM4M5(she, + uid, WC_SHE_UID_SZ, + WC_SHE_MASTER_ECU_KEY_ID, 4, + newKey, sizeof(newKey), + counter, + m4, WC_SHE_M4_SZ, + m5, WC_SHE_M5_SZ); + if (ret != 0) { + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Verify M4/M5 match expected values */ + if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0 || + XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return WC_TEST_RET_ENC_NC; + } + + wc_SHE_Free(she); + WC_FREE_VAR(she, HEAP_HINT); + return ret; +} +#endif /* WC_SHE_SW_DEFAULT && WOLF_CRYPTO_CB && + * !NO_WC_SHE_GETUID && !NO_WC_SHE_GETCOUNTER */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) { wc_test_ret_t ret = 0; @@ -56428,6 +56598,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) goto exit_SHE_Test; } +#if defined(WC_SHE_SW_DEFAULT) && defined(WOLF_CRYPTO_CB) && \ + !defined(NO_WC_SHE_GETUID) && !defined(NO_WC_SHE_GETCOUNTER) + ret = she_sw_default_test(); + if (ret != 0) { + goto exit_SHE_Test; + } +#endif + exit_SHE_Test: wc_SHE_Free(she); WC_FREE_VAR(she, HEAP_HINT); @@ -66539,7 +66717,7 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) she->devId = INVALID_DEVID; switch (info->she.type) { - case WC_SHE_SET_UID: + case WC_SHE_GET_UID: /* Test callback: just acknowledge, UID is in caller's buffer */ ret = 0; break; diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index f9c04bb5f03..533877d04d5 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -66,7 +66,7 @@ #include #endif #ifdef WOLFSSL_SHE - #include + #include #endif #ifdef HAVE_ED25519 #include @@ -821,7 +821,7 @@ WOLFSSL_LOCAL int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, #endif #ifdef WOLFSSL_SHE -WOLFSSL_LOCAL int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, +WOLFSSL_LOCAL int wc_CryptoCb_SheGetUid(wc_SHE* she, const byte* uid, word32 uidSz, const void* ctx); WOLFSSL_LOCAL int wc_CryptoCb_SheGetCounter(wc_SHE* she, word32* counter, const void* ctx); diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 02e300de0cb..1c23469d206 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -10,7 +10,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/poly1305.h \ wolfssl/wolfcrypt/camellia.h \ wolfssl/wolfcrypt/cmac.h \ - wolfssl/wolfcrypt/she.h \ + wolfssl/wolfcrypt/wc_she.h \ wolfssl/wolfcrypt/coding.h \ wolfssl/wolfcrypt/compress.h \ wolfssl/wolfcrypt/des3.h \ diff --git a/wolfssl/wolfcrypt/she.h b/wolfssl/wolfcrypt/wc_she.h similarity index 89% rename from wolfssl/wolfcrypt/she.h rename to wolfssl/wolfcrypt/wc_she.h index ac1b9c4e344..9d3b501f451 100644 --- a/wolfssl/wolfcrypt/she.h +++ b/wolfssl/wolfcrypt/wc_she.h @@ -1,4 +1,4 @@ -/* she.h +/* wc_she.h * * Copyright (C) 2006-2026 wolfSSL Inc. * @@ -45,7 +45,7 @@ /* crypto callback sub-types for WC_ALGO_TYPE_SHE */ enum wc_SheType { - WC_SHE_SET_UID = 1, + WC_SHE_GET_UID = 1, WC_SHE_GET_COUNTER = 2, WC_SHE_GENERATE_M1M2M3 = 3, WC_SHE_GENERATE_M4M5 = 4, @@ -161,23 +161,22 @@ WOLFSSL_API int wc_SHE_Init_Label(wc_SHE* she, const char* label, /* Scrub all data and zero the context. Safe to call on NULL. */ WOLFSSL_API void wc_SHE_Free(wc_SHE* she); -/* Get UID from hardware via callback (WC_SHE_SET_UID). - * she - initialized SHE context with a registered callback +/* Get UID from hardware. + * she - initialized SHE context * uid - buffer to receive the 120-bit (15-byte) SHE UID * uidSz - size of uid buffer in bytes - * ctx - read-only caller context passed to the callback - * (e.g. challenge buffer, HSM handle) */ + * ctx - read-only caller context (e.g. challenge buffer, HSM handle) */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETUID) WOLFSSL_API int wc_SHE_GetUID(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx); #endif -/* Get monotonic counter from hardware via callback (WC_SHE_GET_COUNTER). - * she - initialized SHE context with a registered callback +/* Get monotonic counter from hardware. + * she - initialized SHE context * counter - pointer to receive the current counter value. * The SHE spec uses a 28-bit counter. The caller should * increment this value before passing to GenerateM1M2M3/M4M5. - * ctx - read-only caller context passed to the callback */ + * ctx - read-only caller context */ #if defined(WOLF_CRYPTO_CB) && !defined(NO_WC_SHE_GETCOUNTER) WOLFSSL_API int wc_SHE_GetCounter(wc_SHE* she, word32* counter, const void* ctx); @@ -236,10 +235,7 @@ WOLFSSL_API int wc_SHE_ImportM1M2M3(wc_SHE* she, #endif /* Generate M1/M2/M3 for the SHE key update protocol and write to - * caller-provided buffers. Callback optional -- if a callback is - * registered it is tried first; if it returns CRYPTOCB_UNAVAILABLE - * the software path runs. This allows a secure element to generate - * M1/M2/M3 when it holds the auth key internally. + * caller-provided buffers. * * she - initialized SHE context * uid - 15-byte SHE UID (120-bit ECU/module identifier) @@ -247,14 +243,12 @@ WOLFSSL_API int wc_SHE_ImportM1M2M3(wc_SHE* she, * authKeyId - slot ID of the authorizing key (0-14, e.g. * MASTER_ECU_KEY=1, KEY_1..KEY_10=4..13) * authKey - 16-byte value of the authorizing key. Used to derive - * K1 (encryption) and K2 (MAC). May be NULL when the - * callback handles key access. - * authKeySz - must be WC_SHE_KEY_SZ (16) when authKey is non-NULL + * K1 (encryption) and K2 (MAC). + * authKeySz - must be WC_SHE_KEY_SZ (16) * targetKeyId - slot ID of the key being loaded (1-14) * newKey - 16-byte value of the new key to load. Placed in M2 * cleartext and used to derive K3/K4 for M4/M5. - * May be NULL when the callback handles key access. - * newKeySz - must be WC_SHE_KEY_SZ (16) when newKey is non-NULL + * newKeySz - must be WC_SHE_KEY_SZ (16) * counter - 28-bit monotonic counter value. Must be strictly greater * than the counter stored in the target slot on the SHE. * flags - key protection flags (lower 4 bits of the counter|flags @@ -275,9 +269,7 @@ WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she, byte* m3, word32 m3Sz); /* Generate M4/M5 verification messages and write to caller-provided - * buffers. Independent of M1/M2/M3 -- can be called on a separate - * context. Callback optional -- useful for uploading M1/M2/M3 to an - * HSM which loads the key and returns M4/M5 as proof. + * buffers. Independent of M1/M2/M3, can be called on a separate context. * * she - initialized SHE context * uid - 15-byte SHE UID (same UID used for M1) @@ -286,8 +278,7 @@ WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she, * targetKeyId - slot ID of the key being loaded (same as in M1) * newKey - 16-byte value of the new key. Used to derive K3 * (encryption for M4 counter block) and K4 (MAC for M5). - * May be NULL when the callback handles key access. - * newKeySz - must be WC_SHE_KEY_SZ (16) when newKey is non-NULL + * newKeySz - must be WC_SHE_KEY_SZ (16) * counter - 28-bit monotonic counter (same value as in M2) * m4 - output buffer for M4 (32 bytes) * m4Sz - size of m4 buffer, must be >= WC_SHE_M4_SZ @@ -302,10 +293,9 @@ WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she, byte* m5, word32 m5Sz); /* Export a key from hardware in SHE loadable format (M1-M5). - * Callback required -- dispatches to WC_SHE_EXPORT_KEY. * Some HSMs allow exporting certain key slots (e.g. RAM key) so they * can be re-loaded later via the SHE key update protocol. - * she - initialized SHE context with a registered callback + * she - initialized SHE context * m1 - output buffer for M1 (16 bytes), or NULL to skip * m1Sz - size of m1 buffer * m2 - output buffer for M2 (32 bytes), or NULL to skip @@ -335,7 +325,7 @@ WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she, * in - input data (e.g. BaseKey || KDF_Constant, 32 bytes) * inSz - length of input in bytes (zero-padded to block boundary) * out - output buffer for 16-byte compressed result */ -WOLFSSL_TEST_VIS int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, +WOLFSSL_TEST_VIS int wc_SHE_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out); #ifdef __cplusplus From ce92fe5dc559b96aed5fc6e3dc2b8b635f6aff1d Mon Sep 17 00:00:00 2001 From: night1rider Date: Tue, 24 Mar 2026 12:53:13 -0600 Subject: [PATCH 06/12] update she union for callback to be getUid not setUid --- wolfcrypt/src/cryptocb.c | 4 ++-- wolfssl/wolfcrypt/cryptocb.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index cb06ece4c73..c72c5acd783 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -2055,8 +2055,8 @@ int wc_CryptoCb_SheGetUid(wc_SHE* she, const byte* uid, word32 uidSz, cryptoInfo.she.she = she; cryptoInfo.she.type = WC_SHE_GET_UID; cryptoInfo.she.ctx = ctx; - cryptoInfo.she.op.setUid.uid = uid; - cryptoInfo.she.op.setUid.uidSz = uidSz; + cryptoInfo.she.op.getUid.uid = uid; + cryptoInfo.she.op.getUid.uidSz = uidSz; ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); } diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 533877d04d5..3e1debad249 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -470,7 +470,7 @@ typedef struct wc_CryptoInfo { struct { const byte* uid; word32 uidSz; - } setUid; + } getUid; struct { word32* counter; } getCounter; From 9b0f4f75b1a1f51752eb12563904df480ec3a7f2 Mon Sep 17 00:00:00 2001 From: night1rider Date: Tue, 31 Mar 2026 14:24:46 -0600 Subject: [PATCH 07/12] Add one-shot SHE LoadKey and LoadKey Verify convenience APIs: wc_SHE_LoadKey, wc_SHE_LoadKey_Id, wc_SHE_LoadKey_Label and their verify counterparts --- wolfcrypt/src/wc_she.c | 314 +++++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/wc_she.h | 82 ++++++++++ 2 files changed, 396 insertions(+) diff --git a/wolfcrypt/src/wc_she.c b/wolfcrypt/src/wc_she.c index 777856107e6..74756c027b6 100644 --- a/wolfcrypt/src/wc_she.c +++ b/wolfcrypt/src/wc_she.c @@ -770,6 +770,320 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, return ret; } +/* -------------------------------------------------------------------------- */ +/* One-shot Load Key helpers */ +/* */ +/* Internal helper that does the actual work: imports M1/M2/M3 into the */ +/* already-initialized SHE context, calls GenerateM4M5 (which dispatches to */ +/* the crypto callback to send M1/M2/M3 to the HSM and receive M4/M5 back), */ +/* and frees the context. */ +/* -------------------------------------------------------------------------- */ +#ifndef NO_WC_SHE_LOADKEY +#if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) +static int wc_SHE_LoadKey_Internal(wc_SHE* she, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz) +{ + int ret; + + ret = wc_SHE_ImportM1M2M3(she, m1, m1Sz, m2, m2Sz, m3, m3Sz); + if (ret != 0) { + wc_SHE_Free(she); + return ret; + } + + /* GenerateM4M5 with NULL uid/newKey -- the callback reads M1/M2/M3 + * from the context and sends them to the HSM which returns M4/M5. */ + ret = wc_SHE_GenerateM4M5(she, NULL, 0, 0, 0, NULL, 0, 0, + m4, m4Sz, m5, m5Sz); + + wc_SHE_Free(she); + return ret; +} + +/* -------------------------------------------------------------------------- */ +/* wc_SHE_LoadKey */ +/* */ +/* One-shot: Init, ImportM1M2M3, GenerateM4M5 (via callback), Free. */ +/* Requires a valid devId (not INVALID_DEVID) since the operation dispatches */ +/* to a hardware crypto callback. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_LoadKey( + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz) +{ + int ret; + WC_DECLARE_VAR(she, wc_SHE, 1, heap); + + if (m1 == NULL || m2 == NULL || m3 == NULL || + m4 == NULL || m5 == NULL) { + return BAD_FUNC_ARG; + } + + if (devId == INVALID_DEVID) { + return BAD_FUNC_ARG; + } + + if (m1Sz != WC_SHE_M1_SZ || m2Sz != WC_SHE_M2_SZ || + m3Sz != WC_SHE_M3_SZ) { + return BAD_FUNC_ARG; + } + + if (m4Sz < WC_SHE_M4_SZ || m5Sz < WC_SHE_M5_SZ) { + return BAD_FUNC_ARG; + } + + WC_ALLOC_VAR(she, wc_SHE, 1, heap); + if (!WC_VAR_OK(she)) { + return MEMORY_E; + } + + ret = wc_SHE_Init(she, heap, devId); + if (ret != 0) { + WC_FREE_VAR(she, heap); + return ret; + } + + ret = wc_SHE_LoadKey_Internal(she, m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz); + WC_FREE_VAR(she, heap); + return ret; +} + +#ifdef WOLF_PRIVATE_KEY_ID +/* -------------------------------------------------------------------------- */ +/* wc_SHE_LoadKey_Id */ +/* */ +/* One-shot with opaque hardware key identifier. */ +/* Requires a valid devId (not INVALID_DEVID) since the operation dispatches */ +/* to a hardware crypto callback. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_LoadKey_Id( + unsigned char* id, int idLen, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz) +{ + int ret; + WC_DECLARE_VAR(she, wc_SHE, 1, heap); + + if (id == NULL || m1 == NULL || m2 == NULL || m3 == NULL || + m4 == NULL || m5 == NULL) { + return BAD_FUNC_ARG; + } + + if (devId == INVALID_DEVID) { + return BAD_FUNC_ARG; + } + + if (idLen < 0 || idLen > WC_SHE_MAX_ID_LEN) { + return BAD_FUNC_ARG; + } + + if (m1Sz != WC_SHE_M1_SZ || m2Sz != WC_SHE_M2_SZ || + m3Sz != WC_SHE_M3_SZ) { + return BAD_FUNC_ARG; + } + + if (m4Sz < WC_SHE_M4_SZ || m5Sz < WC_SHE_M5_SZ) { + return BAD_FUNC_ARG; + } + + WC_ALLOC_VAR(she, wc_SHE, 1, heap); + if (!WC_VAR_OK(she)) { + return MEMORY_E; + } + + ret = wc_SHE_Init_Id(she, id, idLen, heap, devId); + if (ret != 0) { + WC_FREE_VAR(she, heap); + return ret; + } + + ret = wc_SHE_LoadKey_Internal(she, m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz); + WC_FREE_VAR(she, heap); + return ret; +} + +/* -------------------------------------------------------------------------- */ +/* wc_SHE_LoadKey_Label */ +/* */ +/* One-shot with human-readable key label. */ +/* Requires a valid devId (not INVALID_DEVID) since the operation dispatches */ +/* to a hardware crypto callback. */ +/* -------------------------------------------------------------------------- */ +int wc_SHE_LoadKey_Label( + const char* label, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz) +{ + int ret; + WC_DECLARE_VAR(she, wc_SHE, 1, heap); + + if (label == NULL || m1 == NULL || m2 == NULL || m3 == NULL || + m4 == NULL || m5 == NULL) { + return BAD_FUNC_ARG; + } + + if (devId == INVALID_DEVID) { + return BAD_FUNC_ARG; + } + + if (XSTRLEN(label) == 0 || XSTRLEN(label) > WC_SHE_MAX_LABEL_LEN) { + return BAD_FUNC_ARG; + } + + if (m1Sz != WC_SHE_M1_SZ || m2Sz != WC_SHE_M2_SZ || + m3Sz != WC_SHE_M3_SZ) { + return BAD_FUNC_ARG; + } + + if (m4Sz < WC_SHE_M4_SZ || m5Sz < WC_SHE_M5_SZ) { + return BAD_FUNC_ARG; + } + + WC_ALLOC_VAR(she, wc_SHE, 1, heap); + if (!WC_VAR_OK(she)) { + return MEMORY_E; + } + + ret = wc_SHE_Init_Label(she, label, heap, devId); + if (ret != 0) { + WC_FREE_VAR(she, heap); + return ret; + } + + ret = wc_SHE_LoadKey_Internal(she, m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz); + WC_FREE_VAR(she, heap); + return ret; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* -------------------------------------------------------------------------- */ +/* One-shot Load Key with Verification */ +/* */ +/* Same as the LoadKey variants but also compares the M4/M5 returned by the */ +/* HSM against caller-provided expected values. Returns SIG_VERIFY_E on */ +/* mismatch. The actual M4/M5 from the HSM are still written to the output */ +/* buffers so the caller can inspect them on failure. */ +/* -------------------------------------------------------------------------- */ +static int wc_SHE_VerifyM4M5( + const byte* m4, word32 m4Sz, + const byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz) +{ + if (m4Expected == NULL || m5Expected == NULL) { + return BAD_FUNC_ARG; + } + + if (m4ExpectedSz != WC_SHE_M4_SZ || m5ExpectedSz != WC_SHE_M5_SZ || + m4Sz < WC_SHE_M4_SZ || m5Sz < WC_SHE_M5_SZ) { + return BAD_FUNC_ARG; + } + + if (ConstantCompare(m4, m4Expected, WC_SHE_M4_SZ) != 0 || + ConstantCompare(m5, m5Expected, WC_SHE_M5_SZ) != 0) { + return SIG_VERIFY_E; + } + + return 0; +} + +int wc_SHE_LoadKey_Verify( + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz) +{ + int ret; + + ret = wc_SHE_LoadKey(heap, devId, m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz); + if (ret != 0) { + return ret; + } + + return wc_SHE_VerifyM4M5(m4, m4Sz, m5, m5Sz, + m4Expected, m4ExpectedSz, + m5Expected, m5ExpectedSz); +} + +#ifdef WOLF_PRIVATE_KEY_ID +int wc_SHE_LoadKey_Verify_Id( + unsigned char* id, int idLen, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz) +{ + int ret; + + ret = wc_SHE_LoadKey_Id(id, idLen, heap, devId, + m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz); + if (ret != 0) { + return ret; + } + + return wc_SHE_VerifyM4M5(m4, m4Sz, m5, m5Sz, + m4Expected, m4ExpectedSz, + m5Expected, m5ExpectedSz); +} + +int wc_SHE_LoadKey_Verify_Label( + const char* label, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz) +{ + int ret; + + ret = wc_SHE_LoadKey_Label(label, heap, devId, + m1, m1Sz, m2, m2Sz, m3, m3Sz, + m4, m4Sz, m5, m5Sz); + if (ret != 0) { + return ret; + } + + return wc_SHE_VerifyM4M5(m4, m4Sz, m5, m5Sz, + m4Expected, m4ExpectedSz, + m5Expected, m5ExpectedSz); +} +#endif /* WOLF_PRIVATE_KEY_ID */ + +#endif /* WOLF_CRYPTO_CB || !NO_WC_SHE_IMPORT_M123 */ +#endif /* !NO_WC_SHE_LOADKEY */ + /* -------------------------------------------------------------------------- */ /* Export Key */ /* */ diff --git a/wolfssl/wolfcrypt/wc_she.h b/wolfssl/wolfcrypt/wc_she.h index 9d3b501f451..836959469c4 100644 --- a/wolfssl/wolfcrypt/wc_she.h +++ b/wolfssl/wolfcrypt/wc_she.h @@ -292,6 +292,88 @@ WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she, byte* m4, word32 m4Sz, byte* m5, word32 m5Sz); +/* One-shot Load Key: Init, ImportM1M2M3, GenerateM4M5 (via callback), Free. + * Requires a valid devId (not INVALID_DEVID) -- dispatches to a hardware + * crypto callback that sends M1/M2/M3 to the HSM and returns M4/M5. + * Define NO_WC_SHE_LOADKEY to compile out all LoadKey/Verify wrappers. + * heap - heap hint for internal allocations, or NULL + * devId - crypto callback device ID (must not be INVALID_DEVID) + * m1-m3 - input: externally-provided SHE key update messages + * m4,m5 - output: verification messages returned by the HSM */ +#ifndef NO_WC_SHE_LOADKEY +#if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) +WOLFSSL_API int wc_SHE_LoadKey( + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz); + +#ifdef WOLF_PRIVATE_KEY_ID +/* One-shot Load Key with opaque hardware key identifier. */ +WOLFSSL_API int wc_SHE_LoadKey_Id( + unsigned char* id, int idLen, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz); + +/* One-shot Load Key with human-readable key label. */ +WOLFSSL_API int wc_SHE_LoadKey_Label( + const char* label, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz); +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* One-shot Load Key with M4/M5 verification. + * Same as wc_SHE_LoadKey but also compares the M4/M5 returned by the HSM + * against caller-provided expected values. Returns SIG_VERIFY_E on mismatch. + * The actual M4/M5 are still written to the output buffers on failure. + * m4Expected, m5Expected - expected verification messages to compare against */ +WOLFSSL_API int wc_SHE_LoadKey_Verify( + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz); + +#ifdef WOLF_PRIVATE_KEY_ID +WOLFSSL_API int wc_SHE_LoadKey_Verify_Id( + unsigned char* id, int idLen, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz); + +WOLFSSL_API int wc_SHE_LoadKey_Verify_Label( + const char* label, + void* heap, int devId, + const byte* m1, word32 m1Sz, + const byte* m2, word32 m2Sz, + const byte* m3, word32 m3Sz, + byte* m4, word32 m4Sz, + byte* m5, word32 m5Sz, + const byte* m4Expected, word32 m4ExpectedSz, + const byte* m5Expected, word32 m5ExpectedSz); +#endif /* WOLF_PRIVATE_KEY_ID */ + +#endif /* WOLF_CRYPTO_CB || !NO_WC_SHE_IMPORT_M123 */ +#endif /* !NO_WC_SHE_LOADKEY */ + /* Export a key from hardware in SHE loadable format (M1-M5). * Some HSMs allow exporting certain key slots (e.g. RAM key) so they * can be re-loaded later via the SHE key update protocol. From 8a973e226489e0eccf403916c513b51380238386 Mon Sep 17 00:00:00 2001 From: night1rider Date: Fri, 3 Apr 2026 15:24:36 -0600 Subject: [PATCH 08/12] Add missing NO_WC_SHE_LOADKEY macro to known macros list --- .wolfssl_known_macro_extras | 3 --- 1 file changed, 3 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 099591a7a9b..735f9b05635 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -659,8 +659,6 @@ WC_RSA_NONBLOCK WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE -<<<<<<< HEAD -======= WC_SHA384 WC_SHA384_DIGEST_SIZE WC_SHA512 @@ -674,7 +672,6 @@ WC_SHE_SW_TEST_EXP_M3 WC_SHE_SW_TEST_EXP_M4 WC_SHE_SW_TEST_EXP_M5 WC_SHE_SW_TEST_NEW_KEY ->>>>>>> 68515713f0 (Address comments from bigbrett and Fenrir bot. Rename she.{c,h} to wc_she.{c,h}, fix naming consistency, auto-enable CMAC/AES dependencies, add WC_SHE_SW_DEFAULT opt-inAddress PR #10009 review comments from bigbrett and Fenrir) WC_SKIP_INCLUDED_C_FILES WC_SSIZE_TYPE WC_STRICT_SIG From 1d6af161876acdefa6ecaa6a675bc9c1f2a583f1 Mon Sep 17 00:00:00 2001 From: Zackery Backman Date: Wed, 8 Apr 2026 23:05:27 -0600 Subject: [PATCH 09/12] Fix .wolfssl_known_macro_extras: remove 19 unneeded macros, add NO_WC_SHE_LOADKEY, fix sort order --- .wolfssl_known_macro_extras | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 735f9b05635..fed00ed99ab 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -444,10 +444,7 @@ NO_TKERNEL_MEM_POOL NO_TLSX_PSKKEM_PLAIN_ANNOUNCE NO_VERIFY_OID NO_WC_DHGENERATEPUBLIC -NO_WC_SHE_EXPORTKEY -NO_WC_SHE_GETCOUNTER -NO_WC_SHE_GETUID -NO_WC_SHE_IMPORT_M123 +NO_WC_SHE_LOADKEY NO_WC_SSIZE_TYPE NO_WOLFSSL_ALLOC_ALIGN NO_WOLFSSL_AUTOSAR_CRYIF @@ -659,19 +656,6 @@ WC_RSA_NONBLOCK WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE -WC_SHA384 -WC_SHA384_DIGEST_SIZE -WC_SHA512 -WC_SHE_DEFAULT_COUNTER -WC_SHE_DEFAULT_UID -WC_SHE_SW_DEFAULT -WC_SHE_SW_TEST_AUTH_KEY -WC_SHE_SW_TEST_EXP_M1 -WC_SHE_SW_TEST_EXP_M2 -WC_SHE_SW_TEST_EXP_M3 -WC_SHE_SW_TEST_EXP_M4 -WC_SHE_SW_TEST_EXP_M5 -WC_SHE_SW_TEST_NEW_KEY WC_SKIP_INCLUDED_C_FILES WC_SSIZE_TYPE WC_STRICT_SIG @@ -900,8 +884,6 @@ WOLFSSL_SE050_NO_TRNG WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT WOLFSSL_SERVER_EXAMPLE WOLFSSL_SETTINGS_FILE -WOLFSSL_SHE -WOLFSSL_SHE_EXTENDED WOLFSSL_SHA256_ALT_CH_MAJ WOLFSSL_SHA512_HASHTYPE WOLFSSL_SHUTDOWNONCE From e6280cd4a3c8638b03a8cd81c3b2a4ef03339c37 Mon Sep 17 00:00:00 2001 From: night1rider Date: Thu, 9 Apr 2026 13:28:50 -0600 Subject: [PATCH 10/12] Fix CMake SHE deps, const-correctness in CryptoCb uid, stale comment, XSTRLEN double call, configure.ac AES-CBC guard, and add LoadKey/LoadKey_Verify test coverage --- CMakeLists.txt | 2 + configure.ac | 4 + tests/api/test_she.c | 154 ++++++++++++++++++++++++++++++++--- tests/api/test_she.h | 11 +++ wolfcrypt/src/cryptocb.c | 2 +- wolfcrypt/src/wc_she.c | 7 +- wolfcrypt/test/test.c | 29 +++++++ wolfssl/wolfcrypt/cryptocb.h | 4 +- 8 files changed, 194 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a21eb8d311e..504ee8b8820 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1652,6 +1652,8 @@ if(WOLFSSL_SHE STREQUAL "standard" OR WOLFSSL_SHE STREQUAL "extended") else() list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHE") + override_cache(WOLFSSL_CMAC "yes") + override_cache(WOLFSSL_AESCBC "yes") endif() endif() diff --git a/configure.ac b/configure.ac index a8ea79f22eb..f8b7f752347 100644 --- a/configure.ac +++ b/configure.ac @@ -5956,6 +5956,10 @@ AC_ARG_ENABLE([she], if test "x$ENABLED_SHE" = "xstandard" || test "x$ENABLED_SHE" = "xextended" then + if test "$ENABLED_AESCBC" = "no" + then + AC_MSG_ERROR([SHE requires AES-CBC. Cannot use --disable-aescbc with --enable-she.]) + fi AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT" ENABLED_CMAC=yes ENABLED_AESCBC=yes diff --git a/tests/api/test_she.c b/tests/api/test_she.c index ab29ec03c9f..84e4dacf579 100644 --- a/tests/api/test_she.c +++ b/tests/api/test_she.c @@ -499,18 +499,32 @@ static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->she.op.generateM1M2M3.m3Sz); break; case WC_SHE_GENERATE_M4M5: - ret = wc_SHE_GenerateM4M5(she, - info->she.op.generateM4M5.uid, - info->she.op.generateM4M5.uidSz, - info->she.op.generateM4M5.authKeyId, - info->she.op.generateM4M5.targetKeyId, - info->she.op.generateM4M5.newKey, - info->she.op.generateM4M5.newKeySz, - info->she.op.generateM4M5.counter, - info->she.op.generateM4M5.m4, - info->she.op.generateM4M5.m4Sz, - info->she.op.generateM4M5.m5, - info->she.op.generateM4M5.m5Sz); + if (info->she.op.generateM4M5.uid == NULL && + she->generated) { + /* LoadKey flow: M1/M2/M3 already imported, simulate HSM + * returning M4/M5 from known test vectors. */ + if (info->she.op.generateM4M5.m4 != NULL) + XMEMCPY(info->she.op.generateM4M5.m4, + sheTestExpM4, WC_SHE_M4_SZ); + if (info->she.op.generateM4M5.m5 != NULL) + XMEMCPY(info->she.op.generateM4M5.m5, + sheTestExpM5, WC_SHE_M5_SZ); + ret = 0; + } + else { + ret = wc_SHE_GenerateM4M5(she, + info->she.op.generateM4M5.uid, + info->she.op.generateM4M5.uidSz, + info->she.op.generateM4M5.authKeyId, + info->she.op.generateM4M5.targetKeyId, + info->she.op.generateM4M5.newKey, + info->she.op.generateM4M5.newKeySz, + info->she.op.generateM4M5.counter, + info->she.op.generateM4M5.m4, + info->she.op.generateM4M5.m4Sz, + info->she.op.generateM4M5.m5, + info->she.op.generateM4M5.m5Sz); + } break; case WC_SHE_EXPORT_KEY: /* Simulate hardware export -- fill with test pattern */ @@ -635,4 +649,120 @@ int test_wc_SHE_CryptoCb(void) return EXPECT_RESULT(); } +#ifndef NO_WC_SHE_LOADKEY + +int test_wc_SHE_LoadKey(void) +{ + EXPECT_DECLS; + int sheTestDevId = 54322; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(sheTestDevId, + test_she_crypto_cb, NULL), 0); + + /* Generate valid M1/M2/M3 from test vectors */ + { + wc_SHE she; + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, + sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ), 0); + wc_SHE_Free(&she); + } + + /* Basic: LoadKey should import M1/M2/M3 and produce M4/M5 via callback */ + ExpectIntEQ(wc_SHE_LoadKey(NULL, sheTestDevId, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), 0); + ExpectIntEQ(XMEMCMP(m4, sheTestExpM4, WC_SHE_M4_SZ), 0); + ExpectIntEQ(XMEMCMP(m5, sheTestExpM5, WC_SHE_M5_SZ), 0); + + /* Bad args: NULL m1 */ + ExpectIntEQ(wc_SHE_LoadKey(NULL, sheTestDevId, + NULL, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: NULL m4 output */ + ExpectIntEQ(wc_SHE_LoadKey(NULL, sheTestDevId, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ, + NULL, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: INVALID_DEVID */ + ExpectIntEQ(wc_SHE_LoadKey(NULL, INVALID_DEVID, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Bad args: wrong M1 size */ + ExpectIntEQ(wc_SHE_LoadKey(NULL, sheTestDevId, + m1, WC_SHE_M1_SZ - 1, m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_CryptoCb_UnRegisterDevice(sheTestDevId); + return EXPECT_RESULT(); +} + +int test_wc_SHE_LoadKey_Verify(void) +{ + EXPECT_DECLS; + int sheTestDevId = 54323; + byte m1[WC_SHE_M1_SZ]; + byte m2[WC_SHE_M2_SZ]; + byte m3[WC_SHE_M3_SZ]; + byte m4[WC_SHE_M4_SZ]; + byte m5[WC_SHE_M5_SZ]; + byte badM4[WC_SHE_M4_SZ]; + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(sheTestDevId, + test_she_crypto_cb, NULL), 0); + + /* Generate valid M1/M2/M3 from test vectors */ + { + wc_SHE she; + ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_MASTER_ECU_KEY_ID, + sheTestAuthKey, sizeof(sheTestAuthKey), + 4, sheTestNewKey, sizeof(sheTestNewKey), 1, 0, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, + m3, WC_SHE_M3_SZ), 0); + wc_SHE_Free(&she); + } + + /* Matching: expected M4/M5 match what the callback produces */ + ExpectIntEQ(wc_SHE_LoadKey_Verify(NULL, sheTestDevId, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ, + sheTestExpM4, WC_SHE_M4_SZ, + sheTestExpM5, WC_SHE_M5_SZ), 0); + + /* Mismatch: wrong expected M4 should fail with SIG_VERIFY_E */ + XMEMCPY(badM4, sheTestExpM4, WC_SHE_M4_SZ); + badM4[0] ^= 0xFF; + ExpectIntEQ(wc_SHE_LoadKey_Verify(NULL, sheTestDevId, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ, + badM4, WC_SHE_M4_SZ, + sheTestExpM5, WC_SHE_M5_SZ), + WC_NO_ERR_TRACE(SIG_VERIFY_E)); + + wc_CryptoCb_UnRegisterDevice(sheTestDevId); + return EXPECT_RESULT(); +} + +#endif /* !NO_WC_SHE_LOADKEY */ + #endif /* WOLF_CRYPTO_CB && WOLFSSL_SHE && !NO_AES */ diff --git a/tests/api/test_she.h b/tests/api/test_she.h index c1df2266d6b..feccb10e3e0 100644 --- a/tests/api/test_she.h +++ b/tests/api/test_she.h @@ -38,6 +38,10 @@ int test_wc_SHE_SetM2M4Header(void); #endif #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) int test_wc_SHE_CryptoCb(void); +#ifndef NO_WC_SHE_LOADKEY +int test_wc_SHE_LoadKey(void); +int test_wc_SHE_LoadKey_Verify(void); +#endif #endif #define TEST_SHE_DECLS \ @@ -59,8 +63,15 @@ int test_wc_SHE_CryptoCb(void); #endif #if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) +#if !defined(NO_WC_SHE_LOADKEY) +#define TEST_SHE_CB_DECLS \ + TEST_DECL_GROUP("she", test_wc_SHE_CryptoCb), \ + TEST_DECL_GROUP("she", test_wc_SHE_LoadKey), \ + TEST_DECL_GROUP("she", test_wc_SHE_LoadKey_Verify) +#else #define TEST_SHE_CB_DECLS \ TEST_DECL_GROUP("she", test_wc_SHE_CryptoCb) +#endif #else #define TEST_SHE_CB_DECLS #endif diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index c72c5acd783..f654ac44752 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -2036,7 +2036,7 @@ int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, #endif /* WOLFSSL_CMAC */ #ifdef WOLFSSL_SHE -int wc_CryptoCb_SheGetUid(wc_SHE* she, const byte* uid, word32 uidSz, +int wc_CryptoCb_SheGetUid(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx) { int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); diff --git a/wolfcrypt/src/wc_she.c b/wolfcrypt/src/wc_she.c index 74756c027b6..a2a260383c4 100644 --- a/wolfcrypt/src/wc_she.c +++ b/wolfcrypt/src/wc_she.c @@ -359,9 +359,6 @@ int wc_SHE_SetKdfConstants(wc_SHE* she, #endif /* WOLFSSL_SHE_EXTENDED */ -/* -------------------------------------------------------------------------- */ -/* GetUID */ - #if defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123) /* -------------------------------------------------------------------------- */ /* Import M1/M2/M3 */ @@ -933,6 +930,7 @@ int wc_SHE_LoadKey_Label( byte* m5, word32 m5Sz) { int ret; + word32 labelLen; WC_DECLARE_VAR(she, wc_SHE, 1, heap); if (label == NULL || m1 == NULL || m2 == NULL || m3 == NULL || @@ -944,7 +942,8 @@ int wc_SHE_LoadKey_Label( return BAD_FUNC_ARG; } - if (XSTRLEN(label) == 0 || XSTRLEN(label) > WC_SHE_MAX_LABEL_LEN) { + labelLen = (word32)XSTRLEN(label); + if (labelLen == 0 || labelLen > WC_SHE_MAX_LABEL_LEN) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 60065dcfdc3..f3ebaafa048 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -56598,6 +56598,35 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) goto exit_SHE_Test; } +#if !defined(NO_WC_SHE_LOADKEY) && \ + (defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123)) + /* ---- LoadKey_Verify ---- */ + XMEMSET(m4, 0, WC_SHE_M4_SZ); + XMEMSET(m5, 0, WC_SHE_M5_SZ); + ret = wc_SHE_LoadKey_Verify(HEAP_HINT, devId, + expM1, WC_SHE_M1_SZ, expM2, WC_SHE_M2_SZ, + expM3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ, + expM4, WC_SHE_M4_SZ, expM5, WC_SHE_M5_SZ); + if (devId == INVALID_DEVID) { + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + ret = WC_TEST_RET_ENC_EC(ret); + goto exit_SHE_Test; + } + } + else { + if (ret != 0) { + goto exit_SHE_Test; + } + if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0 || + XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) { + ret = WC_TEST_RET_ENC_NC; + goto exit_SHE_Test; + } + } + ret = 0; +#endif /* !NO_WC_SHE_LOADKEY */ + #if defined(WC_SHE_SW_DEFAULT) && defined(WOLF_CRYPTO_CB) && \ !defined(NO_WC_SHE_GETUID) && !defined(NO_WC_SHE_GETCOUNTER) ret = she_sw_default_test(); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 3e1debad249..0664f6cb457 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -468,7 +468,7 @@ typedef struct wc_CryptoInfo { const void* ctx; /* read-only caller context */ union { struct { - const byte* uid; + byte* uid; word32 uidSz; } getUid; struct { @@ -821,7 +821,7 @@ WOLFSSL_LOCAL int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz, #endif #ifdef WOLFSSL_SHE -WOLFSSL_LOCAL int wc_CryptoCb_SheGetUid(wc_SHE* she, const byte* uid, +WOLFSSL_LOCAL int wc_CryptoCb_SheGetUid(wc_SHE* she, byte* uid, word32 uidSz, const void* ctx); WOLFSSL_LOCAL int wc_CryptoCb_SheGetCounter(wc_SHE* she, word32* counter, const void* ctx); From 004f3ffe58f79cc119f6d5dd91ed1c202860ce98 Mon Sep 17 00:00:00 2001 From: night1rider Date: Thu, 9 Apr 2026 13:51:14 -0600 Subject: [PATCH 11/12] Fix CMake SHE build: add wc_she.c to sources, propagate CMAC/AES_DIRECT defines, --- CMakeLists.txt | 4 +++- cmake/functions.cmake | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 504ee8b8820..d4b4d696f1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1651,7 +1651,9 @@ if(WOLFSSL_SHE STREQUAL "standard" OR WOLFSSL_SHE STREQUAL "extended") message(FATAL_ERROR "Cannot use SHE without AES.") else() list(APPEND WOLFSSL_DEFINITIONS - "-DWOLFSSL_SHE") + "-DWOLFSSL_SHE" + "-DWOLFSSL_CMAC" + "-DWOLFSSL_AES_DIRECT") override_cache(WOLFSSL_CMAC "yes") override_cache(WOLFSSL_AESCBC "yes") endif() diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 009d5f95858..1a5442ddfd2 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -345,6 +345,9 @@ function(generate_build_flags) if(WOLFSSL_HPKE OR WOLFSSL_USER_SETTINGS) set(BUILD_HPKE "yes" PARENT_SCOPE) endif() + if(WOLFSSL_SHE AND NOT WOLFSSL_SHE STREQUAL "no") + set(BUILD_SHE "yes" PARENT_SCOPE) + endif() set(BUILD_FLAGS_GENERATED "yes" PARENT_SCOPE) endfunction() @@ -1150,6 +1153,10 @@ function(generate_lib_src_list LIB_SOURCES) list(APPEND LIB_SOURCES wolfcrypt/src/cryptocb.c) endif() + if(BUILD_SHE) + list(APPEND LIB_SOURCES wolfcrypt/src/wc_she.c) + endif() + if(BUILD_PKCS11) list(APPEND LIB_SOURCES wolfcrypt/src/wc_pkcs11.c) endif() From a30330cf8af411be8a45c4a5edff3d638d45d77d Mon Sep 17 00:00:00 2001 From: night1rider Date: Fri, 10 Apr 2026 15:10:34 -0600 Subject: [PATCH 12/12] Add ability to skip load key verify test --- wolfcrypt/test/test.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f3ebaafa048..015ea2b0646 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -56598,16 +56598,51 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) goto exit_SHE_Test; } -#if !defined(NO_WC_SHE_LOADKEY) && \ +#if !defined(NO_WC_SHE_LOADKEY) && !defined(NO_WC_SHE_LOADKEY_TEST) && \ (defined(WOLF_CRYPTO_CB) || !defined(NO_WC_SHE_IMPORT_M123)) /* ---- LoadKey_Verify ---- */ + /* Override WC_TEST_SHE_LOADKEY_VERIFY to use a platform-specific variant. + * Platforms with hardware SHE (HSM/HSE) cannot use static test vectors + * because the UID is device-specific. Options: + * + * Default (no override): calls wc_SHE_LoadKey_Verify (no id/label) + * + * WC_TEST_SHE_LOADKEY_ID: byte array for wc_SHE_LoadKey_Verify_Id + * e.g. #define WC_TEST_SHE_LOADKEY_ID { 1, 0, 2, 0, 0, 0, 0 } + * + * WC_TEST_SHE_LOADKEY_LABEL: string for wc_SHE_LoadKey_Verify_Label + * e.g. #define WC_TEST_SHE_LOADKEY_LABEL "she_key_1" + * + * Define NO_WC_SHE_LOADKEY_TEST to skip this sub-test entirely. + */ XMEMSET(m4, 0, WC_SHE_M4_SZ); XMEMSET(m5, 0, WC_SHE_M5_SZ); +#if defined(WOLF_PRIVATE_KEY_ID) && defined(WC_TEST_SHE_LOADKEY_ID) + { + unsigned char sheLoadkeyId[] = WC_TEST_SHE_LOADKEY_ID; + ret = wc_SHE_LoadKey_Verify_Id( + sheLoadkeyId, (int)sizeof(sheLoadkeyId), + HEAP_HINT, devId, + expM1, WC_SHE_M1_SZ, expM2, WC_SHE_M2_SZ, + expM3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ, + expM4, WC_SHE_M4_SZ, expM5, WC_SHE_M5_SZ); + } +#elif defined(WOLF_PRIVATE_KEY_ID) && defined(WC_TEST_SHE_LOADKEY_LABEL) + ret = wc_SHE_LoadKey_Verify_Label( + WC_TEST_SHE_LOADKEY_LABEL, + HEAP_HINT, devId, + expM1, WC_SHE_M1_SZ, expM2, WC_SHE_M2_SZ, + expM3, WC_SHE_M3_SZ, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ, + expM4, WC_SHE_M4_SZ, expM5, WC_SHE_M5_SZ); +#else ret = wc_SHE_LoadKey_Verify(HEAP_HINT, devId, expM1, WC_SHE_M1_SZ, expM2, WC_SHE_M2_SZ, expM3, WC_SHE_M3_SZ, m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ, expM4, WC_SHE_M4_SZ, expM5, WC_SHE_M5_SZ); +#endif if (devId == INVALID_DEVID) { if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { ret = WC_TEST_RET_ENC_EC(ret); @@ -56625,7 +56660,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) } } ret = 0; -#endif /* !NO_WC_SHE_LOADKEY */ +#endif /* !NO_WC_SHE_LOADKEY && !NO_WC_SHE_LOADKEY_TEST */ #if defined(WC_SHE_SW_DEFAULT) && defined(WOLF_CRYPTO_CB) && \ !defined(NO_WC_SHE_GETUID) && !defined(NO_WC_SHE_GETCOUNTER)