Skip to content

Commit 78e92ed

Browse files
committed
Add TLS 1.3 crypto callback pending support for transcript HMAC
1 parent 7e4d2de commit 78e92ed

6 files changed

Lines changed: 148 additions & 14 deletions

File tree

src/internal.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9741,6 +9741,10 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
97419741
#ifdef WOLFSSL_ASYNC_IO
97429742
/* Cleanup async */
97439743
FreeAsyncCtx(ssl, 1);
9744+
#endif
9745+
#if defined(WOLFSSL_ASYNC_REINVOKE) && defined(WOLFSSL_TLS13) && \
9746+
!defined(NO_HMAC)
9747+
Tls13FreeHsHmac(ssl);
97449748
#endif
97459749
if (ssl->options.weOwnRng) {
97469750
wc_FreeRng(ssl->rng);

src/ssl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5716,6 +5716,9 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
57165716
ssl->kdfDeriveStep = TLS13_SEND_KDF_NONE;
57175717
ssl->kdfMsgStep = TLS13_MSG_KDF_NONE;
57185718
ssl->kdfMsgType = 0;
5719+
#if defined(WOLFSSL_ASYNC_REINVOKE) && !defined(NO_HMAC)
5720+
Tls13FreeHsHmac(ssl);
5721+
#endif
57195722
#ifdef WOLFSSL_ASYNC_CRYPT
57205723
ssl->options.buildArgs13Set = 0;
57215724
/* An abandoned handshake can leave a mid-flight handler resume

src/tls.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8750,12 +8750,16 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
87508750
/* Outside the allocation guard: a WC_PENDING_E retry must regenerate,
87518751
* not export an ungenerated key. The key type marks completion;
87528752
* kse->pubKey covers backends that never touch the ecc_key (TSIP). */
8753-
if (ret == 0 && eccKey != NULL && kse->pubKey == NULL &&
8754-
eccKey->type != ECC_PRIVATEKEY &&
8755-
eccKey->type != ECC_PRIVATEKEY_ONLY) {
8753+
if (ret == 0 && eccKey != NULL) {
8754+
/* Outside the generation guard below: the export alloc reads
8755+
* pubKeyLen even when generation is skipped. */
87568756
kse->keyLen = keySize;
87578757
kse->pubKeyLen = keySize * 2 + 1;
8758+
}
87588759

8760+
if (ret == 0 && eccKey != NULL && kse->pubKey == NULL &&
8761+
eccKey->type != ECC_PRIVATEKEY &&
8762+
eccKey->type != ECC_PRIVATEKEY_ONLY) {
87598763
#if defined(WOLFSSL_RENESAS_TSIP_TLS)
87608764
ret = tsip_Tls13GenEccKeyPair(ssl, kse);
87618765
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {

src/tls13.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,10 +1505,26 @@ int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret)
15051505
* hash The hash result - verify data.
15061506
* returns length of verify data generated.
15071507
*/
1508+
#if defined(WOLFSSL_ASYNC_REINVOKE) && !defined(NO_HMAC)
1509+
/* Release the held transcript Hmac and its resume state. */
1510+
void Tls13FreeHsHmac(WOLFSSL* ssl)
1511+
{
1512+
if (ssl->hsHmac != NULL) {
1513+
wc_HmacFree(ssl->hsHmac);
1514+
XFREE(ssl->hsHmac, ssl->heap, DYNAMIC_TYPE_HMAC);
1515+
ssl->hsHmac = NULL;
1516+
}
1517+
ssl->hsHmacStep = 0;
1518+
ssl->hsHmacOut = NULL;
1519+
}
1520+
#endif /* WOLFSSL_ASYNC_REINVOKE && !NO_HMAC */
1521+
15081522
static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash,
15091523
word32* pHashSz)
15101524
{
1525+
#ifndef WOLFSSL_ASYNC_REINVOKE
15111526
WC_DECLARE_VAR(verifyHmac, Hmac, 1, 0);
1527+
#endif
15121528
int hashType = WC_SHA256;
15131529
int hashSz = WC_SHA256_DIGEST_SIZE;
15141530
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
@@ -1561,6 +1577,51 @@ static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash,
15611577
WOLFSSL_BUFFER(hash, hashSz);
15621578
#endif
15631579

1580+
#ifdef WOLFSSL_ASYNC_REINVOKE
1581+
/* Held on the SSL object so a crypto callback WC_PENDING_E resumes by
1582+
* re-invoking the same Hmac with identical arguments; the transcript
1583+
* hash input is recomputed deterministically by the caller's retry.
1584+
* Bound to the output buffer: a replayed caller that computes several
1585+
* HMACs (the PSK binder list) must not resume one request against
1586+
* another's key, so a different output discards the held state. */
1587+
if (ssl->hsHmac != NULL && ssl->hsHmacOut != hash)
1588+
Tls13FreeHsHmac(ssl);
1589+
if (ssl->hsHmac == NULL) {
1590+
ssl->hsHmac = (Hmac*)XMALLOC(sizeof(Hmac), ssl->heap,
1591+
DYNAMIC_TYPE_HMAC);
1592+
if (ssl->hsHmac == NULL)
1593+
return MEMORY_E;
1594+
ret = wc_HmacInit(ssl->hsHmac, ssl->heap, ssl->devId);
1595+
if (ret != 0) {
1596+
Tls13FreeHsHmac(ssl);
1597+
return ret;
1598+
}
1599+
ssl->hsHmacStep = 0;
1600+
ssl->hsHmacOut = hash;
1601+
}
1602+
/* Armed before the operations, matching the HKDF helpers. */
1603+
ret = Tls13KdfAsyncInit(ssl);
1604+
if (ret != 0) {
1605+
Tls13FreeHsHmac(ssl);
1606+
return ret;
1607+
}
1608+
if (ssl->hsHmacStep == 0) {
1609+
ret = wc_HmacSetKey(ssl->hsHmac, hashType, key,
1610+
ssl->specs.hash_size);
1611+
if (ret == 0)
1612+
ssl->hsHmacStep = 1;
1613+
}
1614+
if (ret == 0 && ssl->hsHmacStep == 1) {
1615+
ret = wc_HmacUpdate(ssl->hsHmac, hash, (word32)hashSz);
1616+
if (ret == 0)
1617+
ssl->hsHmacStep = 2;
1618+
}
1619+
if (ret == 0 && ssl->hsHmacStep == 2)
1620+
ret = wc_HmacFinal(ssl->hsHmac, hash);
1621+
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E))
1622+
return wolfSSL_AsyncPush(ssl, &ssl->kdfAsyncDev);
1623+
Tls13FreeHsHmac(ssl);
1624+
#else
15641625
WC_ALLOC_VAR_EX(verifyHmac, Hmac, 1, NULL, DYNAMIC_TYPE_HMAC,
15651626
return MEMORY_E);
15661627

@@ -1576,6 +1637,7 @@ static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash,
15761637
}
15771638

