Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ AES
AES1
AES_CR_CCFC
AES_CR_CPHASE
AES_CR_GCMPH_Msk
AES_CR_NPBLB_Msk
AES_GCM_GMULT_NCT
AES_ICR_CCF
AES_ISR_CCF
Expand Down Expand Up @@ -1231,6 +1233,7 @@ __FreeBSD__
__GLIBC__
__GNUC_MINOR__
__GNUC__
__HAL_RCC_SAES_CLK_ENABLE
__HP_cc
__IAR_SYSTEMS_ICC__
__ICCARM__
Expand Down
5 changes: 4 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -3748,7 +3748,10 @@ then
AC_MSG_NOTICE([--enable-rtl8735b also enables AES-ECB build-wide (HAVE_AES_ECB)])
# WOLF_CRYPTO_CB_COPY/FREE: the HUK HMAC hangs its accumulation buffer on the
# inner SHA-256 devCtx and relies on the cryptocb copy/free ops (see the port).
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_RTL8735B_HUK -DWOLFSSL_RTL8735B_HOST_TEST -DHAVE_AES_ECB -DWOLF_CRYPTO_CB_COPY -DWOLF_CRYPTO_CB_FREE"
# WOLFSSL_RTL8735B_AES: the plaintext-key AES device (runs a caller key on the
# HW engine, no HUK binding); built alongside the HUK device so the compile
# test covers both, selectable at run time by devId.
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_RTL8735B_HUK -DWOLFSSL_RTL8735B_AES -DWOLFSSL_RTL8735B_HOST_TEST -DHAVE_AES_ECB -DWOLF_CRYPTO_CB_COPY -DWOLF_CRYPTO_CB_FREE"
fi


Expand Down
43 changes: 43 additions & 0 deletions doc/dox_comments/header_files/stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,54 @@ void wc_Stm32_DhukUnRegister(int devId);
\param iv optional 16-byte iv; NULL selects ECB, non-NULL selects CBC.
\param ivSz length of iv in bytes when iv is non-NULL; must be 16.

\sa wc_Stm32_Aes_Wrap_ex
\sa wc_Stm32_DhukRegister
*/
int wc_Stm32_Aes_Wrap(struct Aes* aes, const byte* in, word32 inSz, byte* out,
word32* outSz, const byte* iv, int ivSz);

/*!
\ingroup STM32

\brief This function is wc_Stm32_Aes_Wrap() with the blob word order given
explicitly. The two build paths have historically produced different word
orders, so wc_Stm32_Aes_Wrap() keeps each path's established default and
this entry point lets a caller choose. Available on STM32 builds with
WOLFSSL_DHUK and a DHUK-capable SAES.

Pass WC_STM32_WRAP_ORDER_RAW for new provisioning: it is one format that
both the CubeMX/HAL and bare-metal builds agree on, and the same format
wc_Stm32_Aes_DhukOp_ex() and the DHUK crypto-callback derive path consume,
so a blob wrapped on one build is usable on the other. Pass
WC_STM32_WRAP_ORDER_LEGACY to read or regenerate blobs provisioned by the
CubeMX HAL_CRYPEx_WrapKey implementation shipped in wolfSSL 5.9.0 - 5.9.2,
which byte-reversed its input and output.

\return 0 Returned on success.
\return BAD_FUNC_ARG Returned if a required pointer is NULL, if inSz is not a
supported block size, if the iv is non-NULL with ivSz != 16, or (software-key
path) if the wrapping key length is not 16 or 32.
\return <0 A negative error code may be returned on a hardware error.

\param aes pointer to an initialized Aes; aes->devId selects the wrap key.
\param in pointer to the input key bytes to wrap.
\param inSz length of in in bytes.
\param out pointer to the output buffer for the wrapped key.
\param outSz on input the size of out; on output the bytes written.
\param iv optional 16-byte iv; NULL selects ECB, non-NULL selects CBC.
\param ivSz length of iv in bytes when iv is non-NULL; must be 16.
\param rawOrder WC_STM32_WRAP_ORDER_RAW (1) for the shared blob format, or
WC_STM32_WRAP_ORDER_LEGACY (0) for the byte-reversed CubeMX format. Define
WC_STM32_WRAP_DEFAULT_RAW_ORDER before including the header to change what
plain wc_Stm32_Aes_Wrap() passes here.

\sa wc_Stm32_Aes_Wrap
\sa wc_Stm32_Aes_DhukOp_ex
\sa wc_Stm32_DhukRegister
*/
int wc_Stm32_Aes_Wrap_ex(struct Aes* aes, const byte* in, word32 inSz,
byte* out, word32* outSz, const byte* iv, int ivSz, int rawOrder);

