xref: /openbsd-src/regress/lib/libcrypto/ecdh/ecdhtest.c (revision 8550894424f8a4aa4aafb6cd57229dd6ed7cd9dd)
1 /*	$OpenBSD: ecdhtest.c,v 1.12 2021/12/29 22:58:40 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 <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 
74 #include <openssl/crypto.h>
75 #include <openssl/bio.h>
76 #include <openssl/bn.h>
77 #include <openssl/objects.h>
78 #include <openssl/sha.h>
79 #include <openssl/err.h>
80 
81 #include <openssl/ec.h>
82 #include <openssl/ecdh.h>
83 
84 static const int KDF1_SHA1_len = 20;
85 static void *
86 KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen)
87 {
88 #ifndef OPENSSL_NO_SHA
89 	if (*outlen < SHA_DIGEST_LENGTH)
90 		return NULL;
91 	else
92 		*outlen = SHA_DIGEST_LENGTH;
93 	return SHA1(in, inlen, out);
94 #else
95 	return NULL;
96 #endif
97 }
98 
99 
100 static int
101 test_ecdh_curve(int nid, const char *text, BN_CTX *ctx, BIO *out)
102 {
103 	BIGNUM *x_a = NULL, *y_a = NULL, *x_b = NULL, *y_b = NULL;
104 	EC_KEY *a = NULL, *b = NULL;
105 	const EC_GROUP *group;
106 	unsigned char *abuf = NULL, *bbuf = NULL;
107 	int i, alen, blen, aout, bout, ret = 0;
108 	char buf[12];
109 
110 	a = EC_KEY_new_by_curve_name(nid);
111 	b = EC_KEY_new_by_curve_name(nid);
112 	if (a == NULL || b == NULL)
113 		goto err;
114 
115 	group = EC_KEY_get0_group(a);
116 
117 	if ((x_a = BN_new()) == NULL)
118 		goto err;
119 	if ((y_a = BN_new()) == NULL)
120 		goto err;
121 	if ((x_b = BN_new()) == NULL)
122 		goto err;
123 	if ((y_b = BN_new()) == NULL)
124 		goto err;
125 
126 	BIO_puts(out, "Testing key generation with ");
127 	BIO_puts(out, text);
128 	(void)BIO_flush(out);
129 
130 	if (!EC_KEY_generate_key(a))
131 		goto err;
132 
133 	if (!EC_POINT_get_affine_coordinates(group,
134 	    EC_KEY_get0_public_key(a), x_a, y_a, ctx)) goto err;
135 
136 	BIO_printf(out, " .");
137 	(void)BIO_flush(out);
138 
139 	if (!EC_KEY_generate_key(b))
140 		goto err;
141 
142 	if (!EC_POINT_get_affine_coordinates(group,
143 	    EC_KEY_get0_public_key(b), x_b, y_b, ctx)) goto err;
144 
145 	BIO_printf(out, ".");
146 	(void)BIO_flush(out);
147 
148 	alen = KDF1_SHA1_len;
149 	abuf = malloc(alen);
150 	aout = ECDH_compute_key(abuf, alen, EC_KEY_get0_public_key(b),
151 	    a, KDF1_SHA1);
152 
153 	BIO_printf(out, ".");
154 	(void)BIO_flush(out);
155 
156 	blen = KDF1_SHA1_len;
157 	bbuf = malloc(blen);
158 	bout = ECDH_compute_key(bbuf, blen, EC_KEY_get0_public_key(a),
159 	    b, KDF1_SHA1);
160 
161 	BIO_printf(out, ".");
162 	(void)BIO_flush(out);
163 
164 	if ((aout < 4) || (bout != aout) || (memcmp(abuf, bbuf, aout) != 0)) {
165 		BIO_printf(out, " failed\n\n");
166 		BIO_printf(out, "key a:\n");
167 		BIO_printf(out, "private key: ");
168 		BN_print(out, EC_KEY_get0_private_key(a));
169 		BIO_printf(out, "\n");
170 		BIO_printf(out, "public key (x,y): ");
171 		BN_print(out, x_a);
172 		BIO_printf(out, ",");
173 		BN_print(out, y_a);
174 		BIO_printf(out, "\nkey b:\n");
175 		BIO_printf(out, "private key: ");
176 		BN_print(out, EC_KEY_get0_private_key(b));
177 		BIO_printf(out, "\n");
178 		BIO_printf(out, "public key (x,y): ");
179 		BN_print(out, x_b);
180 		BIO_printf(out, ",");
181 		BN_print(out, y_b);
182 		BIO_printf(out, "\n");
183 		BIO_printf(out, "generated key a: ");
184 		for (i = 0; i < bout; i++) {
185 			snprintf(buf, sizeof buf, "%02X", bbuf[i]);
186 			BIO_puts(out, buf);
187 		}
188 		BIO_printf(out, "\n");
189 		BIO_printf(out, "generated key b: ");
190 		for (i = 0; i < aout; i++) {
191 			snprintf(buf, sizeof buf, "%02X", abuf[i]);
192 			BIO_puts(out, buf);
193 		}
194 		BIO_printf(out, "\n");
195 		fprintf(stderr, "Error in ECDH routines\n");
196 		ret = 0;
197 	} else {
198 		BIO_printf(out, " ok\n");
199 		ret = 1;
200 	}
201 
202 err:
203 	ERR_print_errors_fp(stderr);
204 
205 	free(abuf);
206 	free(bbuf);
207 	BN_free(x_a);
208 	BN_free(y_a);
209 	BN_free(x_b);
210 	BN_free(y_b);
211 	EC_KEY_free(b);
212 	EC_KEY_free(a);
213 
214 	return (ret);
215 }
216 
217 /* Keys and shared secrets from RFC 7027 */
218 
219 static const unsigned char bp256_da[] = {
220 	0x81, 0xDB, 0x1E, 0xE1, 0x00, 0x15, 0x0F, 0xF2, 0xEA, 0x33, 0x8D, 0x70,
221 	0x82, 0x71, 0xBE, 0x38, 0x30, 0x0C, 0xB5, 0x42, 0x41, 0xD7, 0x99, 0x50,
222 	0xF7, 0x7B, 0x06, 0x30, 0x39, 0x80, 0x4F, 0x1D
223 };
224 
225 static const unsigned char bp256_db[] = {
226 	0x55, 0xE4, 0x0B, 0xC4, 0x1E, 0x37, 0xE3, 0xE2, 0xAD, 0x25, 0xC3, 0xC6,
227 	0x65, 0x45, 0x11, 0xFF, 0xA8, 0x47, 0x4A, 0x91, 0xA0, 0x03, 0x20, 0x87,
228 	0x59, 0x38, 0x52, 0xD3, 0xE7, 0xD7, 0x6B, 0xD3
229 };
230 
231 static const unsigned char bp256_Z[] = {
232 	0x89, 0xAF, 0xC3, 0x9D, 0x41, 0xD3, 0xB3, 0x27, 0x81, 0x4B, 0x80, 0x94,
233 	0x0B, 0x04, 0x25, 0x90, 0xF9, 0x65, 0x56, 0xEC, 0x91, 0xE6, 0xAE, 0x79,
234 	0x39, 0xBC, 0xE3, 0x1F, 0x3A, 0x18, 0xBF, 0x2B
235 };
236 
237 static const unsigned char bp384_da[] = {
238 	0x1E, 0x20, 0xF5, 0xE0, 0x48, 0xA5, 0x88, 0x6F, 0x1F, 0x15, 0x7C, 0x74,
239 	0xE9, 0x1B, 0xDE, 0x2B, 0x98, 0xC8, 0xB5, 0x2D, 0x58, 0xE5, 0x00, 0x3D,
240 	0x57, 0x05, 0x3F, 0xC4, 0xB0, 0xBD, 0x65, 0xD6, 0xF1, 0x5E, 0xB5, 0xD1,
241 	0xEE, 0x16, 0x10, 0xDF, 0x87, 0x07, 0x95, 0x14, 0x36, 0x27, 0xD0, 0x42
242 };
243 
244 static const unsigned char bp384_db[] = {
245 	0x03, 0x26, 0x40, 0xBC, 0x60, 0x03, 0xC5, 0x92, 0x60, 0xF7, 0x25, 0x0C,
246 	0x3D, 0xB5, 0x8C, 0xE6, 0x47, 0xF9, 0x8E, 0x12, 0x60, 0xAC, 0xCE, 0x4A,
247 	0xCD, 0xA3, 0xDD, 0x86, 0x9F, 0x74, 0xE0, 0x1F, 0x8B, 0xA5, 0xE0, 0x32,
248 	0x43, 0x09, 0xDB, 0x6A, 0x98, 0x31, 0x49, 0x7A, 0xBA, 0xC9, 0x66, 0x70
249 };
250 
251 static const unsigned char bp384_Z[] = {
252 	0x0B, 0xD9, 0xD3, 0xA7, 0xEA, 0x0B, 0x3D, 0x51, 0x9D, 0x09, 0xD8, 0xE4,
253 	0x8D, 0x07, 0x85, 0xFB, 0x74, 0x4A, 0x6B, 0x35, 0x5E, 0x63, 0x04, 0xBC,
254 	0x51, 0xC2, 0x29, 0xFB, 0xBC, 0xE2, 0x39, 0xBB, 0xAD, 0xF6, 0x40, 0x37,
255 	0x15, 0xC3, 0x5D, 0x4F, 0xB2, 0xA5, 0x44, 0x4F, 0x57, 0x5D, 0x4F, 0x42
256 };
257 
258 static const unsigned char bp512_da[] = {
259 	0x16, 0x30, 0x2F, 0xF0, 0xDB, 0xBB, 0x5A, 0x8D, 0x73, 0x3D, 0xAB, 0x71,
260 	0x41, 0xC1, 0xB4, 0x5A, 0xCB, 0xC8, 0x71, 0x59, 0x39, 0x67, 0x7F, 0x6A,
261 	0x56, 0x85, 0x0A, 0x38, 0xBD, 0x87, 0xBD, 0x59, 0xB0, 0x9E, 0x80, 0x27,
262 	0x96, 0x09, 0xFF, 0x33, 0x3E, 0xB9, 0xD4, 0xC0, 0x61, 0x23, 0x1F, 0xB2,
263 	0x6F, 0x92, 0xEE, 0xB0, 0x49, 0x82, 0xA5, 0xF1, 0xD1, 0x76, 0x4C, 0xAD,
264 	0x57, 0x66, 0x54, 0x22
265 };
266 
267 static const unsigned char bp512_db[] = {
268 	0x23, 0x0E, 0x18, 0xE1, 0xBC, 0xC8, 0x8A, 0x36, 0x2F, 0xA5, 0x4E, 0x4E,
269 	0xA3, 0x90, 0x20, 0x09, 0x29, 0x2F, 0x7F, 0x80, 0x33, 0x62, 0x4F, 0xD4,
270 	0x71, 0xB5, 0xD8, 0xAC, 0xE4, 0x9D, 0x12, 0xCF, 0xAB, 0xBC, 0x19, 0x96,
271 	0x3D, 0xAB, 0x8E, 0x2F, 0x1E, 0xBA, 0x00, 0xBF, 0xFB, 0x29, 0xE4, 0xD7,
272 	0x2D, 0x13, 0xF2, 0x22, 0x45, 0x62, 0xF4, 0x05, 0xCB, 0x80, 0x50, 0x36,
273 	0x66, 0xB2, 0x54, 0x29
274 };
275 
276 
277 static const unsigned char bp512_Z[] = {
278 	0xA7, 0x92, 0x70, 0x98, 0x65, 0x5F, 0x1F, 0x99, 0x76, 0xFA, 0x50, 0xA9,
279 	0xD5, 0x66, 0x86, 0x5D, 0xC5, 0x30, 0x33, 0x18, 0x46, 0x38, 0x1C, 0x87,
280 	0x25, 0x6B, 0xAF, 0x32, 0x26, 0x24, 0x4B, 0x76, 0xD3, 0x64, 0x03, 0xC0,
281 	0x24, 0xD7, 0xBB, 0xF0, 0xAA, 0x08, 0x03, 0xEA, 0xFF, 0x40, 0x5D, 0x3D,
282 	0x24, 0xF1, 0x1A, 0x9B, 0x5C, 0x0B, 0xEF, 0x67, 0x9F, 0xE1, 0x45, 0x4B,
283 	0x21, 0xC4, 0xCD, 0x1F
284 };
285 
286 /* Given private value and NID, create EC_KEY structure */
287 
288 static EC_KEY *
289 mk_eckey(int nid, const unsigned char *p, size_t plen)
290 {
291 	EC_KEY *k = NULL;
292 	BIGNUM *priv = NULL;
293 	EC_POINT *pub = NULL;
294 	const EC_GROUP *grp;
295 	int ok = 0;
296 
297 	k = EC_KEY_new_by_curve_name(nid);
298 	if (!k)
299 		goto err;
300 	priv = BN_bin2bn(p, plen, NULL);
301 	if (!priv)
302 		goto err;
303 	if (!EC_KEY_set_private_key(k, priv))
304 		goto err;
305 	grp = EC_KEY_get0_group(k);
306 	pub = EC_POINT_new(grp);
307 	if (!pub)
308 		goto err;
309 	if (!EC_POINT_mul(grp, pub, priv, NULL, NULL, NULL))
310 		goto err;
311 	if (!EC_KEY_set_public_key(k, pub))
312 		goto err;
313 	ok = 1;
314 err:
315 	BN_clear_free(priv);
316 	EC_POINT_free(pub);
317 	if (!ok) {
318 		EC_KEY_free(k);
319 		k = NULL;
320 	}
321 	return (k);
322 }
323 
324 /* Known answer test: compute shared secret and check it matches
325  * expected value.
326  */
327 
328 static int
329 ecdh_kat(BIO *out, const char *cname, int nid,
330     const unsigned char *k1, size_t k1_len,
331     const unsigned char *k2, size_t k2_len,
332     const unsigned char *Z, size_t Zlen)
333 {
334 	int rv = 0;
335 	EC_KEY *key1 = NULL, *key2 = NULL;
336 	unsigned char *Ztmp = NULL;
337 	size_t Ztmplen;
338 	BIO_puts(out, "Testing ECDH shared secret with ");
339 	BIO_puts(out, cname);
340 	key1 = mk_eckey(nid, k1, k1_len);
341 	key2 = mk_eckey(nid, k2, k2_len);
342 	if (!key1 || !key2)
343 		goto err;
344 	Ztmplen = ECDH_size(key1);
345 	if (Ztmplen != Zlen)
346 		goto err;
347 	Ztmp = malloc(Ztmplen);
348 	if (!ECDH_compute_key(Ztmp, Ztmplen,
349 	    EC_KEY_get0_public_key(key2), key1, 0))
350 		goto err;
351 	if (memcmp(Ztmp, Z, Zlen))
352 		goto err;
353 	memset(Ztmp, 0, Zlen);
354 	if (!ECDH_compute_key(Ztmp, Ztmplen,
355 	    EC_KEY_get0_public_key(key1), key2, 0))
356 		goto err;
357 	if (memcmp(Ztmp, Z, Zlen))
358 		goto err;
359 	rv = 1;
360 
361 err:
362 	if (rv)
363 		BIO_puts(out, " ok\n");
364 	else {
365 		fprintf(stderr, "Error in ECDH routines\n");
366 		ERR_print_errors_fp(stderr);
367 	}
368 
369 	EC_KEY_free(key1);
370 	EC_KEY_free(key2);
371 	free(Ztmp);
372 
373 	return rv;
374 }
375 
376 #define test_ecdh_kat(bio, curve, bits) \
377 	ecdh_kat(bio, curve, NID_brainpoolP##bits##r1, \
378 		bp##bits##_da, sizeof(bp##bits##_da), \
379 		bp##bits##_db, sizeof(bp##bits##_db), \
380 		bp##bits##_Z, sizeof(bp##bits##_Z))
381 
382 int
383 main(int argc, char *argv[])
384 {
385 	BN_CTX *ctx = NULL;
386 	int ret = 1;
387 	BIO *out;
388 
389 	out = BIO_new(BIO_s_file());
390 	if (out == NULL)
391 		exit(1);
392 	BIO_set_fp(out, stdout, BIO_NOCLOSE);
393 
394 	if ((ctx = BN_CTX_new()) == NULL)
395 		goto err;
396 
397 	/* NIST PRIME CURVES TESTS */
398 	if (!test_ecdh_curve(NID_X9_62_prime192v1, "NIST Prime-Curve P-192",
399 	    ctx, out))
400 		goto err;
401 	if (!test_ecdh_curve(NID_secp224r1, "NIST Prime-Curve P-224", ctx, out))
402 		goto err;
403 	if (!test_ecdh_curve(NID_X9_62_prime256v1, "NIST Prime-Curve P-256",
404 	    ctx, out))
405 		goto err;
406 	if (!test_ecdh_curve(NID_secp384r1, "NIST Prime-Curve P-384", ctx, out))
407 		goto err;
408 	if (!test_ecdh_curve(NID_secp521r1, "NIST Prime-Curve P-521", ctx, out))
409 		goto err;
410 #ifndef OPENSSL_NO_EC2M
411 	/* NIST BINARY CURVES TESTS */
412 	if (!test_ecdh_curve(NID_sect163k1, "NIST Binary-Curve K-163",
413 	    ctx, out))
414 		goto err;
415 	if (!test_ecdh_curve(NID_sect163r2, "NIST Binary-Curve B-163",
416 	    ctx, out))
417 		goto err;
418 	if (!test_ecdh_curve(NID_sect233k1, "NIST Binary-Curve K-233",
419 	    ctx, out))
420 		goto err;
421 	if (!test_ecdh_curve(NID_sect233r1, "NIST Binary-Curve B-233",
422 	    ctx, out))
423 		goto err;
424 	if (!test_ecdh_curve(NID_sect283k1, "NIST Binary-Curve K-283",
425 	    ctx, out))
426 		goto err;
427 	if (!test_ecdh_curve(NID_sect283r1, "NIST Binary-Curve B-283",
428 	    ctx, out))
429 		goto err;
430 	if (!test_ecdh_curve(NID_sect409k1, "NIST Binary-Curve K-409",
431 	    ctx, out))
432 		goto err;
433 	if (!test_ecdh_curve(NID_sect409r1, "NIST Binary-Curve B-409",
434 	    ctx, out))
435 		goto err;
436 	if (!test_ecdh_curve(NID_sect571k1, "NIST Binary-Curve K-571",
437 	    ctx, out))
438 		goto err;
439 	if (!test_ecdh_curve(NID_sect571r1, "NIST Binary-Curve B-571",
440 	    ctx, out))
441 		goto err;
442 #endif
443 	if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP256r1", 256))
444 		goto err;
445 	if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP384r1", 384))
446 		goto err;
447 	if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP512r1", 512))
448 		goto err;
449 
450 	ret = 0;
451 
452 err:
453 	ERR_print_errors_fp(stderr);
454 	BN_CTX_free(ctx);
455 	BIO_free(out);
456 	CRYPTO_cleanup_all_ex_data();
457 	ERR_remove_thread_state(NULL);
458 	CRYPTO_mem_leaks_fp(stderr);
459 	exit(ret);
460 }
461