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
test_builtin(void)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
main(void)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