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