xref: /openbsd-src/regress/lib/libcrypto/ecdsa/ecdsatest.c (revision d179e8082fbc7d38c661d7617392fc616034d0f1)
1 /*	$OpenBSD: ecdsatest.c,v 1.13 2022/08/31 09:39:59 tb Exp $	*/
2 /*
3  * Written by Nils Larsch for the OpenSSL project.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000-2005 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 /* ====================================================================
59  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60  *
61  * Portions of the attached software ("Contribution") are developed by
62  * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
63  *
64  * The Contribution is licensed pursuant to the OpenSSL open source
65  * license provided above.
66  *
67  * The elliptic curve binary polynomial software is originally written by
68  * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
69  *
70  */
71 
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 
76 #include <openssl/crypto.h>
77 #include <openssl/bio.h>
78 #include <openssl/evp.h>
79 #include <openssl/bn.h>
80 #include <openssl/ecdsa.h>
81 #ifndef OPENSSL_NO_ENGINE
82 #include <openssl/engine.h>
83 #endif
84 #include <openssl/err.h>
85 
86 /* declaration of the test functions */
87 int x9_62_test_internal(BIO *out, int nid, const char *r, const char *s);
88 int test_builtin(BIO *);
89 
90 /* some tests from the X9.62 draft */
91 int
92 x9_62_test_internal(BIO *out, int nid, const char *r_in, const char *s_in)
93 {
94 	int	ret = 0;
95 	const char message[] = "abc";
96 	unsigned char digest[20];
97 	unsigned int  dgst_len = 0;
98 	EVP_MD_CTX *md_ctx = NULL;
99 	EC_KEY    *key = NULL;
100 	ECDSA_SIG *signature = NULL;
101 	BIGNUM    *r = NULL, *s = NULL;
102 
103 	if ((md_ctx = EVP_MD_CTX_new()) == NULL)
104 		goto x962_int_err;
105 	/* get the message digest */
106 	if (!EVP_DigestInit(md_ctx, EVP_sha1()))
107 		goto x962_int_err;
108 	if (!EVP_DigestUpdate(md_ctx, (const void*)message, 3))
109 		goto x962_int_err;
110 	if (!EVP_DigestFinal(md_ctx, digest, &dgst_len))
111 		goto x962_int_err;
112 
113 	BIO_printf(out, "testing %s: ", OBJ_nid2sn(nid));
114 	/* create the key */
115 	if ((key = EC_KEY_new_by_curve_name(nid)) == NULL)
116 		goto x962_int_err;
117 	if (!EC_KEY_generate_key(key))
118 		goto x962_int_err;
119 	BIO_printf(out, ".");
120 	(void)BIO_flush(out);
121 	/* create the signature */
122 	signature = ECDSA_do_sign(digest, 20, key);
123 	if (signature == NULL)
124 		goto x962_int_err;
125 	BIO_printf(out, ".");
126 	(void)BIO_flush(out);
127 	/* compare the created signature with the expected signature */
128 	if ((r = BN_new()) == NULL || (s = BN_new()) == NULL)
129 		goto x962_int_err;
130 	if (!BN_dec2bn(&r, r_in) ||
131 	    !BN_dec2bn(&s, s_in))
132 		goto x962_int_err;
133 	if (BN_cmp(ECDSA_SIG_get0_r(signature), r) ||
134 	    BN_cmp(ECDSA_SIG_get0_s(signature), s))
135 		goto x962_int_err;
136 	BIO_printf(out, ".");
137 	(void)BIO_flush(out);
138 	/* verify the signature */
139 	if (ECDSA_do_verify(digest, 20, signature, key) != 1)
140 		goto x962_int_err;
141 	BIO_printf(out, ".");
142 	(void)BIO_flush(out);
143 
144 	BIO_printf(out, " ok\n");
145 	ret = 1;
146  x962_int_err:
147 	if (!ret)
148 		BIO_printf(out, " failed\n");
149 	if (key)
150 		EC_KEY_free(key);
151 	if (signature)
152 		ECDSA_SIG_free(signature);
153 	if (r)
154 		BN_free(r);
155 	if (s)
156 		BN_free(s);
157 	EVP_MD_CTX_free(md_ctx);
158 	return ret;
159 }
160 
161 int
162 test_builtin(BIO *out)
163 {
164 	EC_builtin_curve *curves = NULL;
165 	size_t		num_curves = 0, n = 0;
166 	EC_KEY		*eckey = NULL, *wrong_eckey = NULL;
167 	EC_GROUP	*group;
168 	ECDSA_SIG	*ecdsa_sig = NULL;
169 	BIGNUM		*r = NULL, *s = NULL;
170 	unsigned char	digest[20], wrong_digest[20];
171 	unsigned char	*signature = NULL;
172 	const unsigned char	*sig_ptr;
173 	unsigned char	*sig_ptr2;
174 	unsigned char	*raw_buf = NULL;
175 	unsigned int	sig_len, degree, r_len, s_len, bn_len, buf_len;
176 	int		nid, ret =  0;
177 
178 	/* fill digest values with some random data */
179 	arc4random_buf(digest, 20);
180 	arc4random_buf(wrong_digest, 20);
181 
182 	/* create and verify a ecdsa signature with every available curve */
183 	BIO_printf(out, "\ntesting ECDSA_sign() and ECDSA_verify() "
184 		"with some internal curves:\n");
185 
186 	/* get a list of all internal curves */
187 	num_curves = EC_get_builtin_curves(NULL, 0);
188 
189 	curves = reallocarray(NULL, sizeof(EC_builtin_curve), num_curves);
190 
191 	if (curves == NULL) {
192 		BIO_printf(out, "reallocarray error\n");
193 		goto builtin_err;
194 	}
195 
196 	if (!EC_get_builtin_curves(curves, num_curves)) {
197 		BIO_printf(out, "unable to get internal curves\n");
198 		goto builtin_err;
199 	}
200 
201 	/* now create and verify a signature for every curve */
202 	for (n = 0; n < num_curves; n++) {
203 		unsigned char dirt, offset;
204 
205 		nid = curves[n].nid;
206 		if (nid == NID_ipsec4)
207 			continue;
208 		/* create new ecdsa key (== EC_KEY) */
209 		if ((eckey = EC_KEY_new()) == NULL)
210 			goto builtin_err;
211 		group = EC_GROUP_new_by_curve_name(nid);
212 		if (group == NULL)
213 			goto builtin_err;
214 		if (EC_KEY_set_group(eckey, group) == 0)
215 			goto builtin_err;
216 		EC_GROUP_free(group);
217 		degree = EC_GROUP_get_degree(EC_KEY_get0_group(eckey));
218 		if (degree < 160) {
219 			/* drop the curve */
220 			EC_KEY_free(eckey);
221 			eckey = NULL;
222 			continue;
223 		}
224 		BIO_printf(out, "%s: ", OBJ_nid2sn(nid));
225 		/* create key */
226 		if (!EC_KEY_generate_key(eckey)) {
227 			BIO_printf(out, " failed\n");
228 			goto builtin_err;
229 		}
230 		/* create second key */
231 		if ((wrong_eckey = EC_KEY_new()) == NULL)
232 			goto builtin_err;
233 		group = EC_GROUP_new_by_curve_name(nid);
234 		if (group == NULL)
235 			goto builtin_err;
236 		if (EC_KEY_set_group(wrong_eckey, group) == 0)
237 			goto builtin_err;
238 		EC_GROUP_free(group);
239 		if (!EC_KEY_generate_key(wrong_eckey)) {
240 			BIO_printf(out, " failed\n");
241 			goto builtin_err;
242 		}
243 
244 		BIO_printf(out, ".");
245 		(void)BIO_flush(out);
246 		/* check key */
247 		if (!EC_KEY_check_key(eckey)) {
248 			BIO_printf(out, " failed\n");
249 			goto builtin_err;
250 		}
251 		BIO_printf(out, ".");
252 		(void)BIO_flush(out);
253 		/* create signature */
254 		if ((sig_len = ECDSA_size(eckey)) == 0)
255 			goto builtin_err;
256 		if ((signature = malloc(sig_len)) == NULL)
257 			goto builtin_err;
258 		if (!ECDSA_sign(0, digest, 20, signature, &sig_len, eckey)) {
259 			BIO_printf(out, " failed\n");
260 			goto builtin_err;
261 		}
262 		BIO_printf(out, ".");
263 		(void)BIO_flush(out);
264 		/* verify signature */
265 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
266 		    eckey) != 1) {
267 			BIO_printf(out, " failed\n");
268 			goto builtin_err;
269 		}
270 		BIO_printf(out, ".");
271 		(void)BIO_flush(out);
272 		/* verify signature with the wrong key */
273 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
274 			wrong_eckey) == 1) {
275 			BIO_printf(out, " failed\n");
276 			goto builtin_err;
277 		}
278 		BIO_printf(out, ".");
279 		(void)BIO_flush(out);
280 		/* wrong digest */
281 		if (ECDSA_verify(0, wrong_digest, 20, signature, sig_len,
282 		    eckey) == 1) {
283 			BIO_printf(out, " failed\n");
284 			goto builtin_err;
285 		}
286 		BIO_printf(out, ".");
287 		(void)BIO_flush(out);
288 		/* wrong length */
289 		if (ECDSA_verify(0, digest, 20, signature, sig_len - 1,
290 		    eckey) == 1) {
291 			BIO_printf(out, " failed\n");
292 			goto builtin_err;
293 		}
294 		BIO_printf(out, ".");
295 		(void)BIO_flush(out);
296 
297 		/*
298 		 * Modify a single byte of the signature: to ensure we don't
299 		 * garble the ASN1 structure, we read the raw signature and
300 		 * modify a byte in one of the bignums directly.
301 		 */
302 		sig_ptr = signature;
303 		if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr,
304 		    sig_len)) == NULL) {
305 			BIO_printf(out, " failed\n");
306 			goto builtin_err;
307 		}
308 
309 		/* Store the two BIGNUMs in raw_buf. */
310 		r_len = BN_num_bytes(ECDSA_SIG_get0_r(ecdsa_sig));
311 		s_len = BN_num_bytes(ECDSA_SIG_get0_s(ecdsa_sig));
312 		bn_len = (degree + 7) / 8;
313 		if ((r_len > bn_len) || (s_len > bn_len)) {
314 			BIO_printf(out, " failed\n");
315 			goto builtin_err;
316 		}
317 		buf_len = 2 * bn_len;
318 		if ((raw_buf = calloc(1, buf_len)) == NULL)
319 			goto builtin_err;
320 		BN_bn2bin(ECDSA_SIG_get0_r(ecdsa_sig), raw_buf + bn_len - r_len);
321 		BN_bn2bin(ECDSA_SIG_get0_s(ecdsa_sig), raw_buf + buf_len - s_len);
322 
323 		/* Modify a single byte in the buffer. */
324 		offset = raw_buf[10] % buf_len;
325 		dirt   = raw_buf[11] ? raw_buf[11] : 1;
326 		raw_buf[offset] ^= dirt;
327 		/* Now read the BIGNUMs back in from raw_buf. */
328 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
329 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
330 			goto builtin_err;
331 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
332 			goto builtin_err;
333 		r = NULL;
334 		s = NULL;
335 
336 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL)) <= 0)
337 			goto builtin_err;
338 		free(signature);
339 		if ((signature = calloc(1, sig_len)) == NULL)
340 			goto builtin_err;
341 
342 		sig_ptr2 = signature;
343 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2)) <= 0)
344 			goto builtin_err;
345 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
346 		    eckey) == 1) {
347 			BIO_printf(out, " failed\n");
348 			goto builtin_err;
349 		}
350 		/* Sanity check: undo the modification and verify signature. */
351 		raw_buf[offset] ^= dirt;
352 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
353 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
354 			goto builtin_err;
355 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
356 			goto builtin_err;
357 		r = NULL;
358 		s = NULL;
359 
360 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL)) <= 0)
361 			goto builtin_err;
362 		free(signature);
363 		if ((signature = calloc(1, sig_len)) == NULL)
364 			goto builtin_err;
365 
366 		sig_ptr2 = signature;
367 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2)) <= 0)
368 			goto builtin_err;
369 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
370 		    eckey) != 1) {
371 			BIO_printf(out, " failed\n");
372 			goto builtin_err;
373 		}
374 		BIO_printf(out, ".");
375 		(void)BIO_flush(out);
376 
377 		BIO_printf(out, " ok\n");
378 		/* cleanup */
379 		/* clean bogus errors */
380 		ERR_clear_error();
381 		free(signature);
382 		signature = NULL;
383 		EC_KEY_free(eckey);
384 		eckey = NULL;
385 		EC_KEY_free(wrong_eckey);
386 		wrong_eckey = NULL;
387 		ECDSA_SIG_free(ecdsa_sig);
388 		ecdsa_sig = NULL;
389 		free(raw_buf);
390 		raw_buf = NULL;
391 	}
392 
393 	ret = 1;
394  builtin_err:
395 	BN_free(r);
396 	BN_free(s);
397 	EC_KEY_free(eckey);
398 	EC_KEY_free(wrong_eckey);
399 	ECDSA_SIG_free(ecdsa_sig);
400 	free(signature);
401 	free(raw_buf);
402 	free(curves);
403 
404 	return ret;
405 }
406 
407 int
408 main(void)
409 {
410 	int 	ret = 1;
411 	BIO	*out;
412 
413 	out = BIO_new_fp(stdout, BIO_NOCLOSE);
414 
415 	ERR_load_crypto_strings();
416 
417 	/* the tests */
418 	if (!test_builtin(out))
419 		goto err;
420 
421 	ret = 0;
422  err:
423 	if (ret)
424 		BIO_printf(out, "\nECDSA test failed\n");
425 	else
426 		BIO_printf(out, "\nECDSA test passed\n");
427 	if (ret)
428 		ERR_print_errors(out);
429 	CRYPTO_cleanup_all_ex_data();
430 	ERR_remove_thread_state(NULL);
431 	ERR_free_strings();
432 	CRYPTO_mem_leaks(out);
433 	if (out != NULL)
434 		BIO_free(out);
435 	return ret;
436 }
437