xref: /openbsd/regress/lib/libcrypto/ecdh/ecdhtest.c (revision d415bd75)
1 /*	$OpenBSD: ecdhtest.c,v 1.20 2023/07/16 07:34:07 tb Exp $ */
2 /* ====================================================================
3  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
4  *
5  * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
6  * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
7  * to the OpenSSL project.
8  *
9  * The ECC Code is licensed pursuant to the OpenSSL open source
10  * license provided below.
11  *
12  * The ECDH software is originally written by Douglas Stebila of
13  * Sun Microsystems Laboratories.
14  *
15  */
16 /* ====================================================================
17  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  *
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  *
26  * 2. Redistributions in binary form must reproduce the above copyright
27  *    notice, this list of conditions and the following disclaimer in
28  *    the documentation and/or other materials provided with the
29  *    distribution.
30  *
31  * 3. All advertising materials mentioning features or use of this
32  *    software must display the following acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
35  *
36  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
37  *    endorse or promote products derived from this software without
38  *    prior written permission. For written permission, please contact
39  *    openssl-core@openssl.org.
40  *
41  * 5. Products derived from this software may not be called "OpenSSL"
42  *    nor may "OpenSSL" appear in their names without prior written
43  *    permission of the OpenSSL Project.
44  *
45  * 6. Redistributions of any form whatsoever must retain the following
46  *    acknowledgment:
47  *    "This product includes software developed by the OpenSSL Project
48  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
51  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
54  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61  * OF THE POSSIBILITY OF SUCH DAMAGE.
62  * ====================================================================
63  *
64  * This product includes cryptographic software written by Eric Young
65  * (eay@cryptsoft.com).  This product includes software written by Tim
66  * Hudson (tjh@cryptsoft.com).
67  *
68  */
69 
70 #include <err.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 
75 #include <openssl/bn.h>
76 #include <openssl/objects.h>
77 #include <openssl/sha.h>
78 #include <openssl/err.h>
79 
80 #include <openssl/ec.h>
81 #include <openssl/ecdh.h>
82 
83 static void
84 hexdump(const unsigned char *buf, size_t len)
85 {
86 	size_t i;
87 
88 	for (i = 1; i <= len; i++)
89 		fprintf(stdout, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
90 
91 	if (len % 8)
92 		fprintf(stdout, "\n");
93 }
94 
95 static void *
96 KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen)
97 {
98 #ifdef OPENSSL_NO_SHA
99 	return NULL;
100 #else
101 	if (*outlen < SHA_DIGEST_LENGTH)
102 		return NULL;
103 	*outlen = SHA_DIGEST_LENGTH;
104 	return SHA1(in, inlen, out);
105 #endif
106 }
107 
108 static int
109 ecdh_keygen_test(int nid)
110 {
111 	EC_KEY *keya = NULL, *keyb = NULL;
112 	const EC_POINT *puba, *pubb;
113 	unsigned char *abuf = NULL, *bbuf = NULL;
114 	int len = SHA_DIGEST_LENGTH;
115 	int failed = 1;
116 
117 	if ((keya = EC_KEY_new_by_curve_name(nid)) == NULL)
118 		goto err;
119 	if (!EC_KEY_generate_key(keya))
120 		goto err;
121 	if ((puba = EC_KEY_get0_public_key(keya)) == NULL)
122 		goto err;
123 
124 	if ((keyb = EC_KEY_new_by_curve_name(nid)) == NULL)
125 		goto err;
126 	if (!EC_KEY_generate_key(keyb))
127 		goto err;
128 	if ((pubb = EC_KEY_get0_public_key(keyb)) == NULL)
129 		goto err;
130 
131 	if ((abuf = calloc(1, len)) == NULL)
132 		goto err;
133 	if ((bbuf = calloc(1, len)) == NULL)
134 		goto err;
135 
136 	if (ECDH_compute_key(abuf, len, pubb, keya, KDF1_SHA1) != len)
137 		goto err;
138 	if (ECDH_compute_key(bbuf, len, puba, keyb, KDF1_SHA1) != len)
139 		goto err;
140 
141 	if (memcmp(abuf, bbuf, len) != 0) {
142 		printf("key generation with %s failed\n", OBJ_nid2sn(nid));
143 
144 		EC_KEY_print_fp(stdout, keya, 1);
145 		printf(" shared secret:\n");
146 		hexdump(abuf, len);
147 
148 		EC_KEY_print_fp(stdout, keyb, 1);
149 		printf(" shared secret:\n");
150 		hexdump(bbuf, len);
151 
152 		fprintf(stderr, "Error in ECDH routines\n");
153 
154 		goto err;
155 	}
156 
157 	failed = 0;
158 
159  err:
160 	ERR_print_errors_fp(stderr);
161 
162 	EC_KEY_free(keya);
163 	EC_KEY_free(keyb);
164 	freezero(abuf, len);
165 	freezero(bbuf, len);
166 
167 	return failed;
168 }
169 
170 static const struct ecdh_kat_test {
171     const int nid;
172     const char *keya;
173     const char *keyb;
174     const char *want;
175 } ecdh_kat_tests[] = {
176 	/* Keys and shared secrets from RFC 5114 */
177 	{
178 		.nid =	NID_X9_62_prime192v1,
179 		.keya =	"323fa3169d8e9c6593f59476bc142000ab5be0e249c43426",
180 		.keyb =	"631f95bb4a67632c9c476eee9ab695ab240a0499307fcf62",
181 		.want =	"ad420182633f8526bfe954acda376f05e5ff4f837f54febe",
182 	},
183 	{
184 		.nid =	NID_secp224r1,
185 		.keya =	"b558eb6c288da707bbb4f8fbae2ab9e9cb62e3bc5c7573e2"
186 			"2e26d37f",
187 		.keyb =	"ac3b1add3d9770e6f6a708ee9f3b8e0ab3b480e9f27f85c8"
188 			"8b5e6d18",
189 		.want =	"52272f50f46f4edc9151569092f46df2d96ecc3b6dc1714a"
190 			"4ea949fa",
191 	},
192 	{
193 		.nid =	NID_X9_62_prime256v1,
194 		.keya =	"814264145f2f56f2e96a8e337a1284993faf432a5abce59e"
195 			"867b7291d507a3af",
196 		.keyb =	"2ce1788ec197e096db95a200cc0ab26a19ce6bccad562b8e"
197 			"ee1b593761cf7f41",
198 		.want =	"dd0f5396219d1ea393310412d19a08f1f5811e9dc8ec8eea"
199 			"7f80d21c820c2788",
200 	},
201 	{
202 		.nid =	NID_secp384r1,
203 		.keya =	"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48"
204 			"d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1",
205 		.keyb =	"52d1791fdb4b70f89c0f00d456c2f7023b6125262c36a7df"
206 			"1f80231121cce3d39be52e00c194a4132c4a6c768bcd94d2",
207 		.want =	"5ea1fc4af7256d2055981b110575e0a8cae53160137d904c"
208 			"59d926eb1b8456e427aa8a4540884c37de159a58028abc0e",
209 	},
210 	{
211 		.nid =	NID_secp521r1,
212 		.keya =	"0113f82da825735e3d97276683b2b74277bad27335ea7166"
213 			"4af2430cc4f33459b9669ee78b3ffb9b8683015d344dcbfe"
214 			"f6fb9af4c6c470be254516cd3c1a1fb47362",
215 		.keyb =	"00cee3480d8645a17d249f2776d28bae616952d1791fdb4b"
216 			"70f7c3378732aa1b22928448bcd1dc2496d435b01048066e"
217 			"be4f72903c361b1a9dc1193dc2c9d0891b96",
218 		.want =	"00cdea89621cfa46b132f9e4cfe2261cde2d4368eb565663"
219 			"4c7cc98c7a00cde54ed1866a0dd3e6126c9d2f845daff82c"
220 			"eb1da08f5d87521bb0ebeca77911169c20cc",
221 	},
222 	/* Keys and shared secrets from RFC 5903 */
223 	{
224 		.nid =	NID_X9_62_prime256v1,
225 		.keya =	"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049"
226 			"c62a9c57862d1433",
227 		.keyb =	"c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0"
228 			"b283ab46476bee53",
229 		.want =	"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03"
230 			"812464d04b9442de",
231 	},
232 	{
233 		.nid =	NID_secp384r1,
234 		.keya =	"099f3c7034d4a2c699884d73a375a67f7624ef7c6b3c0f16"
235 			"0647b67414dce655e35b538041e649ee3faef896783ab194",
236 		.keyb =	"41cb0779b4bdb85d47846725fbec3c9430fab46cc8dc5060"
237 			"855cc9bda0aa2942e0308312916b8ed2960e4bd55a7448fc",
238 		.want =	"11187331c279962d93d604243fd592cb9d0a926f422e4718"
239 			"7521287e7156c5c4d603135569b9e9d09cf5d4a270f59746",
240 	},
241 	{
242 		.nid =	NID_secp521r1,
243 		.keya =	"0037ade9319a89f4dabdb3ef411aaccca5123c61acab57b5"
244 			"393dce47608172a095aa85a30fe1c2952c6771d937ba9777"
245 			"f5957b2639bab072462f68c27a57382d"
246 			"4a52",
247 		.keyb =	"0145ba99a847af43793fdd0e872e7cdfa16be30fdc780f97"
248 			"bccc3f078380201e9c677d600b343757a3bdbf2a3163e4c2"
249 			"f869cca7458aa4a4effc311f5cb151685eb9",
250 		.want =	"01144c7d79ae6956bc8edb8e7c787c4521cb086fa64407f9"
251 			"7894e5e6b2d79b04d1427e73ca4baa240a34786859810c06"
252 			"b3c715a3a8cc3151f2bee417996d19f3ddea",
253 	},
254 	/* Keys and shared secrets from RFC 7027 */
255 	{
256 		.nid =	NID_brainpoolP256r1,
257 		.keya =	"81db1ee100150ff2ea338d708271be38300cb54241d79950"
258 			"f77b063039804f1d",
259 		.keyb =	"55e40bc41e37e3e2ad25c3c6654511ffa8474a91a0032087"
260 			"593852d3e7d76bd3",
261 		.want =	"89afc39d41d3b327814b80940b042590f96556ec91e6ae79"
262 			"39bce31f3a18bf2b",
263 	},
264 	{
265 		.nid =	NID_brainpoolP384r1,
266 		.keya =	"1e20f5e048a5886f1f157c74e91bde2b98c8b52d58e5003d"
267 			"57053fc4b0bd65d6f15eb5d1ee1610df870795143627d042",
268 		.keyb =	"032640bc6003c59260f7250c3db58ce647f98e1260acce4a"
269 			"cda3dd869f74e01f8ba5e0324309db6a9831497abac96670",
270 		.want =	"0bd9d3a7ea0b3d519d09d8e48d0785fb744a6b355e6304bc"
271 			"51c229fbbce239bbadf6403715c35d4fb2a5444f575d4f42",
272 	},
273 	{
274 		.nid =	NID_brainpoolP512r1,
275 		.keya =	"16302ff0dbbb5a8d733dab7141c1b45acbc8715939677f6a"
276 			"56850a38bd87bd59b09e80279609ff333eb9d4c061231fb2"
277 			"6f92eeb04982a5f1d1764cad57665422",
278 		.keyb =	"230e18e1bcc88a362fa54e4ea3902009292f7f8033624fd4"
279 			"71b5d8ace49d12cfabbc19963dab8e2f1eba00bffb29e4d7"
280 			"2d13f2224562f405cb80503666b25429",
281 		.want =	"a7927098655f1f9976fa50a9d566865dc530331846381c87"
282 			"256baf3226244b76d36403c024d7bbf0aa0803eaff405d3d"
283 			"24f11a9b5c0bef679fe1454b21c4cd1f",
284 	},
285 };
286 
287 #define N_KATS (sizeof(ecdh_kat_tests) / sizeof(ecdh_kat_tests[0]))
288 
289 /* Given private value and NID, create EC_KEY structure */
290 
291 static EC_KEY *
292 mk_eckey(int nid, const char *priv_str)
293 {
294 	EC_KEY *key = NULL;
295 	BIGNUM *priv = NULL;
296 	EC_POINT *pub = NULL;
297 	const EC_GROUP *group;
298 	EC_KEY *ret = NULL;
299 
300 	if ((key = EC_KEY_new_by_curve_name(nid)) == NULL)
301 		goto err;
302 	if (!BN_hex2bn(&priv, priv_str))
303 		goto err;
304 	if (!EC_KEY_set_private_key(key, priv))
305 		goto err;
306 	if ((group = EC_KEY_get0_group(key)) == NULL)
307 		goto err;
308 	if ((pub = EC_POINT_new(group)) == NULL)
309 		goto err;
310 	if (!EC_POINT_mul(group, pub, priv, NULL, NULL, NULL))
311 		goto err;
312 	if (!EC_KEY_set_public_key(key, pub))
313 		goto err;
314 
315 	ret = key;
316 	key = NULL;
317 
318  err:
319 	EC_KEY_free(key);
320 	BN_free(priv);
321 	EC_POINT_free(pub);
322 
323 	return ret;
324 }
325 
326 /*
327  * Known answer test: compute shared secret and check it matches expected value.
328  */
329 static int
330 ecdh_kat(const struct ecdh_kat_test *kat)
331 {
332 	EC_KEY *keya = NULL, *keyb = NULL;
333 	const EC_POINT *puba, *pubb;
334 	BIGNUM *z = NULL;
335 	unsigned char *want = NULL, *got = NULL;
336 	int len = 0;
337 	int failed = 1;
338 
339 	if ((keya = mk_eckey(kat->nid, kat->keya)) == NULL)
340 		goto err;
341 	if ((puba = EC_KEY_get0_public_key(keya)) == NULL)
342 		goto err;
343 	if ((keyb = mk_eckey(kat->nid, kat->keyb)) == NULL)
344 		goto err;
345 	if ((pubb = EC_KEY_get0_public_key(keyb)) == NULL)
346 		goto err;
347 
348 	if ((len = ECDH_size(keya)) != ECDH_size(keyb))
349 		goto err;
350 
351 	if ((want = calloc(1, len)) == NULL)
352 		goto err;
353 	if ((got = calloc(1, len)) == NULL)
354 		goto err;
355 
356 	if (!BN_hex2bn(&z, kat->want))
357 		goto err;
358 	if (BN_num_bytes(z) > len)
359 		goto err;
360 	if (BN_bn2binpad(z, want, len) != len)
361 		goto err;
362 
363 	if (ECDH_compute_key(got, len, pubb, keya, NULL) != len)
364 		goto err;
365 	if (memcmp(got, want, len) != 0)
366 		goto err;
367 
368 	memset(got, 0, len);
369 
370 	if (ECDH_compute_key(got, len, puba, keyb, NULL) != len)
371 		goto err;
372 	if (memcmp(got, want, len) != 0)
373 		goto err;
374 
375 	failed = 0;
376 
377  err:
378 	if (failed) {
379 		printf("shared secret with %s failed", OBJ_nid2sn(kat->nid));
380 
381 		fprintf(stderr, "Error in ECDH routines\n");
382 		ERR_print_errors_fp(stderr);
383 	}
384 
385 	EC_KEY_free(keya);
386 	EC_KEY_free(keyb);
387 	BN_free(z);
388 	freezero(want, len);
389 	freezero(got, len);
390 
391 	return failed;
392 }
393 
394 int
395 main(void)
396 {
397 	EC_builtin_curve *curves = NULL;
398 	size_t i, n_curves;
399 	int failed = 0;
400 
401 	if ((n_curves = EC_get_builtin_curves(NULL, 0)) == 0)
402 		errx(1, "EC_get_builtin_curves failed");
403 	if ((curves = calloc(n_curves, sizeof(*curves))) == NULL)
404 		errx(1, NULL);
405 	if (EC_get_builtin_curves(curves, n_curves) != n_curves)
406 		errx(1, "EC_get_builtin_curves failed");
407 
408 	for (i = 0; i < n_curves; i++)
409 		failed |= ecdh_keygen_test(curves[i].nid);
410 
411 	for (i = 0; i < N_KATS; i++)
412 		failed |= ecdh_kat(&ecdh_kat_tests[i]);
413 
414 	free(curves);
415 	ERR_print_errors_fp(stderr);
416 
417 	return failed;
418 }
419