Skip to content

Commit c9d8dae

Browse files
committed
Improve CertificateVerify record fragmentation for large PQC sigs
Refine the record fragmentation approach for CertificateVerify messages that exceed MAX_RECORD_SIZE (16384 bytes). Each fragment is encrypted via BuildTls13Message with hashOutput=1, matching the per-fragment incremental hashing approach used by SendTls13Certificate. This correctly handles SLH-DSA-SHAKE-128s (7856-byte sig, single record) and sends SLH-DSA-SHAKE-128f (17088-byte sig) across two records. However, the client-side signature verification still fails for the 128f case - the signature and transcript data arrive correctly (verified via debug logging) but wc_SlhDsaKey_Verify returns error. Further investigation needed into whether the client-side handshake message reassembly corrupts the signature bytes or the peer public key extraction from fragmented Certificate messages is affected. The 128s variant and all OQS interop tests continue to work correctly. https://claude.ai/code/session_019gqvW3ZMKGGyi6zCRNPDYV
1 parent 63da747 commit c9d8dae

1 file changed

Lines changed: 26 additions & 24 deletions

File tree

src/tls13.c

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10258,30 +10258,36 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
1025810258
#endif /* WOLFSSL_DTLS13 */
1025910259

1026010260
{
10261-
/* The handshake message (after record header) may exceed the
10262-
* TLS record size limit (MAX_RECORD_SIZE = 16384). Large PQC
10263-
* signatures (e.g. SLH-DSA) can produce CertificateVerify
10264-
* messages > 16KB. Split into multiple encrypted records,
10265-
* each within the limit. TLS 1.3 allows handshake messages
10266-
* to be fragmented across records (RFC 8446 Section 5.1).
10261+
/* The CertificateVerify handshake message may exceed
10262+
* MAX_RECORD_SIZE for large PQC signatures (e.g. SLH-DSA
10263+
* SHAKE-128f = 17088 bytes). Split into multiple encrypted
10264+
* records, each within the limit.
1026710265
*
10268-
* The handshake transcript hash must cover the entire
10269-
* plaintext handshake message. Hash it once up front, then
10270-
* encrypt each fragment without re-hashing. */
10266+
* Each fragment is hashed into the transcript via
10267+
* BuildTls13Message(hashOutput=1), matching the approach
10268+
* used by SendTls13Certificate for large cert chains. The
10269+
* client-side receiver hashes each decrypted record
10270+
* independently in the same incremental order. */
1027110271
int hsLen = args->sendSz - RECORD_HEADER_SZ;
1027210272
byte* hsData = args->output + RECORD_HEADER_SZ;
10273-
/* Max plaintext per record: leave room for content type byte
10274-
* and AEAD tag so the ciphertext stays within the limit. */
1027510273
int maxPlain = MAX_RECORD_SIZE - 1
1027610274
- ssl->specs.aead_mac_size;
1027710275

10278-
/* Hash the entire handshake message into the transcript
10279-
* before splitting into records. */
10280-
ret = HashOutput(ssl, args->output, args->sendSz, 0);
10281-
if (ret != 0)
10282-
goto exit_scv;
10283-
10284-
{
10276+
if (hsLen <= maxPlain) {
10277+
/* Fits in a single record — standard path. */
10278+
ret = BuildTls13Message(ssl, args->output,
10279+
WC_MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA,
10280+
hsData, hsLen, handshake, 1, 0, 0);
10281+
if (ret < 0)
10282+
goto exit_scv;
10283+
args->sendSz = ret;
10284+
ret = 0;
10285+
ssl->buffers.outputBuffer.length += (word32)args->sendSz;
10286+
}
10287+
else {
10288+
/* Fragment across multiple records. Each fragment is
10289+
* hashed with hashOutput=1 so the transcript accumulates
10290+
* incrementally, matching what the receiver does. */
1028510291
int hsOff = 0;
1028610292
int totalSent = 0;
1028710293

@@ -10293,18 +10299,15 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
1029310299
if (fragSz > maxPlain)
1029410300
fragSz = maxPlain;
1029510301

10296-
/* Ensure output buffer has room for this record. */
1029710302
if ((ret = CheckAvailableSize(ssl,
10298-
fragSz + MAX_MSG_EXTRA)) != 0) {
10303+
fragSz + MAX_MSG_EXTRA)) != 0)
1029910304
goto exit_scv;
10300-
}
1030110305
out = GetOutputBuffer(ssl);
1030210306

10303-
/* hashOutput=0: already hashed above. */
1030410307
builtSz = BuildTls13Message(ssl, out,
1030510308
fragSz + MAX_MSG_EXTRA,
1030610309
hsData + hsOff, fragSz, handshake,
10307-
0, 0, 0);
10310+
1, 0, 0);
1030810311
if (builtSz < 0) {
1030910312
ret = builtSz;
1031010313
goto exit_scv;
@@ -10314,7 +10317,6 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
1031410317
totalSent += builtSz;
1031510318
hsOff += fragSz;
1031610319
}
10317-
1031810320
args->sendSz = totalSent;
1031910321
ret = 0;
1032010322
}

0 commit comments

Comments
 (0)