xref: /openbsd-src/regress/lib/libcrypto/ecdsa/ecdsatest.c (revision f84b1df5a16cdd762c93854218de246e79975d3b)
1 /*	$OpenBSD: ecdsatest.c,v 1.9 2022/03/31 09:36:09 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 		sig_len = ECDSA_size(eckey);
255 		if ((signature = malloc(sig_len)) == NULL)
256 			goto builtin_err;
257 		if (!ECDSA_sign(0, digest, 20, signature, &sig_len, eckey)) {
258 			BIO_printf(out, " failed\n");
259 			goto builtin_err;
260 		}
261 		BIO_printf(out, ".");
262 		(void)BIO_flush(out);
263 		/* verify signature */
264 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
265 		    eckey) != 1) {
266 			BIO_printf(out, " failed\n");
267 			goto builtin_err;
268 		}
269 		BIO_printf(out, ".");
270 		(void)BIO_flush(out);
271 		/* verify signature with the wrong key */
272 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
273 			wrong_eckey) == 1) {
274 			BIO_printf(out, " failed\n");
275 			goto builtin_err;
276 		}
277 		BIO_printf(out, ".");
278 		(void)BIO_flush(out);
279 		/* wrong digest */
280 		if (ECDSA_verify(0, wrong_digest, 20, signature, sig_len,
281 		    eckey) == 1) {
282 			BIO_printf(out, " failed\n");
283 			goto builtin_err;
284 		}
285 		BIO_printf(out, ".");
286 		(void)BIO_flush(out);
287 		/* wrong length */
288 		if (ECDSA_verify(0, digest, 20, signature, sig_len - 1,
289 		    eckey) == 1) {
290 			BIO_printf(out, " failed\n");
291 			goto builtin_err;
292 		}
293 		BIO_printf(out, ".");
294 		(void)BIO_flush(out);
295 
296 		/*
297 		 * Modify a single byte of the signature: to ensure we don't
298 		 * garble the ASN1 structure, we read the raw signature and
299 		 * modify a byte in one of the bignums directly.
300 		 */
301 		sig_ptr = signature;
302 		if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr,
303 		    sig_len)) == NULL) {
304 			BIO_printf(out, " failed\n");
305 			goto builtin_err;
306 		}
307 
308 		/* Store the two BIGNUMs in raw_buf. */
309 		r_len = BN_num_bytes(ECDSA_SIG_get0_r(ecdsa_sig));
310 		s_len = BN_num_bytes(ECDSA_SIG_get0_s(ecdsa_sig));
311 		bn_len = (degree + 7) / 8;
312 		if ((r_len > bn_len) || (s_len > bn_len)) {
313 			BIO_printf(out, " failed\n");
314 			goto builtin_err;
315 		}
316 		buf_len = 2 * bn_len;
317 		if ((raw_buf = calloc(1, buf_len)) == NULL)
318 			goto builtin_err;
319 		BN_bn2bin(ECDSA_SIG_get0_r(ecdsa_sig), raw_buf + bn_len - r_len);
320 		BN_bn2bin(ECDSA_SIG_get0_s(ecdsa_sig), raw_buf + buf_len - s_len);
321 
322 		/* Modify a single byte in the buffer. */
323 		offset = raw_buf[10] % buf_len;
324 		dirt   = raw_buf[11] ? raw_buf[11] : 1;
325 		raw_buf[offset] ^= dirt;
326 		/* Now read the BIGNUMs back in from raw_buf. */
327 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
328 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
329 			goto builtin_err;
330 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
331 			goto builtin_err;
332 		r = NULL;
333 		s = NULL;
334 
335 		sig_ptr2 = signature;
336 		sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2);
337 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
338 		    eckey) == 1) {
339 			BIO_printf(out, " failed\n");
340 			goto builtin_err;
341 		}
342 		/* Sanity check: undo the modification and verify signature. */
343 		raw_buf[offset] ^= dirt;
344 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
345 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
346 			goto builtin_err;
347 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
348 			goto builtin_err;
349 		r = NULL;
350 		s = NULL;
351 
352 		sig_ptr2 = signature;
353 		sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2);
354 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
355 		    eckey) != 1) {
356 			BIO_printf(out, " failed\n");
357 			goto builtin_err;
358 		}
359 		BIO_printf(out, ".");
360 		(void)BIO_flush(out);
361 
362 		BIO_printf(out, " ok\n");
363 		/* cleanup */
364 		/* clean bogus errors */
365 		ERR_clear_error();
366 		free(signature);
367 		signature = NULL;
368 		EC_KEY_free(eckey);
369 		eckey = NULL;
370 		EC_KEY_free(wrong_eckey);
371 		wrong_eckey = NULL;
372 		ECDSA_SIG_free(ecdsa_sig);
373 		ecdsa_sig = NULL;
374 		free(raw_buf);
375 		raw_buf = NULL;
376 	}
377 
378 	ret = 1;
379  builtin_err:
380 	BN_free(r);
381 	BN_free(s);
382 	EC_KEY_free(eckey);
383 	EC_KEY_free(wrong_eckey);
384 	ECDSA_SIG_free(ecdsa_sig);
385 	free(signature);
386 	free(raw_buf);
387 	free(curves);
388 
389 	return ret;
390 }
391 
392 int
393 main(void)
394 {
395 	int 	ret = 1;
396 	BIO	*out;
397 
398 	out = BIO_new_fp(stdout, BIO_NOCLOSE);
399 
400 	ERR_load_crypto_strings();
401 
402 	/* the tests */
403 	if (!test_builtin(out))
404 		goto err;
405 
406 	ret = 0;
407  err:
408 	if (ret)
409 		BIO_printf(out, "\nECDSA test failed\n");
410 	else
411 		BIO_printf(out, "\nECDSA test passed\n");
412 	if (ret)
413 		ERR_print_errors(out);
414 	CRYPTO_cleanup_all_ex_data();
415 	ERR_remove_thread_state(NULL);
416 	ERR_free_strings();
417 	CRYPTO_mem_leaks(out);
418 	if (out != NULL)
419 		BIO_free(out);
420 	return ret;
421 }
422