Skip to content

Commit 898129a

Browse files
authored
Merge pull request #18 from tianyiy-tim/test/backport-3337
Recognise known safe DH groups/primes and short-circuit Diffie-Hellman test (aws#3337)
2 parents e2ab05e + 3d41a45 commit 898129a

5 files changed

Lines changed: 404 additions & 183 deletions

File tree

crypto/dh_extra/dh_test.cc

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,98 @@ TEST(DHTest, DHCheckForStandardParams) {
10231023
EXPECT_EQ(flags, 0);
10241024
}
10251025

1026+
TEST(DHTest, DHCheckNamedGroupFastPath) {
1027+
auto make_bare_group = [](BIGNUM *p) -> bssl::UniquePtr<DH> {
1028+
bssl::UniquePtr<BIGNUM> p_owner(p);
1029+
if (p_owner == nullptr) {
1030+
return nullptr;
1031+
}
1032+
bssl::UniquePtr<BIGNUM> g(BN_new());
1033+
if (g == nullptr || !BN_set_word(g.get(), 2)) {
1034+
return nullptr;
1035+
}
1036+
// NewDHGroup does not take ownership; it dups the inputs.
1037+
return NewDHGroup(p_owner.get(), /*q=*/nullptr, g.get());
1038+
};
1039+
1040+
// All RFC 3526 MODP moduli, as a bare (p, g=2) group.
1041+
BIGNUM *(*const kRFC3526[])(BIGNUM *) = {
1042+
BN_get_rfc3526_prime_1536, BN_get_rfc3526_prime_2048,
1043+
BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096,
1044+
BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192,
1045+
};
1046+
for (auto getter : kRFC3526) {
1047+
bssl::UniquePtr<DH> dh = make_bare_group(getter(nullptr));
1048+
ASSERT_TRUE(dh);
1049+
int flags = -1;
1050+
ASSERT_TRUE(DH_check(dh.get(), &flags));
1051+
EXPECT_EQ(flags, 0);
1052+
}
1053+
1054+
// All RFC 7919 ffdhe groups. Tested twice: once in their native form (which
1055+
// carries q = (p-1)/2 and g = 2), and once as a bare (p, g=2) group. Both are
1056+
// accepted by the fast path with flags == 0.
1057+
DH *(*const kRFC7919[])(void) = {
1058+
DH_get_rfc7919_2048, DH_get_rfc7919_3072, DH_get_rfc7919_4096,
1059+
DH_get_rfc7919_8192,
1060+
};
1061+
for (auto getter : kRFC7919) {
1062+
bssl::UniquePtr<DH> group(getter());
1063+
ASSERT_TRUE(group);
1064+
int flags = -1;
1065+
ASSERT_TRUE(DH_check(group.get(), &flags));
1066+
EXPECT_EQ(flags, 0);
1067+
1068+
bssl::UniquePtr<DH> bare = make_bare_group(BN_dup(DH_get0_p(group.get())));
1069+
ASSERT_TRUE(bare);
1070+
flags = -1;
1071+
ASSERT_TRUE(DH_check(bare.get(), &flags));
1072+
EXPECT_EQ(flags, 0);
1073+
}
1074+
1075+
// A modulus that is one bit off from a named group must NOT be accepted by
1076+
// the fast path. DH_check should fall through to full validation and flag it
1077+
// as composite. This guards against the fast path masking bad parameters.
1078+
{
1079+
bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_2048(nullptr));
1080+
ASSERT_TRUE(p);
1081+
// Clear a bit that is set in the real prime so the value stays odd but is
1082+
// no longer the named prime (and is composite).
1083+
ASSERT_TRUE(BN_is_bit_set(p.get(), 5));
1084+
ASSERT_TRUE(BN_clear_bit(p.get(), 5));
1085+
bssl::UniquePtr<BIGNUM> g(BN_new());
1086+
ASSERT_TRUE(g);
1087+
ASSERT_TRUE(BN_set_word(g.get(), 2));
1088+
bssl::UniquePtr<DH> dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
1089+
ASSERT_TRUE(dh);
1090+
int flags = -1;
1091+
ASSERT_TRUE(DH_check(dh.get(), &flags));
1092+
EXPECT_TRUE(flags & DH_CHECK_P_NOT_PRIME);
1093+
}
1094+
1095+
// A recognized modulus with a q that is NOT the group's subgroup order must
1096+
// not be waved through by the fast path. Here we perturb ffdhe2048's q so it
1097+
// no longer equals (p-1)/2; the fast path must decline and full validation
1098+
// must reject it (q no longer divides p-1 and is composite).
1099+
{
1100+
bssl::UniquePtr<DH> group(DH_get_rfc7919_2048());
1101+
ASSERT_TRUE(group);
1102+
bssl::UniquePtr<BIGNUM> q(BN_dup(DH_get0_q(group.get())));
1103+
ASSERT_TRUE(q);
1104+
ASSERT_TRUE(BN_add_word(q.get(), 2)); // q := (p-1)/2 + 2, no longer valid
1105+
bssl::UniquePtr<BIGNUM> g(BN_new());
1106+
ASSERT_TRUE(g);
1107+
ASSERT_TRUE(BN_set_word(g.get(), 2));
1108+
bssl::UniquePtr<DH> dh =
1109+
NewDHGroup(DH_get0_p(group.get()), q.get(), g.get());
1110+
ASSERT_TRUE(dh);
1111+
int flags = -1;
1112+
ASSERT_TRUE(DH_check(dh.get(), &flags));
1113+
// If the fast path had wrongly accepted this, flags would be 0.
1114+
EXPECT_TRUE(flags & DH_CHECK_INVALID_Q_VALUE);
1115+
}
1116+
}
1117+
10261118
TEST(DHTest, DHMarshalPubKey) {
10271119
const char* dh512_pem =
10281120
"-----BEGIN DH PARAMETERS-----\n"

0 commit comments

Comments
 (0)