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