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