Skip to content

Commit 2089026

Browse files
tcarmelveilleuxrestyled-commits
authored andcommitted
Make Spake2+ output arguments size-safe (#14667)
* Make Spake2+ output arguments size-size - Both Spake2p::Mac() and Spake2p::HashFinalize expected properly sized output buffers without ensuring it, leading to possible buffer overruns. - This PR makes it necessary to pass a MutableByteSpan to ensure size is checked, and adds the proper checks throughout Fixes #4189 Testing done: - Updatd unit tests to match and they still pass - Integration tests pass * Restyled by clang-format Co-authored-by: Restyled.io <[email protected]>
1 parent 2e98955 commit 2089026

File tree

5 files changed

+40
-25
lines changed

5 files changed

+40
-25
lines changed

src/crypto/CHIPCryptoPAL.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ CHIP_ERROR Spake2p::ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t
345345
CHIP_ERROR Spake2p::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len)
346346
{
347347
CHIP_ERROR error = CHIP_ERROR_INTERNAL;
348+
MutableByteSpan out_span{ out, *out_len };
348349
uint8_t point_buffer[kMAX_Point_Length];
349350
void * MN = nullptr; // Choose N if a prover, M if a verifier
350351
void * XY = nullptr; // Choose Y if a prover, X if a verifier
@@ -406,7 +407,8 @@ CHIP_ERROR Spake2p::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t *
406407

407408
SuccessOrExit(error = GenerateKeys());
408409

409-
SuccessOrExit(error = Mac(Kcaorb, hash_size / 2, in, in_len, out));
410+
SuccessOrExit(error = Mac(Kcaorb, hash_size / 2, in, in_len, out_span));
411+
VerifyOrExit(out_span.size() == hash_size, error = CHIP_ERROR_INTERNAL);
410412

411413
state = CHIP_SPAKE2P_STATE::R2;
412414
error = CHIP_NO_ERROR;
@@ -419,7 +421,9 @@ CHIP_ERROR Spake2p::GenerateKeys()
419421
{
420422
static const uint8_t info_keyconfirm[16] = { 'C', 'o', 'n', 'f', 'i', 'r', 'm', 'a', 't', 'i', 'o', 'n', 'K', 'e', 'y', 's' };
421423

422-
ReturnErrorOnFailure(HashFinalize(Kae));
424+
MutableByteSpan Kae_span{ &Kae[0], sizeof(Kae) };
425+
426+
ReturnErrorOnFailure(HashFinalize(Kae_span));
423427
ReturnErrorOnFailure(KDF(Ka, hash_size / 2, nullptr, 0, info_keyconfirm, sizeof(info_keyconfirm), Kcab, hash_size));
424428

425429
return CHIP_NO_ERROR;
@@ -486,9 +490,8 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Hash(const uint8_t * in, size_t in_len
486490
return CHIP_NO_ERROR;
487491
}
488492

489-
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::HashFinalize(uint8_t * out)
493+
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::HashFinalize(MutableByteSpan & out_span)
490494
{
491-
MutableByteSpan out_span(out, kSHA256_Hash_Length);
492495
ReturnErrorOnFailure(sha256_hash_ctx.Finish(out_span));
493496
return CHIP_NO_ERROR;
494497
}

src/crypto/CHIPCryptoPAL.h

+11-10
Original file line numberDiff line numberDiff line change
@@ -1112,24 +1112,25 @@ class Spake2p
11121112
/**
11131113
* @brief Return the hash.
11141114
*
1115-
* @param out Output buffer. The size is implicit and is determined by the hash used.
1115+
* @param out_span Output buffer. The size available must be >= the hash size. It gets resized
1116+
* to hash size on success.
11161117
*
11171118
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
11181119
**/
1119-
virtual CHIP_ERROR HashFinalize(uint8_t * out) = 0;
1120+
virtual CHIP_ERROR HashFinalize(MutableByteSpan & out_span) = 0;
11201121

11211122
/**
11221123
* @brief Generate a message authentication code.
11231124
*
1124-
* @param key The MAC key buffer.
1125-
* @param key_len The size of the MAC key in bytes.
1126-
* @param in The input buffer.
1127-
* @param in_len The size of the input data to MAC in bytes.
1128-
* @param out The output MAC buffer. Size is implicit and is determined by the hash used.
1125+
* @param key The MAC key buffer.
1126+
* @param key_len The size of the MAC key in bytes.
1127+
* @param in The input buffer.
1128+
* @param in_len The size of the input data to MAC in bytes.
1129+
* @param out_span The output MAC buffer span. Size must be >= the hash_size. Output size is updated to fit on success.
11291130
*
11301131
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
11311132
**/
1132-
virtual CHIP_ERROR Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, uint8_t * out) = 0;
1133+
virtual CHIP_ERROR Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, MutableByteSpan & out_span) = 0;
11331134

