xref: /openbsd-src/regress/lib/libcrypto/ecdsa/ecdsatest.c (revision 48185ea66a1c7a7267ac8e9df330ea60c96ff82d)
1 /*	$OpenBSD: ecdsatest.c,v 1.16 2023/05/04 13:49:29 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 int test_builtin(void);
87 
88 int
89 test_builtin(void)
90 {
91 	unsigned char digest[20], wrong_digest[20];
92 	EC_builtin_curve *curves = NULL;
93 	size_t num_curves = 0, n = 0;
94 	EC_KEY *eckey = NULL, *wrong_eckey = NULL;
95 	EC_GROUP *group;
96 	ECDSA_SIG *ecdsa_sig = NULL;
97 	BIGNUM *r = NULL, *s = NULL;
98 	unsigned char *signature = NULL;
99 	const unsigned char *sig_ptr;
100 	unsigned char *sig_ptr2;
101 	unsigned char *raw_buf = NULL;
102 	unsigned int sig_len, degree, r_len, s_len, bn_len, buf_len;
103 	int nid;
104 	int failed = 1;
105 
106 	/* fill digest values with some random data */
107 	arc4random_buf(digest, 20);
108 	arc4random_buf(wrong_digest, 20);
109 
110 	/* create and verify a ecdsa signature with every available curve */
111 	printf("\ntesting ECDSA_sign() and ECDSA_verify() "
112 	    "with some internal curves:\n");
113 
114 	/* get a list of all internal curves */
115 	num_curves = EC_get_builtin_curves(NULL, 0);
116 
117 	curves = reallocarray(NULL, sizeof(EC_builtin_curve), num_curves);
118 	if (curves == NULL) {
119 		printf("reallocarray error\n");
120 		goto err;
121 	}
122 
123 	if (!EC_get_builtin_curves(curves, num_curves)) {
124 		printf("unable to get internal curves\n");
125 		goto err;
126 	}
127 
128 	/* now create and verify a signature for every curve */
129 	for (n = 0; n < num_curves; n++) {
130 		unsigned char dirt, offset;
131 
132 		nid = curves[n].nid;
133 		if (nid == NID_ipsec4)
134 			continue;
135 
136 		if ((eckey = EC_KEY_new()) == NULL)
137 			goto err;
138 		group = EC_GROUP_new_by_curve_name(nid);
139 		if (group == NULL)
140 			goto err;
141 		if (EC_KEY_set_group(eckey, group) == 0)
142 			goto err;
143 		degree = EC_GROUP_get_degree(group);
144 		EC_GROUP_free(group);
145 		if (degree < 160) {
146 			/* drop the curve */
147 			EC_KEY_free(eckey);
148 			eckey = NULL;
149 			continue;
150 		}
151 		printf("%s: ", OBJ_nid2sn(nid));
152 
153 		if (!EC_KEY_generate_key(eckey)) {
154 			goto err;
155 		}
156 
157 		/* Exercise ECParameters_dup() and let ASAN test for leaks. */
158 		if ((wrong_eckey = ECParameters_dup(key)) == NULL)
159 			goto err;
160 		group = EC_GROUP_new_by_curve_name(nid);
161 		if (group == NULL)
162 			goto err;
163 		if (EC_KEY_set_group(wrong_eckey, group) == 0)
164 			goto err;
165 		EC_GROUP_free(group);
166 		if (!EC_KEY_generate_key(wrong_eckey))
167 			goto err;
168 
169 		printf(".");
170 		fflush(stdout);
171 
172 		if (!EC_KEY_check_key(eckey))
173 			goto err;
174 
175 		printf(".");
176 		fflush(stdout);
177 
178 		if ((sig_len = ECDSA_size(eckey)) == 0)
179 			goto err;
180 		if ((signature = malloc(sig_len)) == NULL)
181 			goto err;
182 		if (!ECDSA_sign(0, digest, 20, signature, &sig_len, eckey))
183 			goto err;
184 
185 		printf(".");
186 		fflush(stdout);
187 
188 		if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) != 1)
189 			goto err;
190 
191 		printf(".");
192 		fflush(stdout);
193 
194 		/* verify signature with the wrong key */
195 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
196 		    wrong_eckey) == 1)
197 			goto err;
198 
199 		printf(".");
200 		fflush(stdout);
201 
202 		if (ECDSA_verify(0, wrong_digest, 20, signature, sig_len,
203 		    eckey) == 1)
204 			goto err;
205 
206 		printf(".");
207 		fflush(stdout);
208 
209 		if (ECDSA_verify(0, digest, 20, signature, sig_len - 1,
210 		    eckey) == 1)
211 			goto err;
212 
213 		printf(".");
214 		fflush(stdout);
215 
216 		/*
217 		 * Modify a single byte of the signature: to ensure we don't
218 		 * garble the ASN1 structure, we read the raw signature and
219 		 * modify a byte in one of the bignums directly.
220 		 */
221 		sig_ptr = signature;
222 		if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr,
223 		    sig_len)) == NULL)
224 			goto err;
225 
226 		/* Store the two BIGNUMs in raw_buf. */
227 		r_len = BN_num_bytes(ECDSA_SIG_get0_r(ecdsa_sig));
228 		s_len = BN_num_bytes(ECDSA_SIG_get0_s(ecdsa_sig));
229 		bn_len = (degree + 7) / 8;
230 		if ((r_len > bn_len) || (s_len > bn_len))
231 			goto err;
232 
233 		buf_len = 2 * bn_len;
234 		if ((raw_buf = calloc(1, buf_len)) == NULL)
235 			goto err;
236 		BN_bn2bin(ECDSA_SIG_get0_r(ecdsa_sig),
237 		    raw_buf + bn_len - r_len);
238 		BN_bn2bin(ECDSA_SIG_get0_s(ecdsa_sig),
239 		    raw_buf + buf_len - s_len);
240 
241 		/* Modify a single byte in the buffer. */
242 		offset = raw_buf[10] % buf_len;
243 		dirt = raw_buf[11] ? raw_buf[11] : 1;
244 		raw_buf[offset] ^= dirt;
245 		/* Now read the BIGNUMs back in from raw_buf. */
246 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
247 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
248 			goto err;
249 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
250 			goto err;
251 		r = NULL;
252 		s = NULL;
253 
254 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL)) <= 0)
255 			goto err;
256 		free(signature);
257 		if ((signature = calloc(1, sig_len)) == NULL)
258 			goto err;
259 
260 		sig_ptr2 = signature;
261 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2)) <= 0)
262 			goto err;
263 		if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) == 1)
264 			goto err;
265 
266 		/* Sanity check: undo the modification and verify signature. */
267 		raw_buf[offset] ^= dirt;
268 		if ((r = BN_bin2bn(raw_buf, bn_len, NULL)) == NULL ||
269 		    (s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) == NULL)
270 			goto err;
271 		if (!ECDSA_SIG_set0(ecdsa_sig, r, s))
272 			goto err;
273 		r = NULL;
274 		s = NULL;
275 
276 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL)) <= 0)
277 			goto err;
278 		free(signature);
279 		if ((signature = calloc(1, sig_len)) == NULL)
280 			goto err;
281 
282 		sig_ptr2 = signature;
283 		if ((sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2)) <= 0)
284 			goto err;
285 		if (ECDSA_verify(0, digest, 20, signature, sig_len,
286 		    eckey) != 1)
287 			goto err;
288 
289 		printf(".");
290 		fflush(stdout);
291 
292 		printf(" ok\n");
293 
294 		ERR_clear_error();
295 		free(signature);
296 		signature = NULL;
297 		EC_KEY_free(eckey);
298 		eckey = NULL;
299 		EC_KEY_free(wrong_eckey);
300 		wrong_eckey = NULL;
301 		ECDSA_SIG_free(ecdsa_sig);
302 		ecdsa_sig = NULL;
303 		free(raw_buf);
304 		raw_buf = NULL;
305 	}
306 
307 	failed = 0;
308 
309  err:
310 	if (failed)
311 		printf(" failed\n");
312 
313 	BN_free(r);
314 	BN_free(s);
315 	EC_KEY_free(eckey);
316 	EC_KEY_free(wrong_eckey);
317 	ECDSA_SIG_free(ecdsa_sig);
318 	free(signature);
319 	free(raw_buf);
320 	free(curves);
321 
322 	return failed;
323 }
324 
325 int
326 main(void)
327 {
328 	int failed = 1;
329 
330 	/* the tests */
331 	if (test_builtin())
332 		goto err;
333 
334 	printf("\nECDSA test passed\n");
335 	failed = 0;
336 
337  err:
338 	if (failed) {
339 		printf("\nECDSA test failed\n");
340 		ERR_print_errors_fp(stdout);
341 	}
342 
343 	CRYPTO_cleanup_all_ex_data();
344 	ERR_remove_thread_state(NULL);
345 	ERR_free_strings();
346 
347 	return failed;
348 }
349