xref: /aosp_15_r20/external/boringssl/src/crypto/dh_extra/dh_test.cc (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (C) 1995-1998 Eric Young ([email protected])
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young ([email protected]).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson ([email protected]).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young ([email protected])"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson ([email protected])"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/dh.h>
58 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include <vector>
63 
64 #include <gtest/gtest.h>
65 
66 #include <openssl/bn.h>
67 #include <openssl/bytestring.h>
68 #include <openssl/crypto.h>
69 #include <openssl/dh.h>
70 #include <openssl/err.h>
71 #include <openssl/mem.h>
72 
73 #include "../fipsmodule/dh/internal.h"
74 #include "../test/test_util.h"
75 
76 
TEST(DHTest,Basic)77 TEST(DHTest, Basic) {
78   bssl::UniquePtr<DH> a(DH_new());
79   ASSERT_TRUE(a);
80   ASSERT_TRUE(DH_generate_parameters_ex(a.get(), 64, DH_GENERATOR_5, nullptr));
81 
82   int check_result;
83   ASSERT_TRUE(DH_check(a.get(), &check_result));
84   EXPECT_FALSE(check_result & DH_CHECK_P_NOT_PRIME);
85   EXPECT_FALSE(check_result & DH_CHECK_P_NOT_SAFE_PRIME);
86   EXPECT_FALSE(check_result & DH_CHECK_UNABLE_TO_CHECK_GENERATOR);
87   EXPECT_FALSE(check_result & DH_CHECK_NOT_SUITABLE_GENERATOR);
88 
89   bssl::UniquePtr<DH> b(DHparams_dup(a.get()));
90   ASSERT_TRUE(b);
91 
92   ASSERT_TRUE(DH_generate_key(a.get()));
93   ASSERT_TRUE(DH_generate_key(b.get()));
94 
95   std::vector<uint8_t> key1(DH_size(a.get()));
96   int ret = DH_compute_key(key1.data(), DH_get0_pub_key(b.get()), a.get());
97   ASSERT_GE(ret, 0);
98   key1.resize(ret);
99 
100   std::vector<uint8_t> key2(DH_size(b.get()));
101   ret = DH_compute_key(key2.data(), DH_get0_pub_key(a.get()), b.get());
102   ASSERT_GE(ret, 0);
103   key2.resize(ret);
104 
105   EXPECT_EQ(Bytes(key1), Bytes(key2));
106 
107   // |DH_compute_key|, unlike |DH_compute_key_padded|, removes leading zeros
108   // from the output, so the key will not have a fixed length. This test uses a
109   // small, 64-bit prime, so check for at least 32 bits of output after removing
110   // leading zeros.
111   EXPECT_GE(key1.size(), 4u);
112 }
113 
114 // The following parameters are taken from RFC 5114, section 2.2. This is not a
115 // safe prime. Do not use these parameters.
116 static const uint8_t kRFC5114_2048_224P[] = {
117     0xad, 0x10, 0x7e, 0x1e, 0x91, 0x23, 0xa9, 0xd0, 0xd6, 0x60, 0xfa, 0xa7,
118     0x95, 0x59, 0xc5, 0x1f, 0xa2, 0x0d, 0x64, 0xe5, 0x68, 0x3b, 0x9f, 0xd1,
119     0xb5, 0x4b, 0x15, 0x97, 0xb6, 0x1d, 0x0a, 0x75, 0xe6, 0xfa, 0x14, 0x1d,
120     0xf9, 0x5a, 0x56, 0xdb, 0xaf, 0x9a, 0x3c, 0x40, 0x7b, 0xa1, 0xdf, 0x15,
121     0xeb, 0x3d, 0x68, 0x8a, 0x30, 0x9c, 0x18, 0x0e, 0x1d, 0xe6, 0xb8, 0x5a,
122     0x12, 0x74, 0xa0, 0xa6, 0x6d, 0x3f, 0x81, 0x52, 0xad, 0x6a, 0xc2, 0x12,
123     0x90, 0x37, 0xc9, 0xed, 0xef, 0xda, 0x4d, 0xf8, 0xd9, 0x1e, 0x8f, 0xef,
124     0x55, 0xb7, 0x39, 0x4b, 0x7a, 0xd5, 0xb7, 0xd0, 0xb6, 0xc1, 0x22, 0x07,
125     0xc9, 0xf9, 0x8d, 0x11, 0xed, 0x34, 0xdb, 0xf6, 0xc6, 0xba, 0x0b, 0x2c,
126     0x8b, 0xbc, 0x27, 0xbe, 0x6a, 0x00, 0xe0, 0xa0, 0xb9, 0xc4, 0x97, 0x08,
127     0xb3, 0xbf, 0x8a, 0x31, 0x70, 0x91, 0x88, 0x36, 0x81, 0x28, 0x61, 0x30,
128     0xbc, 0x89, 0x85, 0xdb, 0x16, 0x02, 0xe7, 0x14, 0x41, 0x5d, 0x93, 0x30,
129     0x27, 0x82, 0x73, 0xc7, 0xde, 0x31, 0xef, 0xdc, 0x73, 0x10, 0xf7, 0x12,
130     0x1f, 0xd5, 0xa0, 0x74, 0x15, 0x98, 0x7d, 0x9a, 0xdc, 0x0a, 0x48, 0x6d,
131     0xcd, 0xf9, 0x3a, 0xcc, 0x44, 0x32, 0x83, 0x87, 0x31, 0x5d, 0x75, 0xe1,
132     0x98, 0xc6, 0x41, 0xa4, 0x80, 0xcd, 0x86, 0xa1, 0xb9, 0xe5, 0x87, 0xe8,
133     0xbe, 0x60, 0xe6, 0x9c, 0xc9, 0x28, 0xb2, 0xb9, 0xc5, 0x21, 0x72, 0xe4,
134     0x13, 0x04, 0x2e, 0x9b, 0x23, 0xf1, 0x0b, 0x0e, 0x16, 0xe7, 0x97, 0x63,
135     0xc9, 0xb5, 0x3d, 0xcf, 0x4b, 0xa8, 0x0a, 0x29, 0xe3, 0xfb, 0x73, 0xc1,
136     0x6b, 0x8e, 0x75, 0xb9, 0x7e, 0xf3, 0x63, 0xe2, 0xff, 0xa3, 0x1f, 0x71,
137     0xcf, 0x9d, 0xe5, 0x38, 0x4e, 0x71, 0xb8, 0x1c, 0x0a, 0xc4, 0xdf, 0xfe,
138     0x0c, 0x10, 0xe6, 0x4f,
139 };
140 static const uint8_t kRFC5114_2048_224G[] = {
141     0xac, 0x40, 0x32, 0xef, 0x4f, 0x2d, 0x9a, 0xe3, 0x9d, 0xf3, 0x0b, 0x5c,
142     0x8f, 0xfd, 0xac, 0x50, 0x6c, 0xde, 0xbe, 0x7b, 0x89, 0x99, 0x8c, 0xaf,
143     0x74, 0x86, 0x6a, 0x08, 0xcf, 0xe4, 0xff, 0xe3, 0xa6, 0x82, 0x4a, 0x4e,
144     0x10, 0xb9, 0xa6, 0xf0, 0xdd, 0x92, 0x1f, 0x01, 0xa7, 0x0c, 0x4a, 0xfa,
145     0xab, 0x73, 0x9d, 0x77, 0x00, 0xc2, 0x9f, 0x52, 0xc5, 0x7d, 0xb1, 0x7c,
146     0x62, 0x0a, 0x86, 0x52, 0xbe, 0x5e, 0x90, 0x01, 0xa8, 0xd6, 0x6a, 0xd7,
147     0xc1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4a, 0xf4, 0xd0, 0x27, 0x27,
148     0x5a, 0xc1, 0x34, 0x8b, 0xb8, 0xa7, 0x62, 0xd0, 0x52, 0x1b, 0xc9, 0x8a,
149     0xe2, 0x47, 0x15, 0x04, 0x22, 0xea, 0x1e, 0xd4, 0x09, 0x93, 0x9d, 0x54,
150     0xda, 0x74, 0x60, 0xcd, 0xb5, 0xf6, 0xc6, 0xb2, 0x50, 0x71, 0x7c, 0xbe,
151     0xf1, 0x80, 0xeb, 0x34, 0x11, 0x8e, 0x98, 0xd1, 0x19, 0x52, 0x9a, 0x45,
152     0xd6, 0xf8, 0x34, 0x56, 0x6e, 0x30, 0x25, 0xe3, 0x16, 0xa3, 0x30, 0xef,
153     0xbb, 0x77, 0xa8, 0x6f, 0x0c, 0x1a, 0xb1, 0x5b, 0x05, 0x1a, 0xe3, 0xd4,
154     0x28, 0xc8, 0xf8, 0xac, 0xb7, 0x0a, 0x81, 0x37, 0x15, 0x0b, 0x8e, 0xeb,
155     0x10, 0xe1, 0x83, 0xed, 0xd1, 0x99, 0x63, 0xdd, 0xd9, 0xe2, 0x63, 0xe4,
156     0x77, 0x05, 0x89, 0xef, 0x6a, 0xa2, 0x1e, 0x7f, 0x5f, 0x2f, 0xf3, 0x81,
157     0xb5, 0x39, 0xcc, 0xe3, 0x40, 0x9d, 0x13, 0xcd, 0x56, 0x6a, 0xfb, 0xb4,
158     0x8d, 0x6c, 0x01, 0x91, 0x81, 0xe1, 0xbc, 0xfe, 0x94, 0xb3, 0x02, 0x69,
159     0xed, 0xfe, 0x72, 0xfe, 0x9b, 0x6a, 0xa4, 0xbd, 0x7b, 0x5a, 0x0f, 0x1c,
160     0x71, 0xcf, 0xff, 0x4c, 0x19, 0xc4, 0x18, 0xe1, 0xf6, 0xec, 0x01, 0x79,
161     0x81, 0xbc, 0x08, 0x7f, 0x2a, 0x70, 0x65, 0xb3, 0x84, 0xb8, 0x90, 0xd3,
162     0x19, 0x1f, 0x2b, 0xfa,
163 };
164 static const uint8_t kRFC5114_2048_224Q[] = {
165     0x80, 0x1c, 0x0d, 0x34, 0xc5, 0x8d, 0x93, 0xfe, 0x99, 0x71,
166     0x77, 0x10, 0x1f, 0x80, 0x53, 0x5a, 0x47, 0x38, 0xce, 0xbc,
167     0xbf, 0x38, 0x9a, 0x99, 0xb3, 0x63, 0x71, 0xeb,
168 };
169 
170 // kRFC5114_2048_224BadY is a bad y-coordinate for RFC 5114's 2048-bit MODP
171 // Group with 224-bit Prime Order Subgroup (section 2.2).
172 static const uint8_t kRFC5114_2048_224BadY[] = {
173     0x45, 0x32, 0x5f, 0x51, 0x07, 0xe5, 0xdf, 0x1c, 0xd6, 0x02, 0x82, 0xb3,
174     0x32, 0x8f, 0xa4, 0x0f, 0x87, 0xb8, 0x41, 0xfe, 0xb9, 0x35, 0xde, 0xad,
175     0xc6, 0x26, 0x85, 0xb4, 0xff, 0x94, 0x8c, 0x12, 0x4c, 0xbf, 0x5b, 0x20,
176     0xc4, 0x46, 0xa3, 0x26, 0xeb, 0xa4, 0x25, 0xb7, 0x68, 0x8e, 0xcc, 0x67,
177     0xba, 0xea, 0x58, 0xd0, 0xf2, 0xe9, 0xd2, 0x24, 0x72, 0x60, 0xda, 0x88,
178     0x18, 0x9c, 0xe0, 0x31, 0x6a, 0xad, 0x50, 0x6d, 0x94, 0x35, 0x8b, 0x83,
179     0x4a, 0x6e, 0xfa, 0x48, 0x73, 0x0f, 0x83, 0x87, 0xff, 0x6b, 0x66, 0x1f,
180     0xa8, 0x82, 0xc6, 0x01, 0xe5, 0x80, 0xb5, 0xb0, 0x52, 0xd0, 0xe9, 0xd8,
181     0x72, 0xf9, 0x7d, 0x5b, 0x8b, 0xa5, 0x4c, 0xa5, 0x25, 0x95, 0x74, 0xe2,
182     0x7a, 0x61, 0x4e, 0xa7, 0x8f, 0x12, 0xe2, 0xd2, 0x9d, 0x8c, 0x02, 0x70,
183     0x34, 0x44, 0x32, 0xc7, 0xb2, 0xf3, 0xb9, 0xfe, 0x17, 0x2b, 0xd6, 0x1f,
184     0x8b, 0x7e, 0x4a, 0xfa, 0xa3, 0xb5, 0x3e, 0x7a, 0x81, 0x9a, 0x33, 0x66,
185     0x62, 0xa4, 0x50, 0x18, 0x3e, 0xa2, 0x5f, 0x00, 0x07, 0xd8, 0x9b, 0x22,
186     0xe4, 0xec, 0x84, 0xd5, 0xeb, 0x5a, 0xf3, 0x2a, 0x31, 0x23, 0xd8, 0x44,
187     0x22, 0x2a, 0x8b, 0x37, 0x44, 0xcc, 0xc6, 0x87, 0x4b, 0xbe, 0x50, 0x9d,
188     0x4a, 0xc4, 0x8e, 0x45, 0xcf, 0x72, 0x4d, 0xc0, 0x89, 0xb3, 0x72, 0xed,
189     0x33, 0x2c, 0xbc, 0x7f, 0x16, 0x39, 0x3b, 0xeb, 0xd2, 0xdd, 0xa8, 0x01,
190     0x73, 0x84, 0x62, 0xb9, 0x29, 0xd2, 0xc9, 0x51, 0x32, 0x9e, 0x7a, 0x6a,
191     0xcf, 0xc1, 0x0a, 0xdb, 0x0e, 0xe0, 0x62, 0x77, 0x6f, 0x59, 0x62, 0x72,
192     0x5a, 0x69, 0xa6, 0x5b, 0x70, 0xca, 0x65, 0xc4, 0x95, 0x6f, 0x9a, 0xc2,
193     0xdf, 0x72, 0x6d, 0xb1, 0x1e, 0x54, 0x7b, 0x51, 0xb4, 0xef, 0x7f, 0x89,
194     0x93, 0x74, 0x89, 0x59,
195 };
196 
NewDHGroup(const BIGNUM * p,const BIGNUM * q,const BIGNUM * g)197 static bssl::UniquePtr<DH> NewDHGroup(const BIGNUM *p, const BIGNUM *q,
198                                       const BIGNUM *g) {
199   bssl::UniquePtr<BIGNUM> p_copy(BN_dup(p));
200   bssl::UniquePtr<BIGNUM> q_copy(q != nullptr ? BN_dup(q) : nullptr);
201   bssl::UniquePtr<BIGNUM> g_copy(BN_dup(g));
202   bssl::UniquePtr<DH> dh(DH_new());
203   if (p_copy == nullptr || (q != nullptr && q_copy == nullptr) ||
204       g_copy == nullptr || dh == nullptr ||
205       !DH_set0_pqg(dh.get(), p_copy.get(), q_copy.get(), g_copy.get())) {
206     return nullptr;
207   }
208   p_copy.release();
209   q_copy.release();
210   g_copy.release();
211   return dh;
212 }
213 
TEST(DHTest,BadY)214 TEST(DHTest, BadY) {
215   bssl::UniquePtr<BIGNUM> p(
216       BN_bin2bn(kRFC5114_2048_224P, sizeof(kRFC5114_2048_224P), nullptr));
217   bssl::UniquePtr<BIGNUM> q(
218       BN_bin2bn(kRFC5114_2048_224Q, sizeof(kRFC5114_2048_224Q), nullptr));
219   bssl::UniquePtr<BIGNUM> g(
220       BN_bin2bn(kRFC5114_2048_224G, sizeof(kRFC5114_2048_224G), nullptr));
221   ASSERT_TRUE(p);
222   ASSERT_TRUE(q);
223   ASSERT_TRUE(g);
224   bssl::UniquePtr<DH> dh = NewDHGroup(p.get(), q.get(), g.get());
225   ASSERT_TRUE(dh);
226 
227   bssl::UniquePtr<BIGNUM> pub_key(
228       BN_bin2bn(kRFC5114_2048_224BadY, sizeof(kRFC5114_2048_224BadY), nullptr));
229   ASSERT_TRUE(pub_key);
230   ASSERT_TRUE(DH_generate_key(dh.get()));
231 
232   int flags;
233   ASSERT_TRUE(DH_check_pub_key(dh.get(), pub_key.get(), &flags));
234   EXPECT_TRUE(flags & DH_CHECK_PUBKEY_INVALID)
235       << "DH_check_pub_key did not reject the key";
236 
237   std::vector<uint8_t> result(DH_size(dh.get()));
238   EXPECT_LT(DH_compute_key(result.data(), pub_key.get(), dh.get()), 0)
239       << "DH_compute_key unexpectedly succeeded";
240   ERR_clear_error();
241 }
242 
BIGNUMEqualsHex(const BIGNUM * bn,const char * hex)243 static bool BIGNUMEqualsHex(const BIGNUM *bn, const char *hex) {
244   BIGNUM *hex_bn = NULL;
245   if (!BN_hex2bn(&hex_bn, hex)) {
246     return false;
247   }
248   bssl::UniquePtr<BIGNUM> free_hex_bn(hex_bn);
249   return BN_cmp(bn, hex_bn) == 0;
250 }
251 
TEST(DHTest,ASN1)252 TEST(DHTest, ASN1) {
253   // kParams are a set of Diffie-Hellman parameters generated with
254   // openssl dhparam 256
255   static const uint8_t kParams[] = {
256       0x30, 0x26, 0x02, 0x21, 0x00, 0xd7, 0x20, 0x34, 0xa3, 0x27,
257       0x4f, 0xdf, 0xbf, 0x04, 0xfd, 0x24, 0x68, 0x25, 0xb6, 0x56,
258       0xd8, 0xab, 0x2a, 0x41, 0x2d, 0x74, 0x0a, 0x52, 0x08, 0x7c,
259       0x40, 0x71, 0x4e, 0xd2, 0x57, 0x93, 0x13, 0x02, 0x01, 0x02,
260   };
261 
262   CBS cbs;
263   CBS_init(&cbs, kParams, sizeof(kParams));
264   bssl::UniquePtr<DH> dh(DH_parse_parameters(&cbs));
265   ASSERT_TRUE(dh);
266   EXPECT_EQ(CBS_len(&cbs), 0u);
267   EXPECT_TRUE(BIGNUMEqualsHex(
268       DH_get0_p(dh.get()),
269       "d72034a3274fdfbf04fd246825b656d8ab2a412d740a52087c40714ed2579313"));
270   EXPECT_TRUE(BIGNUMEqualsHex(DH_get0_g(dh.get()), "2"));
271   EXPECT_EQ(dh->priv_length, 0u);
272 
273   bssl::ScopedCBB cbb;
274   uint8_t *der;
275   size_t der_len;
276   ASSERT_TRUE(CBB_init(cbb.get(), 0));
277   ASSERT_TRUE(DH_marshal_parameters(cbb.get(), dh.get()));
278   ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
279   bssl::UniquePtr<uint8_t> free_der(der);
280   EXPECT_EQ(Bytes(kParams), Bytes(der, der_len));
281 
282   // kParamsDSA are a set of Diffie-Hellman parameters generated with
283   // openssl dhparam 256 -dsaparam
284   static const uint8_t kParamsDSA[] = {
285       0x30, 0x81, 0x89, 0x02, 0x41, 0x00, 0x93, 0xf3, 0xc1, 0x18, 0x01, 0xe6,
286       0x62, 0xb6, 0xd1, 0x46, 0x9a, 0x2c, 0x72, 0xea, 0x31, 0xd9, 0x18, 0x10,
287       0x30, 0x28, 0x63, 0xe2, 0x34, 0x7d, 0x80, 0xca, 0xee, 0x82, 0x2b, 0x19,
288       0x3c, 0x19, 0xbb, 0x42, 0x83, 0x02, 0x70, 0xdd, 0xdb, 0x8c, 0x03, 0xab,
289       0xe9, 0x9c, 0xc4, 0x00, 0x4d, 0x70, 0x5f, 0x52, 0x03, 0x31, 0x2c, 0xa4,
290       0x67, 0x34, 0x51, 0x95, 0x2a, 0xac, 0x11, 0xe2, 0x6a, 0x55, 0x02, 0x40,
291       0x44, 0xc8, 0x10, 0x53, 0x44, 0x32, 0x31, 0x63, 0xd8, 0xd1, 0x8c, 0x75,
292       0xc8, 0x98, 0x53, 0x3b, 0x5b, 0x4a, 0x2a, 0x0a, 0x09, 0xe7, 0xd0, 0x3c,
293       0x53, 0x72, 0xa8, 0x6b, 0x70, 0x41, 0x9c, 0x26, 0x71, 0x44, 0xfc, 0x7f,
294       0x08, 0x75, 0xe1, 0x02, 0xab, 0x74, 0x41, 0xe8, 0x2a, 0x3d, 0x3c, 0x26,
295       0x33, 0x09, 0xe4, 0x8b, 0xb4, 0x41, 0xec, 0xa6, 0xa8, 0xba, 0x1a, 0x07,
296       0x8a, 0x77, 0xf5, 0x5f, 0x02, 0x02, 0x00, 0xa0,
297   };
298 
299   CBS_init(&cbs, kParamsDSA, sizeof(kParamsDSA));
300   dh.reset(DH_parse_parameters(&cbs));
301   ASSERT_TRUE(dh);
302   EXPECT_EQ(CBS_len(&cbs), 0u);
303   EXPECT_TRUE(
304       BIGNUMEqualsHex(DH_get0_p(dh.get()),
305                       "93f3c11801e662b6d1469a2c72ea31d91810302863e2347d80caee8"
306                       "22b193c19bb42830270dddb8c03abe99cc4004d705f5203312ca467"
307                       "3451952aac11e26a55"));
308   EXPECT_TRUE(
309       BIGNUMEqualsHex(DH_get0_g(dh.get()),
310                       "44c8105344323163d8d18c75c898533b5b4a2a0a09e7d03c5372a86"
311                       "b70419c267144fc7f0875e102ab7441e82a3d3c263309e48bb441ec"
312                       "a6a8ba1a078a77f55f"));
313   EXPECT_EQ(dh->priv_length, 160u);
314 
315   ASSERT_TRUE(CBB_init(cbb.get(), 0));
316   ASSERT_TRUE(DH_marshal_parameters(cbb.get(), dh.get()));
317   ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
318   bssl::UniquePtr<uint8_t> free_der2(der);
319   EXPECT_EQ(Bytes(kParamsDSA), Bytes(der, der_len));
320 }
321 
TEST(DHTest,RFC3526)322 TEST(DHTest, RFC3526) {
323   bssl::UniquePtr<BIGNUM> bn(BN_get_rfc3526_prime_1536(nullptr));
324   ASSERT_TRUE(bn);
325 
326   static const uint8_t kPrime1536[] = {
327       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2,
328       0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
329       0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
330       0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
331       0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d,
332       0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
333       0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9,
334       0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
335       0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11,
336       0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d,
337       0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36,
338       0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
339       0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56,
340       0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d,
341       0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08,
342       0xca, 0x23, 0x73, 0x27, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
343   };
344 
345   uint8_t buffer[sizeof(kPrime1536)];
346   ASSERT_EQ(BN_num_bytes(bn.get()), sizeof(kPrime1536));
347   ASSERT_EQ(BN_bn2bin(bn.get(), buffer), sizeof(kPrime1536));
348   EXPECT_EQ(Bytes(buffer), Bytes(kPrime1536));
349 }
350 
TEST(DHTest,LeadingZeros)351 TEST(DHTest, LeadingZeros) {
352   bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_1536(nullptr));
353   ASSERT_TRUE(p);
354   bssl::UniquePtr<BIGNUM> g(BN_new());
355   ASSERT_TRUE(g);
356   ASSERT_TRUE(BN_set_word(g.get(), 2));
357 
358   bssl::UniquePtr<DH> dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
359   ASSERT_TRUE(dh);
360 
361   // These values are far too small to be reasonable Diffie-Hellman keys, but
362   // they are an easy way to get a shared secret with leading zeros.
363   bssl::UniquePtr<BIGNUM> priv_key(BN_new()), peer_key(BN_new());
364   ASSERT_TRUE(priv_key);
365   ASSERT_TRUE(BN_set_word(priv_key.get(), 2));
366   ASSERT_TRUE(peer_key);
367   ASSERT_TRUE(BN_set_word(peer_key.get(), 3));
368   ASSERT_TRUE(DH_set0_key(dh.get(), /*pub_key=*/nullptr, priv_key.get()));
369   priv_key.release();
370 
371   uint8_t padded[192] = {0};
372   padded[191] = 9;
373   static const uint8_t kTruncated[] = {9};
374   EXPECT_EQ(int(sizeof(padded)), DH_size(dh.get()));
375 
376   std::vector<uint8_t> buf(DH_size(dh.get()));
377   int len = DH_compute_key(buf.data(), peer_key.get(), dh.get());
378   ASSERT_GT(len, 0);
379   EXPECT_EQ(Bytes(buf.data(), len), Bytes(kTruncated));
380 
381   len = DH_compute_key_padded(buf.data(), peer_key.get(), dh.get());
382   ASSERT_GT(len, 0);
383   EXPECT_EQ(Bytes(buf.data(), len), Bytes(padded));
384 }
385 
TEST(DHTest,Overwrite)386 TEST(DHTest, Overwrite) {
387   // Generate a DH key with the 1536-bit MODP group.
388   bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_1536(nullptr));
389   ASSERT_TRUE(p);
390   bssl::UniquePtr<BIGNUM> g(BN_new());
391   ASSERT_TRUE(g);
392   ASSERT_TRUE(BN_set_word(g.get(), 2));
393 
394   bssl::UniquePtr<DH> key1 = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
395   ASSERT_TRUE(key1);
396   ASSERT_TRUE(DH_generate_key(key1.get()));
397 
398   bssl::UniquePtr<BIGNUM> peer_key(BN_new());
399   ASSERT_TRUE(peer_key);
400   ASSERT_TRUE(BN_set_word(peer_key.get(), 42));
401 
402   // Use the key to fill in cached values.
403   std::vector<uint8_t> buf1(DH_size(key1.get()));
404   ASSERT_GT(DH_compute_key_padded(buf1.data(), peer_key.get(), key1.get()), 0);
405 
406   // Generate a different key with a different group.
407   p.reset(BN_get_rfc3526_prime_2048(nullptr));
408   ASSERT_TRUE(p);
409   bssl::UniquePtr<DH> key2 = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
410   ASSERT_TRUE(key2);
411   ASSERT_TRUE(DH_generate_key(key2.get()));
412 
413   // Overwrite |key1|'s contents with |key2|.
414   p.reset(BN_dup(DH_get0_p(key2.get())));
415   ASSERT_TRUE(p);
416   g.reset(BN_dup(DH_get0_g(key2.get())));
417   ASSERT_TRUE(g);
418   bssl::UniquePtr<BIGNUM> pub(BN_dup(DH_get0_pub_key(key2.get())));
419   ASSERT_TRUE(pub);
420   bssl::UniquePtr<BIGNUM> priv(BN_dup(DH_get0_priv_key(key2.get())));
421   ASSERT_TRUE(priv);
422   ASSERT_TRUE(DH_set0_pqg(key1.get(), p.get(), /*q=*/nullptr, g.get()));
423   p.release();
424   g.release();
425   ASSERT_TRUE(DH_set0_key(key1.get(), pub.get(), priv.get()));
426   pub.release();
427   priv.release();
428 
429   // Verify that |key1| and |key2| behave equivalently.
430   buf1.resize(DH_size(key1.get()));
431   ASSERT_GT(DH_compute_key_padded(buf1.data(), peer_key.get(), key1.get()), 0);
432   std::vector<uint8_t> buf2(DH_size(key2.get()));
433   ASSERT_GT(DH_compute_key_padded(buf2.data(), peer_key.get(), key2.get()), 0);
434   EXPECT_EQ(Bytes(buf1), Bytes(buf2));
435 }
436 
TEST(DHTest,GenerateKeyTwice)437 TEST(DHTest, GenerateKeyTwice) {
438   bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_2048(nullptr));
439   ASSERT_TRUE(p);
440   bssl::UniquePtr<BIGNUM> g(BN_new());
441   ASSERT_TRUE(g);
442   ASSERT_TRUE(BN_set_word(g.get(), 2));
443   bssl::UniquePtr<DH> key1 = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
444   ASSERT_TRUE(key1);
445   ASSERT_TRUE(DH_generate_key(key1.get()));
446 
447   // Copy the parameters and private key to a new DH object.
448   bssl::UniquePtr<DH> key2(DHparams_dup(key1.get()));
449   ASSERT_TRUE(key2);
450   bssl::UniquePtr<BIGNUM> priv_key(BN_dup(DH_get0_priv_key(key1.get())));
451   ASSERT_TRUE(DH_set0_key(key2.get(), /*pub_key=*/NULL, priv_key.get()));
452   priv_key.release();
453 
454   // This time, calling |DH_generate_key| preserves the old key and recomputes
455   // the public key.
456   ASSERT_TRUE(DH_generate_key(key2.get()));
457   EXPECT_EQ(BN_cmp(DH_get0_priv_key(key1.get()), DH_get0_priv_key(key2.get())),
458             0);
459   EXPECT_EQ(BN_cmp(DH_get0_pub_key(key1.get()), DH_get0_pub_key(key2.get())),
460             0);
461 }
462 
463 // Bad parameters should be rejected, rather than cause a DoS risk in the
464 // event that an application uses Diffie-Hellman incorrectly, with untrusted
465 // domain parameters.
TEST(DHTest,InvalidParameters)466 TEST(DHTest, InvalidParameters) {
467   auto check_invalid_group = [](DH *dh) {
468     // All operations on egregiously invalid groups should fail.
469     EXPECT_FALSE(DH_generate_key(dh));
470     int check_result;
471     EXPECT_FALSE(DH_check(dh, &check_result));
472     bssl::UniquePtr<BIGNUM> pub_key(BN_new());
473     ASSERT_TRUE(pub_key);
474     ASSERT_TRUE(BN_set_u64(pub_key.get(), 42));
475     EXPECT_FALSE(DH_check_pub_key(dh, pub_key.get(), &check_result));
476     uint8_t buf[1024];
477     EXPECT_EQ(DH_compute_key(buf, pub_key.get(), dh), -1);
478     EXPECT_EQ(DH_compute_key_padded(buf, pub_key.get(), dh), -1);
479   };
480 
481   bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_2048(nullptr));
482   ASSERT_TRUE(p);
483   bssl::UniquePtr<BIGNUM> g(BN_new());
484   ASSERT_TRUE(g);
485   ASSERT_TRUE(BN_set_word(g.get(), 2));
486 
487   // p is negative.
488   BN_set_negative(p.get(), 1);
489   bssl::UniquePtr<DH> dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
490   ASSERT_TRUE(dh);
491   BN_set_negative(p.get(), 0);
492   check_invalid_group(dh.get());
493 
494   // g is negative.
495   BN_set_negative(g.get(), 1);
496   dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
497   ASSERT_TRUE(dh);
498   BN_set_negative(g.get(), 0);
499   check_invalid_group(dh.get());
500 
501   // g is not reduced mod p.
502   dh = NewDHGroup(p.get(), /*q=*/nullptr, p.get());
503   ASSERT_TRUE(dh);
504   BN_set_negative(g.get(), 0);
505   check_invalid_group(dh.get());
506 
507   // p is too large.
508   bssl::UniquePtr<BIGNUM> large(BN_new());
509   ASSERT_TRUE(BN_set_bit(large.get(), 0));
510   ASSERT_TRUE(BN_set_bit(large.get(), 10000000));
511   dh = NewDHGroup(large.get(), /*q=*/nullptr, g.get());
512   ASSERT_TRUE(dh);
513   check_invalid_group(dh.get());
514 
515   // q is too large.
516   dh = NewDHGroup(p.get(), large.get(), g.get());
517   ASSERT_TRUE(dh);
518   check_invalid_group(dh.get());
519 
520   // Attempting to generate too large of a Diffie-Hellman group should fail.
521   EXPECT_FALSE(
522       DH_generate_parameters_ex(dh.get(), 20000, DH_GENERATOR_5, nullptr));
523 }
524 
TEST(DHTest,PrivateKeyLength)525 TEST(DHTest, PrivateKeyLength) {
526   // Use a custom P, rather than one of the MODP primes, to pick one which does
527   // not begin with all ones. Otherwise some of the tests for boundary
528   // conditions below will not notice mistakes.
529   static const uint8_t kP[] = {
530       0xb6, 0xfa, 0x00, 0x07, 0x0a, 0x1f, 0xfb, 0x28, 0x7e, 0x6e, 0x6a, 0x97,
531       0xca, 0xa4, 0x6d, 0xf5, 0x25, 0x84, 0x76, 0xc6, 0xc4, 0xa5, 0x47, 0xb6,
532       0xb2, 0x7d, 0x76, 0x46, 0xf2, 0xb5, 0x7c, 0xc6, 0xc6, 0xb4, 0xb4, 0x82,
533       0xc5, 0xed, 0x7b, 0xd9, 0x30, 0x6e, 0x41, 0xdb, 0x7f, 0x93, 0x2f, 0xb5,
534       0x85, 0xa7, 0x38, 0x9e, 0x08, 0xc4, 0x25, 0x92, 0x7d, 0x5d, 0x2b, 0x77,
535       0x09, 0xe0, 0x2f, 0x4e, 0x14, 0x36, 0x8a, 0x08, 0x0b, 0xfd, 0x89, 0x22,
536       0x47, 0xb4, 0xbd, 0xff, 0x79, 0x4e, 0x78, 0x66, 0x2a, 0x77, 0x74, 0xbd,
537       0x85, 0xb6, 0xce, 0x5a, 0x89, 0xb7, 0x60, 0xc3, 0x8d, 0x2a, 0x1f, 0xb7,
538       0x30, 0x33, 0x1a, 0xc4, 0x51, 0xa8, 0x18, 0x62, 0x40, 0xb6, 0x5a, 0xb5,
539       0x6c, 0xf5, 0xf9, 0xbc, 0x94, 0x50, 0xba, 0xeb, 0xa2, 0xe9, 0xb3, 0x99,
540       0xde, 0xf8, 0x55, 0xfd, 0xed, 0x46, 0x1b, 0x69, 0xa5, 0x6a, 0x04, 0xe3,
541       0xa9, 0x2c, 0x0c, 0x89, 0x41, 0xfe, 0xe4, 0xa0, 0x85, 0x85, 0x2c, 0x45,
542       0xf1, 0xcb, 0x96, 0x04, 0x23, 0x4a, 0x7d, 0x56, 0x38, 0xd8, 0x86, 0x9d,
543       0xfc, 0xe0, 0x33, 0x65, 0x1a, 0xff, 0x07, 0xf0, 0xfb, 0xc6, 0x5d, 0x26,
544       0xa2, 0x96, 0xd4, 0xb5, 0xe8, 0xcd, 0x48, 0xd7, 0x8e, 0x53, 0xfe, 0xcb,
545       0x4b, 0xf2, 0x3a, 0x8b, 0x35, 0x87, 0x0a, 0x79, 0xbe, 0x8d, 0x36, 0x45,
546       0x12, 0x6e, 0x1b, 0xd4, 0xa5, 0x57, 0xe0, 0x98, 0xb7, 0x59, 0xba, 0xc2,
547       0xd8, 0x2e, 0x05, 0x0f, 0xe1, 0x70, 0x39, 0x5b, 0xe6, 0x4e, 0xdb, 0xb0,
548       0xdd, 0x7e, 0xe6, 0x66, 0x13, 0x85, 0x26, 0x32, 0x27, 0xa1, 0x00, 0x7f,
549       0x6a, 0xa9, 0xda, 0x2e, 0x50, 0x25, 0x87, 0x73, 0xab, 0x71, 0xfb, 0xa0,
550       0x92, 0xba, 0x8e, 0x9c, 0x4e, 0xea, 0x18, 0x32, 0xc4, 0x02, 0x8f, 0xe8,
551       0x95, 0x9e, 0xcb, 0x9f};
552   bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
553   ASSERT_TRUE(p);
554   bssl::UniquePtr<BIGNUM> g(BN_new());
555   ASSERT_TRUE(g);
556   ASSERT_TRUE(BN_set_word(g.get(), 2));
557   bssl::UniquePtr<BIGNUM> q(BN_new());
558   ASSERT_TRUE(q);
559   ASSERT_TRUE(BN_rshift1(q.get(), p.get()));  // (p-1)/2
560 
561   EXPECT_EQ(BN_num_bits(p.get()), 2048u);
562   EXPECT_EQ(BN_num_bits(q.get()), 2047u);
563 
564   // This test will only probabilistically notice some kinds of failures, so we
565   // repeat it for several iterations.
566   constexpr unsigned kIterations = 100;
567 
568   // If the private key was chosen from the range [1, M), num_bits(priv_key)
569   // should be very close to num_bits(M), but may be a few bits short. Allow 128
570   // leading zeros, which should fail with negligible probability.
571   constexpr unsigned kMaxLeadingZeros = 128;
572 
573   for (unsigned i = 0; i < kIterations; i++) {
574     // If unspecified, the private key is bounded by q = (p-1)/2.
575     bssl::UniquePtr<DH> dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
576     ASSERT_TRUE(dh);
577     ASSERT_TRUE(DH_generate_key(dh.get()));
578     EXPECT_LT(BN_cmp(DH_get0_priv_key(dh.get()), q.get()), 0);
579     EXPECT_LE(BN_num_bits(q.get()) - kMaxLeadingZeros,
580               BN_num_bits(DH_get0_priv_key(dh.get())));
581 
582     // Setting too large of a private key length should not be a DoS vector. The
583     // key is clamped to q = (p-1)/2.
584     dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
585     ASSERT_TRUE(dh);
586     DH_set_length(dh.get(), 10000000);
587     ASSERT_TRUE(DH_generate_key(dh.get()));
588     EXPECT_LT(BN_cmp(DH_get0_priv_key(dh.get()), q.get()), 0);
589     EXPECT_LE(BN_num_bits(q.get()) - kMaxLeadingZeros,
590               BN_num_bits(DH_get0_priv_key(dh.get())));
591 
592     // A small private key size should bound the private key.
593     dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
594     ASSERT_TRUE(dh);
595     unsigned bits = 1024;
596     DH_set_length(dh.get(), bits);
597     ASSERT_TRUE(DH_generate_key(dh.get()));
598     EXPECT_LE(BN_num_bits(DH_get0_priv_key(dh.get())), bits);
599     EXPECT_LE(bits - kMaxLeadingZeros, BN_num_bits(DH_get0_priv_key(dh.get())));
600 
601     // If the private key length is num_bits(q) - 1, the length should be the
602     // limiting factor.
603     dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
604     ASSERT_TRUE(dh);
605     bits = BN_num_bits(q.get()) - 1;
606     DH_set_length(dh.get(), bits);
607     ASSERT_TRUE(DH_generate_key(dh.get()));
608     EXPECT_LE(BN_num_bits(DH_get0_priv_key(dh.get())), bits);
609     EXPECT_LE(bits - kMaxLeadingZeros, BN_num_bits(DH_get0_priv_key(dh.get())));
610 
611     // If the private key length is num_bits(q), q should be the limiting
612     // factor.
613     dh = NewDHGroup(p.get(), /*q=*/nullptr, g.get());
614     ASSERT_TRUE(dh);
615     DH_set_length(dh.get(), BN_num_bits(q.get()));
616     ASSERT_TRUE(DH_generate_key(dh.get()));
617     EXPECT_LT(BN_cmp(DH_get0_priv_key(dh.get()), q.get()), 0);
618     EXPECT_LE(BN_num_bits(q.get()) - kMaxLeadingZeros,
619               BN_num_bits(DH_get0_priv_key(dh.get())));
620   }
621 }
622