Skip to content

Commit 748c20f

Browse files
committed
Merged PR 15120207: Fix heap buffer overflow in SymCryptXmssSign when height >= 32
Fix for MSRC 111294: SymCryptXmssSign function - Heap overflow via 64->32-bit leaf-count truncation This PR fixes heap buffer overflow in `SymCryptXmssSign` when signing with XMSS^MT parameter sets with a height of 32 or greater. Note that XMSS(^MT) signing is only approved by FIPS and Microsoft SDL when performed inside an HSM; XMSS(^MT) signing in SymCrypt is provided only for testing and validation purposes and should not be used in production software. - Update callers of `SymCryptHbsSizeofScratchBytesForIncrementalTreehash` to consistently use `1ULL << pParams->nLayerHeight` for `nLeaves` - since XMSS^MT operations are done layer-by-layer, scratch space should only allocate space for one layer (consistent with how `SymCryptXmssVerifyInternal` already worked) - Add regression test with custom parameter set to exercise 32-deep tree Validated: - Local unit tests - Validated POC on VM: ASAN crashes without fix, does not crash with fix Thanks to [Federico Ponzi](https://fponzi.me) for finding this. Related work items: #61560104
1 parent e615174 commit 748c20f

6 files changed

Lines changed: 618 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ prior to the creation of a new release, based on the changes contained in that r
55
# Version 103.11.0
66

77
- Add Composite ML-KEM implementation
8+
- Fix heap buffer overflow in `SymCryptXmssSign` when signing with XMSS^MT parameter sets with a height of 32 or greater
9+
- Thanks to [Federico Ponzi](https://fponzi.me) for finding this
810

911
# Version 103.10.2
1012

lib/sc_lib.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5096,3 +5096,39 @@ SymCryptCountLeadingZeros32( UINT32 value )
50965096

50975097
return (UINT32)zeros;
50985098
}
5099+
5100+
FORCEINLINE
5101+
UINT32
5102+
SymCryptCountLeadingZeros64( UINT64 value )
5103+
{
5104+
unsigned long zeros = 0;
5105+
5106+
if(value == 0)
5107+
{
5108+
return 64;
5109+
}
5110+
5111+
#if SYMCRYPT_MS_VC && (SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64)
5112+
_BitScanReverse64(&zeros, value);
5113+
zeros = 63 - zeros;
5114+
#elif SYMCRYPT_MS_VC && (SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_ARM)
5115+
if( (value >> 32) == 0 )
5116+
{
5117+
_BitScanReverse(&zeros, (UINT32)value);
5118+
zeros = 63 - zeros;
5119+
} else {
5120+
_BitScanReverse(&zeros, (UINT32)(value >> 32));
5121+
zeros = 31 - zeros;
5122+
}
5123+
#elif SYMCRYPT_GNUC
5124+
zeros = __builtin_clzll(value);
5125+
#else
5126+
while( (value & 0x8000000000000000) == 0 )
5127+
{
5128+
zeros++;
5129+
value <<= 1;
5130+
}
5131+
#endif
5132+
5133+
return (UINT32)zeros;
5134+
}

lib/xmss.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -417,8 +417,8 @@ SymCryptXmssSetParams(
417417
goto cleanup;
418418
}
419419

420-
// Layer height (tree height of one layer) can be at most 32
421-
if ((nTotalTreeHeight / nLayers) > 32)
420+
// Layer height (tree height of one layer) can be at most 31
421+
if ((nTotalTreeHeight / nLayers) > 31)
422422
{
423423
scError = SYMCRYPT_INVALID_ARGUMENT;
424424
goto cleanup;
@@ -720,9 +720,11 @@ SymCryptHbsSizeofScratchBytesForIncrementalTreehash(
720720
UINT32 cbNode,
721721
UINT32 nLeaves)
722722
{
723-
SIZE_T nodeSize = (cbNode + 2 * sizeof(UINT32)) + sizeof(SYMCRYPT_INCREMENTAL_TREEHASH);
723+
SIZE_T nodeSize = cbNode + 2 * sizeof(UINT32);
724+
SIZE_T result = (sizeof(SYMCRYPT_INCREMENTAL_TREEHASH) - sizeof(SYMCRYPT_TREEHASH_NODE));
724725

725-
return nodeSize * SymCryptHbsIncrementalTreehashStackDepth(nLeaves);
726+
result += nodeSize * SymCryptHbsIncrementalTreehashStackDepth(nLeaves);
727+
return result;
726728
}
727729

728730

@@ -1015,8 +1017,8 @@ SymCryptXmssComputeSubtreeRoot(
10151017
PSYMCRYPT_TREEHASH_NODE pNode = NULL;
10161018
SYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT ctxIncHash;
10171019

1018-
// uLeaf must be a multiple of 2^uHeight
1019-
SYMCRYPT_ASSERT((uLeaf & ((1UL << uHeight) - 1)) == 0);
1020+
SYMCRYPT_ASSERT((uLeaf & ((1UL << uHeight) - 1)) == 0); // uLeaf must be a multiple of 2^uHeight
1021+
SYMCRYPT_ASSERT(pParams->nLayerHeight < 32); // Ensure nLeaves fits in 32 bits
10201022

10211023
SIZE_T cbScratchTree = SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nLayerHeight);
10221024
SIZE_T cbScratchLtree = SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len);
@@ -1078,6 +1080,8 @@ SymCryptXmssComputePublicRoot(
10781080
SIZE_T cbScratch = 0;
10791081
XMSS_ADRS adrs;
10801082

1083+
SYMCRYPT_ASSERT(pParams->nLayerHeight < 32); // Ensure nLeaves fits in 32 bits
1084+
10811085
if (pbRoot == NULL || cbRoot != pParams->cbHashOutput ||
10821086
pbSeed == NULL || cbSeed != pParams->cbHashOutput ||
10831087
pbSkXmss == NULL || cbSkXmss != pParams->cbHashOutput)
@@ -1751,6 +1755,8 @@ SymCryptXmssVerifyInternal(
17511755

17521756
SYMCRYPT_CHECK_MAGIC(pKey);
17531757

1758+
SYMCRYPT_ASSERT(pParams->nLayerHeight < 32); // Ensure nLeaves fits in 32 bits
1759+
17541760
if (flags != 0 ||
17551761
pbSignature == NULL ||
17561762
cbSignature != SymCryptXmssSizeofSignatureFromParams(pParams) ||
@@ -1761,7 +1767,7 @@ SymCryptXmssVerifyInternal(
17611767
}
17621768

17631769
cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len);
1764-
cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << (pParams->nTotalTreeHeight / pParams->nLayers));
1770+
cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nLayerHeight);
17651771

17661772
pbScratch = (PBYTE)SymCryptCallbackAlloc(cbScratch);
17671773

@@ -2037,9 +2043,10 @@ SymCryptXmssSign(
20372043
UINT32 uLeaf;
20382044
const UINT64 LeafMask = (1ULL << pParams->nLayerHeight) - 1;
20392045

2040-
20412046
SYMCRYPT_CHECK_MAGIC(pKey);
20422047

2048+
SYMCRYPT_ASSERT(pParams->nLayerHeight < 32); // Ensure nLeaves fits in 32 bits
2049+
20432050
if (flags != 0 ||
20442051
pbSignature == NULL ||
20452052
cbSignature != SymCryptXmssSizeofSignatureFromParams(pParams) ||
@@ -2050,7 +2057,7 @@ SymCryptXmssSign(
20502057
}
20512058

20522059
cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len); // Ltree hashing
2053-
cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nTotalTreeHeight); // Merkle-tree hashing
2060+
cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nLayerHeight); // Merkle-tree hashing
20542061

20552062
pbScratch = (PBYTE)SymCryptCallbackAlloc(cbScratch);
20562063

0 commit comments

Comments
 (0)