15781639
WC_FREE_VAR_EX(verifyHmac, NULL, DYNAMIC_TYPE_HMAC);
1640+
#endif /* WOLFSSL_ASYNC_REINVOKE */
15791641

15801642
#ifdef WOLFSSL_DEBUG_TLS
15811643
WOLFSSL_MSG(" Hash");
@@ -14031,6 +14093,7 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input,
1403114093
static int ExpectedResumptionSecret(WOLFSSL* ssl)
1403214094
{
1403314095
int ret;
14096+
int saveRet = 0;
1403414097
word32 finishedSz = 0;
1403514098
byte mac[WC_MAX_DIGEST_SIZE];
1403614099
Digest digest;
@@ -14094,6 +14157,9 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl)
1409414157

1409514158
/* Restore the hash inline with currently seen messages. */
1409614159
restore:
14160+
/* The restore result must not mask the error that got here, or a
14161+
* WC_PENDING_E would be reported as success with the derive skipped. */
14162+
saveRet = ret;
1409714163
switch (ssl->specs.mac_algorithm) {
1409814164
#ifndef NO_SHA256
1409914165
case sha256_mac:
@@ -14124,6 +14190,8 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl)
1412414190
break;
1412514191
#endif
1412614192
}
14193+
if (saveRet != 0)
14194+
ret = saveRet;
1412714195