11341135
/**
11351136
* @brief Verify a message authentication code.
@@ -1192,7 +1193,7 @@ class Spake2p_P256_SHA256_HKDF_HMAC : public Spake2p
11921193
~Spake2p_P256_SHA256_HKDF_HMAC() override { Spake2p_P256_SHA256_HKDF_HMAC::Clear(); }
11931194

11941195
void Clear() override;
1195-
CHIP_ERROR Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, uint8_t * out) override;
1196+
CHIP_ERROR Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, MutableByteSpan & out_span) override;
11961197
CHIP_ERROR MacVerify(const uint8_t * key, size_t key_len, const uint8_t * mac, size_t mac_len, const uint8_t * in,
11971198
size_t in_len) override;
11981199
CHIP_ERROR FELoad(const uint8_t * in, size_t in_len, void * fe) override;
@@ -1212,7 +1213,7 @@ class Spake2p_P256_SHA256_HKDF_HMAC : public Spake2p
12121213
protected:
12131214
CHIP_ERROR InitImpl() override;
12141215
CHIP_ERROR Hash(const uint8_t * in, size_t in_len) override;
1215-
CHIP_ERROR HashFinalize(uint8_t * out) override;
1216+
CHIP_ERROR HashFinalize(MutableByteSpan & out_span) override;
12161217
CHIP_ERROR KDF(const uint8_t * secret, size_t secret_length, const uint8_t * salt, size_t salt_length, const uint8_t * info,
12171218
size_t info_length, uint8_t * out, size_t out_length) override;
12181219

src/crypto/CHIPCryptoPALOpenSSL.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -1323,10 +1323,14 @@ void Spake2p_P256_SHA256_HKDF_HMAC::Clear()
13231323
state = CHIP_SPAKE2P_STATE::PREINIT;
13241324
}
13251325

1326-
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, uint8_t * out)
1326+
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len,
1327+
MutableByteSpan & out_span)
13271328
{
13281329
HMAC_sha hmac;
1329-
return hmac.HMAC_SHA256(key, key_len, in, in_len, out, kSHA256_Hash_Length);
1330+
VerifyOrReturnError(out_span.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL);
1331+
ReturnErrorOnFailure(hmac.HMAC_SHA256(key, key_len, in, in_len, out_span.data(), kSHA256_Hash_Length));
1332+
out_span = out_span.SubSpan(0, kSHA256_Hash_Length);
1333+
return CHIP_NO_ERROR;
13301334
}
13311335

13321336
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::MacVerify(const uint8_t * key, size_t key_len, const uint8_t * mac, size_t mac_len,
@@ -1335,9 +1339,11 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::MacVerify(const uint8_t * key, size_t
13351339
VerifyOrReturnError(mac_len == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT);
13361340

13371341
uint8_t computed_mac[kSHA256_Hash_Length];
1338-
ReturnErrorOnFailure(Mac(key, key_len, in, in_len, computed_mac));
1342+
MutableByteSpan computed_mac_span{ computed_mac };
1343+
ReturnErrorOnFailure(Mac(key, key_len, in, in_len, computed_mac_span));
1344+
VerifyOrReturnError(computed_mac_span.size() == mac_len, CHIP_ERROR_INTERNAL);
13391345

1340-
VerifyOrReturnError(CRYPTO_memcmp(mac, computed_mac, mac_len) == 0, CHIP_ERROR_INTERNAL);
1346+
VerifyOrReturnError(CRYPTO_memcmp(mac, computed_mac_span.data(), computed_mac_span.size()) == 0, CHIP_ERROR_INTERNAL);
13411347

13421348
return CHIP_NO_ERROR;
13431349
}

src/crypto/CHIPCryptoPALmbedTLS.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -1027,10 +1027,14 @@ void Spake2p_P256_SHA256_HKDF_HMAC::Clear()
10271027
state = CHIP_SPAKE2P_STATE::PREINIT;
10281028
}
10291029

1030-
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, uint8_t * out)
1030+
CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len,
1031+
MutableByteSpan & out_span)
10311032
{
10321033
HMAC_sha hmac;
1033-
return hmac.HMAC_SHA256(key, key_len, in, in_len, out, kSHA256_Hash_Length);
1034+
VerifyOrReturnError(out_span.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL);
1035+
ReturnErrorOnFailure(hmac.HMAC_SHA256(key, key_len, in, in_len, out_span.data(), kSHA256_Hash_Length));
1036+
out_span = out_span.SubSpan(0, kSHA256_Hash_Length);
1037+
return CHIP_NO_ERROR;
10341038
}
10351039

10361040
/**
@@ -1058,11 +1062,11 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::MacVerify(const uint8_t * key, size_t
10581062
int result = 0;
10591063

10601064
uint8_t computed_mac[kSHA256_Hash_Length];
1061-
1065+
MutableByteSpan computed_mac_span{ computed_mac };
10621066
VerifyOrExit(mac_len == kSHA256_Hash_Length, error = CHIP_ERROR_INVALID_ARGUMENT);
10631067

1064-
error = Mac(key, key_len, in, in_len, computed_mac);
1065-
SuccessOrExit(error);
1068+
SuccessOrExit(error = Mac(key, key_len, in, in_len, computed_mac_span));
1069+
VerifyOrExit(computed_mac_span.size() == mac_len, error = CHIP_ERROR_INTERNAL);
10661070

10671071
VerifyOrExit(constant_time_memcmp(mac, computed_mac, kSHA256_Hash_Length) == 0, error = CHIP_ERROR_INTERNAL);
10681072

src/crypto/tests/CHIPCryptoPALTest.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,7 @@ static void TestSPAKE2P_spake2p_Mac(nlTestSuite * inSuite, void * inContext)
14141414
{
14151415
HeapChecker heapChecker(inSuite);
14161416
uint8_t mac[kMAX_Hash_Length];
1417+
MutableByteSpan mac_span{ mac };
14171418

14181419
int numOfTestVectors = ArraySize(hmac_tvs);
14191420
int numOfTestsRan = 0;
@@ -1426,10 +1427,10 @@ static void TestSPAKE2P_spake2p_Mac(nlTestSuite * inSuite, void * inContext)
14261427
CHIP_ERROR err = spake2p.Init(nullptr, 0);
14271428
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
14281429

1429-
err = spake2p.Mac(vector->key, vector->key_len, vector->input, vector->input_len, mac);
1430+
err = spake2p.Mac(vector->key, vector->key_len, vector->input, vector->input_len, mac_span);
14301431
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
14311432

1432-
NL_TEST_ASSERT(inSuite, memcmp(mac, vector->output, vector->output_len) == 0);
1433+
NL_TEST_ASSERT(inSuite, memcmp(mac_span.data(), vector->output, vector->output_len) == 0);
14331434

14341435
err = spake2p.MacVerify(vector->key, vector->key_len, vector->output, vector->output_len, vector->input, vector->input_len);
14351436
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

0 commit comments

Comments
 (0)