xref: /openbsd-src/regress/lib/libcrypto/ecdsa/ecdsatest.c (revision 256a93a44f36679bee503f12e49566c2183f6181)
1 /*	$OpenBSD: ecdsatest.c,v 1.14 2022/09/02 11:47:25 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(int nid, const char *r, const char *s);
88 int test_builtin(void);
89 
90 /* some tests from the X9.62 draft */
91 int
92 x9_62_test_internal(int nid, const char *r_in, const char *s_in)
93 {
94 	EVP_MD_CTX *md_ctx = NULL;
95 	const char message[] = "abc";
96 	unsigned char digest[20];
97 	unsigned int dgst_len = 0;
98 	EC_KEY *key = NULL;
99 	ECDSA_SIG *signature = NULL;
100 	BIGNUM *r = NULL, *s = NULL;
101 	int failed = 1;
102 
103 	if ((md_ctx = EVP_MD_CTX_new()) == NULL)
104 		goto err;
105 
106 	if (!EVP_DigestInit(md_ctx, EVP_sha1()))
107 		goto err;
108 	if (!EVP_DigestUpdate(md_ctx, message, 3))
109 		goto err;
110 	if (!EVP_DigestFinal(md_ctx, digest, &dgst_len))
111 		goto err;
112 
113 	printf("testing %s: ", OBJ_nid2sn(nid));
114 
115 	if ((key = EC_KEY_new_by_curve_name(nid)) == NULL)
116 		goto err;
117 	if (!EC_KEY_generate_key(key))
118 		goto err;
119 
120 	printf(".");
121 	fflush(stdout);
122 
123 	if ((signature = ECDSA_do_sign(digest, 20, key)) == NULL)
124 		goto err;
125 
126 	printf(".");
127 	fflush(stdout);
128 
129 	if (!BN_dec2bn(&r, r_in) || !BN_dec2bn(&s, s_in))
130 		goto err;
131 	if (BN_cmp(ECDSA_SIG_get0_r(signature), r) ||
132 	    BN_cmp(ECDSA_SIG_get0_s(signature), s))
133 		goto err;
134 
135 	printf(".");
136 	fflush(stdout);
137 
138 	if (ECDSA_do_verify(digest, 20, signature, key) != 1)
139 		goto err;
140 
141 	printf(".");
142 	fflush(stdout);
143 
144 	printf(" ok\n");
145 
146 	failed = 0;
147 
148  err:
149 	if (failed)
150 		printf(" failed\n");
151 	EC_KEY_free(key);
152 	ECDSA_SIG_free(signature);
153 	BN_free(r);
154 	BN_free(s);
155 	EVP_MD_CTX_free(md_ctx);
156 	return failed;
157 }
158 
159 int
160 test_builtin(void)
161 {
162 	unsigned char digest[20], wrong_digest[20];
163 	EC_builtin_curve *curves = NULL;
164 	size_t num_curves = 0, n = 0;
165 	EC_KEY *eckey = NULL, *wrong_eckey = NULL;
166 	EC_GROUP *group;
167 	ECDSA_SIG *ecdsa_sig = NULL;
168 	BIGNUM *r = NULL, *s = NULL;
169 	unsigned char *signature = NULL;
170 	const unsigned char *sig_ptr;
171 	unsigned char *sig_ptr2;
172 	unsigned char *raw_buf = NULL;
173 	unsigned int sig_len, degree, r_len, s_len, bn_len, buf_len;
174 	int nid;
175 	int failed = 1;
176 
177 	/* fill digest values with some random data */
178 	arc4random_buf(digest, 20);
179 	arc4random_buf(wrong_digest, 20);
180 
181 	/* create and verify a ecdsa signature with every available curve */
182 	printf("\ntesting ECDSA_sign() and ECDSA_verify() "
183 	    "with some internal curves:\n");
184 
185 	/* get a list of all internal curves */
186 	num_curves = EC_get_builtin_curves(NULL, 0);
187 
188 	curves = reallocarray(NULL, sizeof(EC_builtin_curve), num_curves);
189 	if (curves == NULL) {
190 		printf("reallocarray error\n");
191 		goto err;
192 	}
193 
194 	if (!EC_get_builtin_curves(curves, num_curves)) {
195 		printf("unable to get internal curves\n");
196 		goto err;
197 	}
198 
199 	/* now create and verify a signature for every curve */
200 	for (n = 0; n < num_curves; n++) {
201 		unsigned char dirt, offset;
202 
203 		nid = curves[n].nid;
204 		if (nid == NID_ipsec4)
205 			continue;
206 
207 		if ((eckey = EC_KEY_new()) == NULL)
208 			goto err;
209 		group = EC_GROUP_new_by_curve_name(nid);
210 		if (group == NULL)
211 			goto err;
212 		if (EC_KEY_set_group(eckey, group) == 0)
213 			goto err;
214 		degree = EC_GROUP_get_degree(group);
215 		EC_GROUP_free(group);
216 		if (degree < 160) {
217 			/* drop the curve */
218 			EC_KEY_free(eckey);
219 			eckey = NULL;
220 			continue;
221 		}
222 		printf("%s: ", OBJ_nid2sn(nid));
223 
224 		if (!EC_KEY_generate_key(eckey)) {
225 			goto err;
226 		}
227 
228 		if ((wrong_eckey = EC_KEY_new()) == NULL)
229 			goto err;
230 		group = EC_GROUP_new_by_curve_name(nid);
231 		if (group == NULL)
232 			goto err;
233 		if (EC_KEY_set_group(wrong_eckey, group) == 0)
234 			goto err;
235 		EC_GROUP_free(group);
236 		if (!EC_KEY_generate_key(wrong_eckey))
237 			goto err;
238 
239 		printf(".");
240 		fflush(stdout);
241 
242 		if (!EC_KEY_check_key(eckey))
243 			goto err;
244 
245 		printf(".");
246 		fflush(stdout);
247 
248 		if ((sig_len = ECDSA_size(eckey)) == 0)
249 			goto err;
250 		if ((signature = malloc(sig_len)) == NULL)
251 			goto err;
252 		if (!ECDSA_sign(0, digest, 20, signature, &sig_len, eckey))
253 			goto err;
254 
255 		printf(".");
256 		fflush(stdout);
257 
258 		if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) != 1)
259 			goto err;
260 
261 		printf(".");
262 		fflush(stdout);
263 
264 		/* verify signature with the wrong key */
265 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
266 		    wrong_eckey) == 1)
267 			goto err;
268 
269 		printf(".");
270 		fflush(stdout);
271 
272 		if (ECDSA_verify(0, wrong_digest, 20, signature, sig_len,
273 		    eckey) == 1)
274 			goto err;
275 
276 		printf(".");
277 		fflush(stdout);
278 
279 		if (ECDSA_verify(0, digest, 20, signature, sig_len - 1,
280 		    eckey) == 1)
281 			goto err;
282 
283 		printf(".");
284 		fflush(stdout);
285 
286 		/*
287 		 * Modify a single byte of the signature: to ensure we don't
288 		 * garble the ASN1 structure, we read the raw signature and
289 		 * modify a byte in one of the bignums directly.
290 		 */
291 		sig_ptr = signature;
292 		if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr,
293 		    sig_len)) == NULL)
294 			goto err;
295 
296 		/* Store the two BIGNUMs in raw_buf. */
297 		r_len = BN_num_bytes(ECDSA_SIG_get0_r(ecdsa_sig));
298 		s_len = BN_num_bytes(ECDSA_SIG_get0_s(ecdsa_sig));
299 		bn_len = (degree + 7) / 8;
300 		if ((r_len > bn_len) || (s_len > bn_len))
301 			goto err;
302 
303 		buf_len = 2 * bn_len;
304 		if ((raw_buf = calloc(1, buf_len)) == NULL)
305 			goto err;
306 		BN_bn2bin(ECDSA_SIG_get0_r(ecdsa_sig),
307 		    raw_buf + bn_len - r_len);
308 		BN_bn2bin(ECDSA_SIG_get0_s(ecdsa_sig),
309 		    raw_buf + buf_len - s_len);
310 
311 		/* Modify a single byte in the buffer. */
312 		offset = raw_buf[10] % buf_len;
313 		dirt = raw_buf[11] ? raw_buf[11] : 1;
314 		raw_buf[offset] ^= dirt;
315 		/* Now read the BIGNUMs back in from raw_buf. */
316 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
317 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
318 			goto err;
319 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
320 			goto err;
321 		r = NULL;
322 		s = NULL;
323 
324 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL)) <= 0)
325 			goto err;
326 		free(signature);
327 		if ((signature = calloc(1, sig_len)) == NULL)
328 			goto err;
329 
330 		sig_ptr2 = signature;
331 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2)) <= 0)
332 			goto err;
333 		if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) == 1)
334 			goto err;
335 
336 		/* Sanity check: undo the modification and verify signature. */
337 		raw_buf[offset] ^= dirt;
338 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
339 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
340 			goto err;
341 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
342 			goto err;
343 		r = NULL;
344 		s = NULL;
345 
346 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL)) <= 0)
347 			goto err;
348 		free(signature);
349 		if ((signature = calloc(1, sig_len)) == NULL)
350 			goto err;
351 
352 		sig_ptr2 = signature;
353 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2)) <= 0)
354 			goto err;
355 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
356 		    eckey) != 1)
357 			goto err;
358 
359 		printf(".");
360 		fflush(stdout);
361 
362 		printf(" ok\n");
363 
364 		ERR_clear_error();
365 		free(signature);
366 		signature = NULL;
367 		EC_KEY_free(eckey);
368 		eckey = NULL;
369 		EC_KEY_free(wrong_eckey);
370 		wrong_eckey = NULL;
371 		ECDSA_SIG_free(ecdsa_sig);
372 		ecdsa_sig = NULL;
373 		free(raw_buf);
374 		raw_buf = NULL;
375 	}
376 
377 	failed = 0;
378 
379  err:
380 	if (failed)
381 		printf(" failed\n");
382 
383 	BN_free(r);
384 	BN_free(s);
385 	EC_KEY_free(eckey);
386 	EC_KEY_free(wrong_eckey);
387 	ECDSA_SIG_free(ecdsa_sig);
388 	free(signature);
389 	free(raw_buf);
390 	free(curves);
391 
392 	return failed;
393 }
394 
395 int
396 main(void)
397 {
398 	int failed = 1;
399 
400 	/* the tests */
401 	if (test_builtin())
402 		goto err;
403 
404 	printf("\nECDSA test passed\n");
405 	failed = 0;
406 
407  err:
408 	if (failed) {
409 		printf("\nECDSA test failed\n");
410 		ERR_print_errors_fp(stdout);
411 	}
412 
413 	CRYPTO_cleanup_all_ex_data();
414 	ERR_remove_thread_state(NULL);
415 	ERR_free_strings();
416 
417 	return failed;
418 }
419