1 /* $OpenBSD: ecdhtest.c,v 1.12 2021/12/29 22:58:40 tb Exp $ */ 2 /* ==================================================================== 3 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 4 * 5 * The Elliptic Curve Public-Key Crypto Library (ECC Code) included 6 * herein is developed by SUN MICROSYSTEMS, INC., and is contributed 7 * to the OpenSSL project. 8 * 9 * The ECC Code is licensed pursuant to the OpenSSL open source 10 * license provided below. 11 * 12 * The ECDH software is originally written by Douglas Stebila of 13 * Sun Microsystems Laboratories. 14 * 15 */ 16 /* ==================================================================== 17 * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in 28 * the documentation and/or other materials provided with the 29 * distribution. 30 * 31 * 3. All advertising materials mentioning features or use of this 32 * software must display the following acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 35 * 36 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 37 * endorse or promote products derived from this software without 38 * prior written permission. For written permission, please contact 39 * openssl-core@openssl.org. 40 * 41 * 5. Products derived from this software may not be called "OpenSSL" 42 * nor may "OpenSSL" appear in their names without prior written 43 * permission of the OpenSSL Project. 44 * 45 * 6. Redistributions of any form whatsoever must retain the following 46 * acknowledgment: 47 * "This product includes software developed by the OpenSSL Project 48 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 51 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 54 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 56 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 59 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 61 * OF THE POSSIBILITY OF SUCH DAMAGE. 62 * ==================================================================== 63 * 64 * This product includes cryptographic software written by Eric Young 65 * (eay@cryptsoft.com). This product includes software written by Tim 66 * Hudson (tjh@cryptsoft.com). 67 * 68 */ 69 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <string.h> 73 74 #include <openssl/crypto.h> 75 #include <openssl/bio.h> 76 #include <openssl/bn.h> 77 #include <openssl/objects.h> 78 #include <openssl/sha.h> 79 #include <openssl/err.h> 80 81 #include <openssl/ec.h> 82 #include <openssl/ecdh.h> 83 84 static const int KDF1_SHA1_len = 20; 85 static void * 86 KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen) 87 { 88 #ifndef OPENSSL_NO_SHA 89 if (*outlen < SHA_DIGEST_LENGTH) 90 return NULL; 91 else 92 *outlen = SHA_DIGEST_LENGTH; 93 return SHA1(in, inlen, out); 94 #else 95 return NULL; 96 #endif 97 } 98 99 100 static int 101 test_ecdh_curve(int nid, const char *text, BN_CTX *ctx, BIO *out) 102 { 103 BIGNUM *x_a = NULL, *y_a = NULL, *x_b = NULL, *y_b = NULL; 104 EC_KEY *a = NULL, *b = NULL; 105 const EC_GROUP *group; 106 unsigned char *abuf = NULL, *bbuf = NULL; 107 int i, alen, blen, aout, bout, ret = 0; 108 char buf[12]; 109 110 a = EC_KEY_new_by_curve_name(nid); 111 b = EC_KEY_new_by_curve_name(nid); 112 if (a == NULL || b == NULL) 113 goto err; 114 115 group = EC_KEY_get0_group(a); 116 117 if ((x_a = BN_new()) == NULL) 118 goto err; 119 if ((y_a = BN_new()) == NULL) 120 goto err; 121 if ((x_b = BN_new()) == NULL) 122 goto err; 123 if ((y_b = BN_new()) == NULL) 124 goto err; 125 126 BIO_puts(out, "Testing key generation with "); 127 BIO_puts(out, text); 128 (void)BIO_flush(out); 129 130 if (!EC_KEY_generate_key(a)) 131 goto err; 132 133 if (!EC_POINT_get_affine_coordinates(group, 134 EC_KEY_get0_public_key(a), x_a, y_a, ctx)) goto err; 135 136 BIO_printf(out, " ."); 137 (void)BIO_flush(out); 138 139 if (!EC_KEY_generate_key(b)) 140 goto err; 141 142 if (!EC_POINT_get_affine_coordinates(group, 143 EC_KEY_get0_public_key(b), x_b, y_b, ctx)) goto err; 144 145 BIO_printf(out, "."); 146 (void)BIO_flush(out); 147 148 alen = KDF1_SHA1_len; 149 abuf = malloc(alen); 150 aout = ECDH_compute_key(abuf, alen, EC_KEY_get0_public_key(b), 151 a, KDF1_SHA1); 152 153 BIO_printf(out, "."); 154 (void)BIO_flush(out); 155 156 blen = KDF1_SHA1_len; 157 bbuf = malloc(blen); 158 bout = ECDH_compute_key(bbuf, blen, EC_KEY_get0_public_key(a), 159 b, KDF1_SHA1); 160 161 BIO_printf(out, "."); 162 (void)BIO_flush(out); 163 164 if ((aout < 4) || (bout != aout) || (memcmp(abuf, bbuf, aout) != 0)) { 165 BIO_printf(out, " failed\n\n"); 166 BIO_printf(out, "key a:\n"); 167 BIO_printf(out, "private key: "); 168 BN_print(out, EC_KEY_get0_private_key(a)); 169 BIO_printf(out, "\n"); 170 BIO_printf(out, "public key (x,y): "); 171 BN_print(out, x_a); 172 BIO_printf(out, ","); 173 BN_print(out, y_a); 174 BIO_printf(out, "\nkey b:\n"); 175 BIO_printf(out, "private key: "); 176 BN_print(out, EC_KEY_get0_private_key(b)); 177 BIO_printf(out, "\n"); 178 BIO_printf(out, "public key (x,y): "); 179 BN_print(out, x_b); 180 BIO_printf(out, ","); 181 BN_print(out, y_b); 182 BIO_printf(out, "\n"); 183 BIO_printf(out, "generated key a: "); 184 for (i = 0; i < bout; i++) { 185 snprintf(buf, sizeof buf, "%02X", bbuf[i]); 186 BIO_puts(out, buf); 187 } 188 BIO_printf(out, "\n"); 189 BIO_printf(out, "generated key b: "); 190 for (i = 0; i < aout; i++) { 191 snprintf(buf, sizeof buf, "%02X", abuf[i]); 192 BIO_puts(out, buf); 193 } 194 BIO_printf(out, "\n"); 195 fprintf(stderr, "Error in ECDH routines\n"); 196 ret = 0; 197 } else { 198 BIO_printf(out, " ok\n"); 199 ret = 1; 200 } 201 202 err: 203 ERR_print_errors_fp(stderr); 204 205 free(abuf); 206 free(bbuf); 207 BN_free(x_a); 208 BN_free(y_a); 209 BN_free(x_b); 210 BN_free(y_b); 211 EC_KEY_free(b); 212 EC_KEY_free(a); 213 214 return (ret); 215 } 216 217 /* Keys and shared secrets from RFC 7027 */ 218 219 static const unsigned char bp256_da[] = { 220 0x81, 0xDB, 0x1E, 0xE1, 0x00, 0x15, 0x0F, 0xF2, 0xEA, 0x33, 0x8D, 0x70, 221 0x82, 0x71, 0xBE, 0x38, 0x30, 0x0C, 0xB5, 0x42, 0x41, 0xD7, 0x99, 0x50, 222 0xF7, 0x7B, 0x06, 0x30, 0x39, 0x80, 0x4F, 0x1D 223 }; 224 225 static const unsigned char bp256_db[] = { 226 0x55, 0xE4, 0x0B, 0xC4, 0x1E, 0x37, 0xE3, 0xE2, 0xAD, 0x25, 0xC3, 0xC6, 227 0x65, 0x45, 0x11, 0xFF, 0xA8, 0x47, 0x4A, 0x91, 0xA0, 0x03, 0x20, 0x87, 228 0x59, 0x38, 0x52, 0xD3, 0xE7, 0xD7, 0x6B, 0xD3 229 }; 230 231 static const unsigned char bp256_Z[] = { 232 0x89, 0xAF, 0xC3, 0x9D, 0x41, 0xD3, 0xB3, 0x27, 0x81, 0x4B, 0x80, 0x94, 233 0x0B, 0x04, 0x25, 0x90, 0xF9, 0x65, 0x56, 0xEC, 0x91, 0xE6, 0xAE, 0x79, 234 0x39, 0xBC, 0xE3, 0x1F, 0x3A, 0x18, 0xBF, 0x2B 235 }; 236 237 static const unsigned char bp384_da[] = { 238 0x1E, 0x20, 0xF5, 0xE0, 0x48, 0xA5, 0x88, 0x6F, 0x1F, 0x15, 0x7C, 0x74, 239 0xE9, 0x1B, 0xDE, 0x2B, 0x98, 0xC8, 0xB5, 0x2D, 0x58, 0xE5, 0x00, 0x3D, 240 0x57, 0x05, 0x3F, 0xC4, 0xB0, 0xBD, 0x65, 0xD6, 0xF1, 0x5E, 0xB5, 0xD1, 241 0xEE, 0x16, 0x10, 0xDF, 0x87, 0x07, 0x95, 0x14, 0x36, 0x27, 0xD0, 0x42 242 }; 243 244 static const unsigned char bp384_db[] = { 245 0x03, 0x26, 0x40, 0xBC, 0x60, 0x03, 0xC5, 0x92, 0x60, 0xF7, 0x25, 0x0C, 246 0x3D, 0xB5, 0x8C, 0xE6, 0x47, 0xF9, 0x8E, 0x12, 0x60, 0xAC, 0xCE, 0x4A, 247 0xCD, 0xA3, 0xDD, 0x86, 0x9F, 0x74, 0xE0, 0x1F, 0x8B, 0xA5, 0xE0, 0x32, 248 0x43, 0x09, 0xDB, 0x6A, 0x98, 0x31, 0x49, 0x7A, 0xBA, 0xC9, 0x66, 0x70 249 }; 250 251 static const unsigned char bp384_Z[] = { 252 0x0B, 0xD9, 0xD3, 0xA7, 0xEA, 0x0B, 0x3D, 0x51, 0x9D, 0x09, 0xD8, 0xE4, 253 0x8D, 0x07, 0x85, 0xFB, 0x74, 0x4A, 0x6B, 0x35, 0x5E, 0x63, 0x04, 0xBC, 254 0x51, 0xC2, 0x29, 0xFB, 0xBC, 0xE2, 0x39, 0xBB, 0xAD, 0xF6, 0x40, 0x37, 255 0x15, 0xC3, 0x5D, 0x4F, 0xB2, 0xA5, 0x44, 0x4F, 0x57, 0x5D, 0x4F, 0x42 256 }; 257 258 static const unsigned char bp512_da[] = { 259 0x16, 0x30, 0x2F, 0xF0, 0xDB, 0xBB, 0x5A, 0x8D, 0x73, 0x3D, 0xAB, 0x71, 260 0x41, 0xC1, 0xB4, 0x5A, 0xCB, 0xC8, 0x71, 0x59, 0x39, 0x67, 0x7F, 0x6A, 261 0x56, 0x85, 0x0A, 0x38, 0xBD, 0x87, 0xBD, 0x59, 0xB0, 0x9E, 0x80, 0x27, 262 0x96, 0x09, 0xFF, 0x33, 0x3E, 0xB9, 0xD4, 0xC0, 0x61, 0x23, 0x1F, 0xB2, 263 0x6F, 0x92, 0xEE, 0xB0, 0x49, 0x82, 0xA5, 0xF1, 0xD1, 0x76, 0x4C, 0xAD, 264 0x57, 0x66, 0x54, 0x22 265 }; 266 267 static const unsigned char bp512_db[] = { 268 0x23, 0x0E, 0x18, 0xE1, 0xBC, 0xC8, 0x8A, 0x36, 0x2F, 0xA5, 0x4E, 0x4E, 269 0xA3, 0x90, 0x20, 0x09, 0x29, 0x2F, 0x7F, 0x80, 0x33, 0x62, 0x4F, 0xD4, 270 0x71, 0xB5, 0xD8, 0xAC, 0xE4, 0x9D, 0x12, 0xCF, 0xAB, 0xBC, 0x19, 0x96, 271 0x3D, 0xAB, 0x8E, 0x2F, 0x1E, 0xBA, 0x00, 0xBF, 0xFB, 0x29, 0xE4, 0xD7, 272 0x2D, 0x13, 0xF2, 0x22, 0x45, 0x62, 0xF4, 0x05, 0xCB, 0x80, 0x50, 0x36, 273 0x66, 0xB2, 0x54, 0x29 274 }; 275 276 277 static const unsigned char bp512_Z[] = { 278 0xA7, 0x92, 0x70, 0x98, 0x65, 0x5F, 0x1F, 0x99, 0x76, 0xFA, 0x50, 0xA9, 279 0xD5, 0x66, 0x86, 0x5D, 0xC5, 0x30, 0x33, 0x18, 0x46, 0x38, 0x1C, 0x87, 280 0x25, 0x6B, 0xAF, 0x32, 0x26, 0x24, 0x4B, 0x76, 0xD3, 0x64, 0x03, 0xC0, 281 0x24, 0xD7, 0xBB, 0xF0, 0xAA, 0x08, 0x03, 0xEA, 0xFF, 0x40, 0x5D, 0x3D, 282 0x24, 0xF1, 0x1A, 0x9B, 0x5C, 0x0B, 0xEF, 0x67, 0x9F, 0xE1, 0x45, 0x4B, 283 0x21, 0xC4, 0xCD, 0x1F 284 }; 285 286 /* Given private value and NID, create EC_KEY structure */ 287 288 static EC_KEY * 289 mk_eckey(int nid, const unsigned char *p, size_t plen) 290 { 291 EC_KEY *k = NULL; 292 BIGNUM *priv = NULL; 293 EC_POINT *pub = NULL; 294 const EC_GROUP *grp; 295 int ok = 0; 296 297 k = EC_KEY_new_by_curve_name(nid); 298 if (!k) 299 goto err; 300 priv = BN_bin2bn(p, plen, NULL); 301 if (!priv) 302 goto err; 303 if (!EC_KEY_set_private_key(k, priv)) 304 goto err; 305 grp = EC_KEY_get0_group(k); 306 pub = EC_POINT_new(grp); 307 if (!pub) 308 goto err; 309 if (!EC_POINT_mul(grp, pub, priv, NULL, NULL, NULL)) 310 goto err; 311 if (!EC_KEY_set_public_key(k, pub)) 312 goto err; 313 ok = 1; 314 err: 315 BN_clear_free(priv); 316 EC_POINT_free(pub); 317 if (!ok) { 318 EC_KEY_free(k); 319 k = NULL; 320 } 321 return (k); 322 } 323 324 /* Known answer test: compute shared secret and check it matches 325 * expected value. 326 */ 327 328 static int 329 ecdh_kat(BIO *out, const char *cname, int nid, 330 const unsigned char *k1, size_t k1_len, 331 const unsigned char *k2, size_t k2_len, 332 const unsigned char *Z, size_t Zlen) 333 { 334 int rv = 0; 335 EC_KEY *key1 = NULL, *key2 = NULL; 336 unsigned char *Ztmp = NULL; 337 size_t Ztmplen; 338 BIO_puts(out, "Testing ECDH shared secret with "); 339 BIO_puts(out, cname); 340 key1 = mk_eckey(nid, k1, k1_len); 341 key2 = mk_eckey(nid, k2, k2_len); 342 if (!key1 || !key2) 343 goto err; 344 Ztmplen = ECDH_size(key1); 345 if (Ztmplen != Zlen) 346 goto err; 347 Ztmp = malloc(Ztmplen); 348 if (!ECDH_compute_key(Ztmp, Ztmplen, 349 EC_KEY_get0_public_key(key2), key1, 0)) 350 goto err; 351 if (memcmp(Ztmp, Z, Zlen)) 352 goto err; 353 memset(Ztmp, 0, Zlen); 354 if (!ECDH_compute_key(Ztmp, Ztmplen, 355 EC_KEY_get0_public_key(key1), key2, 0)) 356 goto err; 357 if (memcmp(Ztmp, Z, Zlen)) 358 goto err; 359 rv = 1; 360 361 err: 362 if (rv) 363 BIO_puts(out, " ok\n"); 364 else { 365 fprintf(stderr, "Error in ECDH routines\n"); 366 ERR_print_errors_fp(stderr); 367 } 368 369 EC_KEY_free(key1); 370 EC_KEY_free(key2); 371 free(Ztmp); 372 373 return rv; 374 } 375 376 #define test_ecdh_kat(bio, curve, bits) \ 377 ecdh_kat(bio, curve, NID_brainpoolP##bits##r1, \ 378 bp##bits##_da, sizeof(bp##bits##_da), \ 379 bp##bits##_db, sizeof(bp##bits##_db), \ 380 bp##bits##_Z, sizeof(bp##bits##_Z)) 381 382 int 383 main(int argc, char *argv[]) 384 { 385 BN_CTX *ctx = NULL; 386 int ret = 1; 387 BIO *out; 388 389 out = BIO_new(BIO_s_file()); 390 if (out == NULL) 391 exit(1); 392 BIO_set_fp(out, stdout, BIO_NOCLOSE); 393 394 if ((ctx = BN_CTX_new()) == NULL) 395 goto err; 396 397 /* NIST PRIME CURVES TESTS */ 398 if (!test_ecdh_curve(NID_X9_62_prime192v1, "NIST Prime-Curve P-192", 399 ctx, out)) 400 goto err; 401 if (!test_ecdh_curve(NID_secp224r1, "NIST Prime-Curve P-224", ctx, out)) 402 goto err; 403 if (!test_ecdh_curve(NID_X9_62_prime256v1, "NIST Prime-Curve P-256", 404 ctx, out)) 405 goto err; 406 if (!test_ecdh_curve(NID_secp384r1, "NIST Prime-Curve P-384", ctx, out)) 407 goto err; 408 if (!test_ecdh_curve(NID_secp521r1, "NIST Prime-Curve P-521", ctx, out)) 409 goto err; 410 #ifndef OPENSSL_NO_EC2M 411 /* NIST BINARY CURVES TESTS */ 412 if (!test_ecdh_curve(NID_sect163k1, "NIST Binary-Curve K-163", 413 ctx, out)) 414 goto err; 415 if (!test_ecdh_curve(NID_sect163r2, "NIST Binary-Curve B-163", 416 ctx, out)) 417 goto err; 418 if (!test_ecdh_curve(NID_sect233k1, "NIST Binary-Curve K-233", 419 ctx, out)) 420 goto err; 421 if (!test_ecdh_curve(NID_sect233r1, "NIST Binary-Curve B-233", 422 ctx, out)) 423 goto err; 424 if (!test_ecdh_curve(NID_sect283k1, "NIST Binary-Curve K-283", 425 ctx, out)) 426 goto err; 427 if (!test_ecdh_curve(NID_sect283r1, "NIST Binary-Curve B-283", 428 ctx, out)) 429 goto err; 430 if (!test_ecdh_curve(NID_sect409k1, "NIST Binary-Curve K-409", 431 ctx, out)) 432 goto err; 433 if (!test_ecdh_curve(NID_sect409r1, "NIST Binary-Curve B-409", 434 ctx, out)) 435 goto err; 436 if (!test_ecdh_curve(NID_sect571k1, "NIST Binary-Curve K-571", 437 ctx, out)) 438 goto err; 439 if (!test_ecdh_curve(NID_sect571r1, "NIST Binary-Curve B-571", 440 ctx, out)) 441 goto err; 442 #endif 443 if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP256r1", 256)) 444 goto err; 445 if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP384r1", 384)) 446 goto err; 447 if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP512r1", 512)) 448 goto err; 449 450 ret = 0; 451 452 err: 453 ERR_print_errors_fp(stderr); 454 BN_CTX_free(ctx); 455 BIO_free(out); 456 CRYPTO_cleanup_all_ex_data(); 457 ERR_remove_thread_state(NULL); 458 CRYPTO_mem_leaks_fp(stderr); 459 exit(ret); 460 } 461