Skip to content

Commit 110f184

Browse files
dkosticskmcgrail
authored andcommitted
Reject XOF digests in DH_compute_key_hashed
DH_compute_key_hashed passes an uninitialized out_len to EVP_Digest. For XOF digests, EVP_DigestFinalXOF interprets *out_size as an input length, which can cause an out-of-bounds write to the caller-provided buffer. Reject XOF digests and initialize out_len to the fixed digest size. We would like to thank Joshua Rogers (https://joshua.hu/) of AISLE Research Team (https://aisle.com/) for reporting this issue.
1 parent 8a43348 commit 110f184

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

crypto/dh_extra/dh_test.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include <openssl/bytestring.h>
6868
#include <openssl/crypto.h>
6969
#include <openssl/dh.h>
70+
#include <openssl/digest.h>
7071
#include <openssl/err.h>
7172
#include <openssl/mem.h>
7273
#include <openssl/nid.h>
@@ -76,6 +77,29 @@
7677
#include "openssl/pem.h"
7778

7879

80+
TEST(DHTest, ComputeKeyHashedRejectsXOF) {
81+
bssl::UniquePtr<DH> a(DH_new_by_nid(NID_ffdhe2048));
82+
ASSERT_TRUE(a);
83+
bssl::UniquePtr<DH> b(DHparams_dup(a.get()));
84+
ASSERT_TRUE(b);
85+
ASSERT_TRUE(DH_generate_key(a.get()));
86+
ASSERT_TRUE(DH_generate_key(b.get()));
87+
88+
uint8_t out[64];
89+
size_t out_len = 0;
90+
91+
// XOF digests should be rejected.
92+
EXPECT_FALSE(DH_compute_key_hashed(a.get(), out, &out_len, sizeof(out),
93+
DH_get0_pub_key(b.get()), EVP_shake128()));
94+
EXPECT_FALSE(DH_compute_key_hashed(a.get(), out, &out_len, sizeof(out),
95+
DH_get0_pub_key(b.get()), EVP_shake256()));
96+
97+
// Non-XOF digests should succeed.
98+
EXPECT_TRUE(DH_compute_key_hashed(a.get(), out, &out_len, sizeof(out),
99+
DH_get0_pub_key(b.get()), EVP_sha256()));
100+
EXPECT_EQ(out_len, 32u);
101+
}
102+
79103
TEST(DHTest, Basic) {
80104
bssl::UniquePtr<DH> a(DH_new());
81105
ASSERT_TRUE(a);

crypto/fipsmodule/dh/dh.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* [including the GNU Public Licence.] */
5656

5757
#include <openssl/dh.h>
58+
#include <limits.h>
5859

5960
#include <string.h>
6061

@@ -447,7 +448,11 @@ int DH_compute_key_hashed(DH *dh, uint8_t *out, size_t *out_len,
447448
*out_len = SIZE_MAX;
448449

449450
const size_t digest_len = EVP_MD_size(digest);
450-
if (digest_len > max_out_len) {
451+
if (digest_len == 0 || digest_len > max_out_len
452+
#if SIZE_MAX > UINT_MAX
453+
|| digest_len > UINT_MAX
454+
#endif
455+
) {
451456
return 0;
452457
}
453458

@@ -458,7 +463,7 @@ int DH_compute_key_hashed(DH *dh, uint8_t *out, size_t *out_len,
458463
int ret = 0;
459464
const size_t dh_len = DH_size(dh);
460465
uint8_t *shared_bytes = OPENSSL_malloc(dh_len);
461-
unsigned out_len_unsigned;
466+
unsigned out_len_unsigned = (unsigned)digest_len;
462467
if (!shared_bytes ||
463468
// SP 800-56A is ambiguous about whether the output should be padded prior
464469
// to revision three. But revision three, section C.1, awkwardly specifies

0 commit comments

Comments
 (0)