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