1412814196
ForceZero(mac, sizeof(mac));
1412914197
return ret;

tests/api/test_tls13.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9543,7 +9543,8 @@ enum TestTls13PendTarget {
95439543
TEST_TLS13_PEND_ECC_KEYGEN,
95449544
TEST_TLS13_PEND_ECDSA_SIGN,
95459545
TEST_TLS13_PEND_ECDSA_VERIFY,
9546-
TEST_TLS13_PEND_KDF
9546+
TEST_TLS13_PEND_KDF,
9547+
TEST_TLS13_PEND_HMAC
95479548
};
95489549

95499550
typedef struct TestTls13PendCtx {
@@ -9585,6 +9586,9 @@ static int TestTls13PendMatches(int target, wc_CryptoInfo* info)
95859586
case TEST_TLS13_PEND_KDF:
95869587
match = (info->algo_type == WC_ALGO_TYPE_KDF);
95879588
break;
9589+
case TEST_TLS13_PEND_HMAC:
9590+
match = (info->algo_type == WC_ALGO_TYPE_HMAC);
9591+
break;
95889592
default:
95899593
break;
95909594
}
@@ -9615,6 +9619,38 @@ static int TestTls13PendCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
96159619

96169620
if (info == NULL || c == NULL)
96179621
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
9622+
#if defined(HAVE_HKDF) && !defined(NO_HMAC) && !defined(HAVE_SELFTEST) && \
9623+
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0))
9624+
if (c->target == TEST_TLS13_PEND_HMAC &&
9625+
info->algo_type == WC_ALGO_TYPE_KDF) {
9626+
/* Serve the key schedule synchronously in software; falling back
9627+
* with the devId set would route its internal HMACs back here and
9628+
* those cannot resume (see wolfcrypt/src/hmac.c). Only the
9629+
* TLS-layer transcript HMACs are left to pend. */
9630+
if (info->kdf.type == WC_KDF_TYPE_HKDF_EXTRACT) {
9631+
return wc_HKDF_Extract_ex(info->kdf.hkdf_extract.hashType,
9632+
info->kdf.hkdf_extract.salt, info->kdf.hkdf_extract.saltSz,
9633+
info->kdf.hkdf_extract.inKey, info->kdf.hkdf_extract.inKeySz,
9634+
info->kdf.hkdf_extract.out, NULL, INVALID_DEVID);
9635+
}
9636+
if (info->kdf.type == WC_KDF_TYPE_HKDF_EXPAND) {
9637+
return wc_HKDF_Expand_ex(info->kdf.hkdf_expand.hashType,
9638+
info->kdf.hkdf_expand.inKey, info->kdf.hkdf_expand.inKeySz,
9639+
info->kdf.hkdf_expand.info, info->kdf.hkdf_expand.infoSz,
9640+
info->kdf.hkdf_expand.out, info->kdf.hkdf_expand.outSz,
9641+
NULL, INVALID_DEVID);
9642+
}
9643+
if (info->kdf.type == WC_KDF_TYPE_HKDF) {
9644+
return wc_HKDF_ex(info->kdf.hkdf.hashType,
9645+
info->kdf.hkdf.inKey, info->kdf.hkdf.inKeySz,
9646+
info->kdf.hkdf.salt, info->kdf.hkdf.saltSz,
9647+
info->kdf.hkdf.info, info->kdf.hkdf.infoSz,
9648+
info->kdf.hkdf.out, info->kdf.hkdf.outSz,
9649+
NULL, INVALID_DEVID);
9650+
}
9651+
}
9652+
#endif
9653+
96189654
if (!TestTls13PendMatches(c->target, info))
96199655
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
96209656

