mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-19 01:41:30 +10:00
Fix stack buffer overflow in aes_ccm_encr for partial blocks (#11347)
* Fix out-of-bounds write in aes_ccm_encr for partial blocks aes_ccm_encr() writes a full 16-byte AES block to the output before XOR-ing with the input, so a trailing partial block writes up to 15 bytes past the length the caller asked for. Every caller in the tree passes a buffer with enough slack, so nothing misbehaves today, but the decrypt path clears it by only a few bytes. Encrypt into a temporary block and XOR out of it, matching what aes_ccm_encr_auth() and aes_ccm_decr_auth() already do in this same file. The ciphertext is unchanged. * Add regression test for the CCM partial-block write and drop stale workarounds The guard bytes past the caller's buffer catch the overflow without relying on a sanitizer, so the test is meaningful in the native environment too. encryptCurve25519() no longer needs to write extraNonce before aes_ccm_ae(): the call stays inside numBytes now, so the copy after it is the only one required. The comment warning about the 15-byte overshoot no longer describes the code.
This commit is contained in:
@@ -230,8 +230,6 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtas
|
||||
if (!HardwareRNG::fill((uint8_t *)&extraNonceTmp, sizeof(extraNonceTmp)))
|
||||
CryptRNG.rand((uint8_t *)&extraNonceTmp, sizeof(extraNonceTmp));
|
||||
auth = bytesOut + numBytes;
|
||||
memcpy((uint8_t *)(auth + 8), &extraNonceTmp,
|
||||
sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : *extraNonce = extraNonceTmp;
|
||||
LOG_DEBUG("Random nonce value: %d", extraNonceTmp);
|
||||
if (remotePublic.size == 0) {
|
||||
LOG_DEBUG("Node %d or their public_key not found", toNode);
|
||||
@@ -246,8 +244,7 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtas
|
||||
// Calculate the shared secret with the destination node and encrypt
|
||||
printBytes("Attempt encrypt with nonce: ", nonce, 13);
|
||||
printBytes("Attempt encrypt with shared_key starting with: ", shared_key, 8);
|
||||
aes_ccm_ae(shared_key, 32, nonce, 8, bytes, numBytes, nullptr, 0, bytesOut,
|
||||
auth); // this can write up to 15 bytes longer than numbytes past bytesOut
|
||||
aes_ccm_ae(shared_key, 32, nonce, 8, bytes, numBytes, nullptr, 0, bytesOut, auth);
|
||||
memcpy((uint8_t *)(auth + 8), &extraNonceTmp,
|
||||
sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : *extraNonce = extraNonceTmp;
|
||||
return true;
|
||||
|
||||
@@ -111,11 +111,12 @@ static void aes_ccm_encr(size_t L, const uint8_t *in, size_t len, uint8_t *out,
|
||||
in += AES_BLOCK_SIZE;
|
||||
}
|
||||
if (last) {
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
|
||||
crypto->aesEncrypt(a, out);
|
||||
crypto->aesEncrypt(a, tmp);
|
||||
/* XOR zero-padded last block */
|
||||
for (i = 0; i < last; i++)
|
||||
*out++ ^= *in++;
|
||||
out[i] = tmp[i] ^ in[i];
|
||||
}
|
||||
}
|
||||
static void aes_ccm_encr_auth(size_t M, const uint8_t *x, uint8_t *a, uint8_t *auth)
|
||||
|
||||
Reference in New Issue
Block a user