/*!
\ingroup STM32

Expand Down
88 changes: 88 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -24191,6 +24191,92 @@ static int test_wc_EncryptPKCS8Key_rc4NoPad(void)
return EXPECT_RESULT();
}

/* Negative: PKCS5v2 with a valid encryption algorithm but an hmacOid that maps
* to no OID must return a clean ALGO_ID_E, not dereference a NULL OidFromId()
* result. Exercises the NULL guards added in wc_EncryptPKCS8Key_ex. */
static int test_wc_EncryptPKCS8Key_ex_badHmac(void)
Comment thread
dgarske marked this conversation as resolved.
{
EXPECT_DECLS;
#if defined(HAVE_PKCS8) && !defined(NO_ASN) && !defined(NO_PWDBASED) \
&& defined(WOLFSSL_AES_256) && !defined(NO_AES_CBC) && !defined(NO_ASN_CRYPT)
WC_RNG rng;
word32 outSz = 0;
/* At least HMAC_FIPS_MIN_KEY (14) bytes: a FIPS module older than v6.0.0
* rejects a shorter PBKDF2 password with HMAC_MIN_KEYLEN_E. */
const char password[] = "Lorem ipsum dolor sit amet";
byte plain[48];

XMEMSET(plain, 0, sizeof(plain));
plain[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
plain[1] = (byte)(sizeof(plain) - 2);
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
PRIVATE_KEY_UNLOCK();
/* out == NULL would normally return LENGTH_ONLY_E, but the hmacOid guard
* runs first, so a bogus hmacOid yields ALGO_ID_E cleanly (no crash). */
ExpectIntEQ(wc_EncryptPKCS8Key_ex(plain, (word32)sizeof(plain), NULL, &outSz,
password, (int)XSTRLEN(password), PKCS5, PBES2, AES256CBCb, NULL, 0,
WC_PKCS12_ITT_DEFAULT, 99999 /* hmacOid with no OID */, &rng, NULL),
WC_NO_ERR_TRACE(ALGO_ID_E));
PRIVATE_KEY_LOCK();
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}

/* Positive control for the guard above. The same call with a valid hmacOid
* must get past the hmacOid check and reach the normal length-query path
* (LENGTH_ONLY_E for out == NULL), proving the negative case really was
* rejected by the hmacOid guard and not by something earlier; then a full
* encrypt + wc_DecryptPKCS8Key round-trip recovers the input. */
static int test_wc_EncryptPKCS8Key_ex_goodHmac(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS8) && !defined(NO_ASN) && !defined(NO_PWDBASED) \
&& defined(WOLFSSL_AES_256) && !defined(NO_AES_CBC) && !defined(NO_ASN_CRYPT) \
&& !defined(NO_SHA256) && !defined(NO_HMAC)
WC_RNG rng;
word32 outSz = 0;
word32 encSz = 0;
/* At least HMAC_FIPS_MIN_KEY (14) bytes: a FIPS module older than v6.0.0
* rejects a shorter PBKDF2 password with HMAC_MIN_KEYLEN_E. */
const char password[] = "Lorem ipsum dolor sit amet";
byte plain[48];
byte* enc = NULL;

XMEMSET(plain, 0, sizeof(plain));
plain[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
plain[1] = (byte)(sizeof(plain) - 2);
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);

PRIVATE_KEY_UNLOCK();
/* Length query: a valid hmacOid must pass the guard and report a size. */
ExpectIntEQ(wc_EncryptPKCS8Key_ex(plain, (word32)sizeof(plain), NULL,
&outSz, password, (int)XSTRLEN(password), PKCS5, PBES2, AES256CBCb,
NULL, 0, WC_PKCS12_ITT_DEFAULT, HMAC_SHA256_OID, &rng, NULL),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntGT(outSz, 0);

ExpectNotNull(enc = (byte*)XMALLOC(outSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
if (enc != NULL) {
encSz = outSz;
ExpectIntGT(encSz = (word32)wc_EncryptPKCS8Key_ex(plain,
(word32)sizeof(plain), enc, &encSz, password,
(int)XSTRLEN(password), PKCS5, PBES2, AES256CBCb, NULL, 0,
WC_PKCS12_ITT_DEFAULT, HMAC_SHA256_OID, &rng, NULL), 0);
/* Round-trip: decrypt in place and recover the original DER. */
ExpectIntGE(wc_DecryptPKCS8Key(enc, encSz, password,
(int)XSTRLEN(password)), (int)sizeof(plain));
ExpectBufEQ(enc, plain, sizeof(plain));
XFREE(enc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
PRIVATE_KEY_LOCK();
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}

static int test_wc_DecryptedPKCS8Key(void)
{
EXPECT_DECLS;
Expand Down Expand Up @@ -39117,6 +39203,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wc_EncryptPKCS8Key_blockAligned),
TEST_DECL(test_wc_EncryptPKCS8Key_pbes1BlockAligned),
TEST_DECL(test_wc_EncryptPKCS8Key_rc4NoPad),
TEST_DECL(test_wc_EncryptPKCS8Key_ex_badHmac),
TEST_DECL(test_wc_EncryptPKCS8Key_ex_goodHmac),
TEST_DECL(test_wc_DecryptedPKCS8Key),
TEST_DECL(test_wc_GetPkcs8TraditionalOffset),

Expand Down
36 changes: 29 additions & 7 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -10740,7 +10740,9 @@ int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
#ifdef STM32_CRYPTO_AES_GCM

/* this function supports inline encrypt */
static WARN_UNUSED_RESULT int wc_AesGcmEncrypt_STM32(
/* Not static: the CubeMX crypto-callback device (port/st/stm32.c) calls this to
* service AES-GCM in-callback on the HAL engine. */
WOLFSSL_LOCAL WARN_UNUSED_RESULT int wc_AesGcmEncrypt_STM32(
Aes* aes, byte* out, const byte* in, word32 sz,
const byte* iv, word32 ivSz,
byte* authTag, word32 authTagSz,
Expand Down Expand Up @@ -11354,14 +11356,18 @@ int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
}
#endif

#if defined(WOLFSSL_STM32_BARE) && defined(STM32_CRYPTO)
/* Not under WOLF_CRYPTO_CB_ONLY_AES: that mode leaves aes->key empty (the key
* lives in aes->devKey), so the HW GCM must be reached through the STM32
* crypto-callback device, which stages the key first. */
#if defined(WOLFSSL_STM32_BARE) && defined(STM32_CRYPTO) && \
!defined(WOLF_CRYPTO_CB_ONLY_AES)
ret = wc_Stm32_Aes_Gcm(aes, out, in, sz, iv, ivSz,
authTag, authTagSz,
authIn, authInSz, 1 /* enc */);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
/* fall through to SW GCM (still uses HW AES via wc_AesEncrypt) */
#endif /* WOLFSSL_STM32_BARE && STM32_CRYPTO */
#endif /* WOLFSSL_STM32_BARE && STM32_CRYPTO && !WOLF_CRYPTO_CB_ONLY_AES */


#ifdef STM32_CRYPTO_AES_GCM
Expand Down Expand Up @@ -11557,7 +11563,8 @@ int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,

#ifdef STM32_CRYPTO_AES_GCM
/* this function supports inline decrypt */
static WARN_UNUSED_RESULT int wc_AesGcmDecrypt_STM32(
/* Not static: called by the CubeMX crypto-callback device (see encrypt). */
WOLFSSL_LOCAL WARN_UNUSED_RESULT int wc_AesGcmDecrypt_STM32(
Aes* aes, byte* out,
const byte* in, word32 sz,
const byte* iv, word32 ivSz,
Expand Down Expand Up @@ -12201,9 +12208,24 @@ int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
}
#endif

/* BARE: GCM decrypt always uses SW path (with HW AES blocks via
* wc_AesEncrypt). Encrypt is HW-accelerated above; decrypt + tag
* verification stays in well-tested SW for now. */
#if defined(WOLFSSL_STM32_BARE) && defined(STM32_CRYPTO) && \
!defined(WOLF_CRYPTO_CB_ONLY_AES)
/* BARE: HW GCM decrypt-verify on both AES IPs -- the TinyAES GCM engine
* (H5/U5/L5/U3/WBA/...) and the CRYP IP (F2/F4/F7/H7/MP13), the latter
* validated on NUCLEO-F439ZI against the SP 800-38D vectors;
* otherwise wc_Stm32_Aes_Gcm returns CRYPTOCB_UNAVAILABLE and the well-tested
* SW path runs (its AES blocks still on HW via wc_AesEncrypt). The received
* tag is verified inside wc_Stm32_Aes_Gcm (const cast: it compares, never
* writes, on the decrypt path). Excluded under WOLF_CRYPTO_CB_ONLY_AES for
* the same reason as the encrypt path above -- the key is only in
* aes->devKey there, so HW GCM must go through the crypto-cb device. */
ret = wc_Stm32_Aes_Gcm(aes, out, in, sz, iv, ivSz,
(byte*)authTag, authTagSz,
authIn, authInSz, 0 /* dec */);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
/* fall through to SW GCM decrypt */
#endif /* WOLFSSL_STM32_BARE && STM32_CRYPTO && !WOLF_CRYPTO_CB_ONLY_AES */

#ifdef STM32_CRYPTO_AES_GCM
/* The STM standard peripheral library API's doesn't support partial blocks */
Expand Down
45 changes: 30 additions & 15 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -10734,6 +10734,9 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz,
}
if (ret == 0 && version == PKCS5v2) {
ret = GetAlgoV2(encAlgId, &encOid, &encOidSz, &pbeId, &blockSz);
if (ret == 0 && encOid == NULL) {
ret = ALGO_ID_E;
}
}
if (ret == 0) {
/* CBC block ciphers use PKCS#7 padding: 1..blockSz bytes, a full
Expand All @@ -10752,26 +10755,38 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz,
if (ret == 0) {
if (version != PKCS5v2) {
pbeOidBuf = OidFromId((word32)pbeId, oidPBEType, &pbeOidBufSz);
/* pbe = OBJ pbse1 SEQ [ inner ] */
pbeLen = 2 + pbeOidBufSz + 2 + innerLen;
if (pbeOidBuf == NULL) {
ret = ALGO_ID_E;
}
else {
/* pbe = OBJ pbse1 SEQ [ inner ] */
pbeLen = 2 + pbeOidBufSz + 2 + innerLen;
}
}
else {
if (hmacOid > 0) {
hmacOidBuf = OidFromId((word32)hmacOid, oidHmacType,
&hmacOidBufSz);
innerLen += 2 + 2 + hmacOidBufSz;
}
pbeOidBuf = pbes2;
pbeOidBufSz = sizeof(pbes2);
/* kdf = OBJ pbkdf2 [ SEQ innerLen ] */
kdfLen = 2U + (word32)sizeof(pbkdf2Oid) + 2U + innerLen;
/* enc = OBJ enc_alg OCT iv */
encLen = 2U + (word32)encOidSz + 2U + (word32)blockSz;
/* pbe = OBJ pbse2 SEQ [ SEQ [ kdf ] SEQ [ enc ] ] */
pbeLen = 2U + (word32)sizeof(pbes2) + 2U + 2U + kdfLen + 2U +
encLen;

ret = wc_RNG_GenerateBlock(rng, cbcIv, (word32)blockSz);
if (hmacOidBuf == NULL) {
ret = ALGO_ID_E;
}
else {
innerLen += 2 + 2 + hmacOidBufSz;
}
}
if (ret == 0) {
pbeOidBuf = pbes2;
pbeOidBufSz = sizeof(pbes2);
/* kdf = OBJ pbkdf2 [ SEQ innerLen ] */
kdfLen = 2U + (word32)sizeof(pbkdf2Oid) + 2U + innerLen;
/* enc = OBJ enc_alg OCT iv */
encLen = 2U + (word32)encOidSz + 2U + (word32)blockSz;
/* pbe = OBJ pbse2 SEQ [ SEQ [ kdf ] SEQ [ enc ] ] */
pbeLen = 2U + (word32)sizeof(pbes2) + 2U + 2U + kdfLen + 2U +
encLen;

ret = wc_RNG_GenerateBlock(rng, cbcIv, (word32)blockSz);
}
}
}
if (ret == 0) {
Expand Down
Loading
Loading