@@ -9849,6 +9885,14 @@ int test_tls13_cryptocb_async(void)
98499885
TEST_SUCCESS);
98509886
ExpectIntEQ(test_tls13_cryptocb_pend_one(TEST_TLS13_PEND_KDF, 1),
98519887
TEST_SUCCESS);
9888+
#if !defined(HAVE_SELFTEST) && \
9889+
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0))
9890+
/* Transcript HMACs (Finished verify_data) pending on both sides. */
9891+
ExpectIntEQ(test_tls13_cryptocb_pend_one(TEST_TLS13_PEND_HMAC, 0),
9892+
TEST_SUCCESS);
9893+
ExpectIntEQ(test_tls13_cryptocb_pend_one(TEST_TLS13_PEND_HMAC, 1),
9894+
TEST_SUCCESS);
9895+
#endif
98529896
#endif
98539897
#endif
98549898
return EXPECT_RESULT();

wolfssl/internal.h

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,18 @@ WOLFSSL_LOCAL int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input
23662366
WOLFSSL_LOCAL int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
23672367
word16 sz, const byte* aad, word16 aadSz);
23682368
WOLFSSL_LOCAL int DoTls13MsgDerives(WOLFSSL* ssl, byte type);
2369+
/* A crypto/PK callback pending is finished by re-invoking the provider:
2370+
* wolfSSL_AsyncPoll() never runs a callback. Exported so tests compile in
2371+
* only where a callback pend is resumable. */
2372+
#if defined(WOLFSSL_ASYNC_CRYPT) && \
2373+
(defined(WOLF_CRYPTO_CB) || defined(HAVE_PK_CALLBACKS)) && \
2374+
!defined(WOLFSSL_ASYNC_CRYPT_SW) && !defined(HAVE_INTEL_QA) && \
2375+
!defined(HAVE_CAVIUM)
2376+
#define WOLFSSL_ASYNC_REINVOKE
2377+
#endif
2378+
#if defined(WOLFSSL_ASYNC_REINVOKE) && !defined(NO_HMAC)
2379+
WOLFSSL_LOCAL void Tls13FreeHsHmac(WOLFSSL* ssl);
2380+
#endif
23692381
WOLFSSL_LOCAL int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input,
23702382
word32* inOutIdx, byte type,
23712383
word32 size, word32 totalSz);
@@ -6424,16 +6436,6 @@ enum ConnectionIdUsage {
64246436

64256437
/* wolfSSL ssl type */
64266438

6427-
/* A crypto/PK callback pending is finished by re-invoking the provider:
6428-
* wolfSSL_AsyncPoll() never runs a callback. Exported so tests compile in
6429-
* only where a callback pend is resumable. */
6430-
#if defined(WOLFSSL_ASYNC_CRYPT) && \
6431-
(defined(WOLF_CRYPTO_CB) || defined(HAVE_PK_CALLBACKS)) && \
6432-
!defined(WOLFSSL_ASYNC_CRYPT_SW) && !defined(HAVE_INTEL_QA) && \
6433-
!defined(HAVE_CAVIUM)
6434-
#define WOLFSSL_ASYNC_REINVOKE
6435-
#endif
6436-
64376439
/* TLS 1.3 key-schedule resume steps (kdfMsgStep/kdfDeriveStep). A value is
64386440
* recorded after its named operation completes ("step <= X" = X not done);
64396441
* 0 = sequence not entered or finished. Values repeat across sequences. */
@@ -7076,6 +7078,15 @@ struct WOLFSSL {
70767078
byte kdfDeriveStep; /* enum Tls13KdfSendStep (send side) */
70777079
byte kdfMsgStep; /* enum Tls13KdfMsgStep (receive side) */
70787080
byte kdfMsgType; /* handshake type kdfMsgStep belongs to */
7081+
#if defined(WOLFSSL_ASYNC_REINVOKE) && defined(WOLFSSL_TLS13) && \
7082+
!defined(NO_HMAC)
7083+
/* Transcript HMAC (Finished verify_data, PSK binders) held across a
7084+
* WC_PENDING_E so the retry re-invokes the same object and arguments,
7085+
* bound to its output buffer. */
7086+
Hmac* hsHmac;
7087+
byte* hsHmacOut;
7088+
byte hsHmacStep;
7089+
#endif
70797090
};
70807091

70817092
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)

0 commit comments

Comments
 (0)