1 /* $OpenBSD: ecdhtest.c,v 1.10 2018/07/17 17:06:49 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_METHOD_get_field_type(EC_GROUP_method_of(group)) == 134 NID_X9_62_prime_field) { 135 if (!EC_POINT_get_affine_coordinates_GFp(group, 136 EC_KEY_get0_public_key(a), x_a, y_a, ctx)) goto err; 137 } 138 #ifndef OPENSSL_NO_EC2M 139 else { 140 if (!EC_POINT_get_affine_coordinates_GF2m(group, 141 EC_KEY_get0_public_key(a), x_a, y_a, ctx)) goto err; 142 } 143 #endif 144 BIO_printf(out, " ."); 145 (void)BIO_flush(out); 146 147 if (!EC_KEY_generate_key(b)) 148 goto err; 149 150 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == 151 NID_X9_62_prime_field) { 152 if (!EC_POINT_get_affine_coordinates_GFp(group, 153 EC_KEY_get0_public_key(b), x_b, y_b, ctx)) goto err; 154 } 155 #ifndef OPENSSL_NO_EC2M 156 else { 157 if (!EC_POINT_get_affine_coordinates_GF2m(group, 158 EC_KEY_get0_public_key(b), x_b, y_b, ctx)) goto err; 159 } 160 #endif 161 162 BIO_printf(out, "."); 163 (void)BIO_flush(out); 164 165 alen = KDF1_SHA1_len; 166 abuf = malloc(alen); 167 aout = ECDH_compute_key(abuf, alen, EC_KEY_get0_public_key(b), 168 a, KDF1_SHA1); 169 170 BIO_printf(out, "."); 171 (void)BIO_flush(out); 172 173 blen = KDF1_SHA1_len; 174 bbuf = malloc(blen); 175 bout = ECDH_compute_key(bbuf, blen, EC_KEY_get0_public_key(a), 176 b, KDF1_SHA1); 177 178 BIO_printf(out, "."); 179 (void)BIO_flush(out); 180 181 if ((aout < 4) || (bout != aout) || (memcmp(abuf, bbuf, aout) != 0)) { 182 BIO_printf(out, " failed\n\n"); 183 BIO_printf(out, "key a:\n"); 184 BIO_printf(out, "private key: "); 185 BN_print(out, EC_KEY_get0_private_key(a)); 186 BIO_printf(out, "\n"); 187 BIO_printf(out, "public key (x,y): "); 188 BN_print(out, x_a); 189 BIO_printf(out, ","); 190 BN_print(out, y_a); 191 BIO_printf(out, "\nkey b:\n"); 192 BIO_printf(out, "private key: "); 193 BN_print(out, EC_KEY_get0_private_key(b)); 194 BIO_printf(out, "\n"); 195 BIO_printf(out, "public key (x,y): "); 196 BN_print(out, x_b); 197 BIO_printf(out, ","); 198 BN_print(out, y_b); 199 BIO_printf(out, "\n"); 200 BIO_printf(out, "generated key a: "); 201 for (i = 0; i < bout; i++) { 202 snprintf(buf, sizeof buf, "%02X", bbuf[i]); 203 BIO_puts(out, buf); 204 } 205 BIO_printf(out, "\n"); 206 BIO_printf(out, "generated key b: "); 207 for (i = 0; i < aout; i++) { 208 snprintf(buf, sizeof buf, "%02X", abuf[i]); 209 BIO_puts(out, buf); 210 } 211 BIO_printf(out, "\n"); 212 fprintf(stderr, "Error in ECDH routines\n"); 213 ret = 0; 214 } else { 215 BIO_printf(out, " ok\n"); 216 ret = 1; 217 } 218 219 err: 220 ERR_print_errors_fp(stderr); 221 222 free(abuf); 223 free(bbuf); 224 BN_free(x_a); 225 BN_free(y_a); 226 BN_free(x_b); 227 BN_free(y_b); 228 EC_KEY_free(b); 229 EC_KEY_free(a); 230 231 return (ret); 232 } 233 234 /* Keys and shared secrets from RFC 7027 */ 235 236 static const unsigned char bp256_da[] = { 237 0x81, 0xDB, 0x1E, 0xE1, 0x00, 0x15, 0x0F, 0xF2, 0xEA, 0x33, 0x8D, 0x70, 238 0x82, 0x71, 0xBE, 0x38, 0x30, 0x0C, 0xB5, 0x42, 0x41, 0xD7, 0x99, 0x50, 239 0xF7, 0x7B, 0x06, 0x30, 0x39, 0x80, 0x4F, 0x1D 240 }; 241 242 static const unsigned char bp256_db[] = { 243 0x55, 0xE4, 0x0B, 0xC4, 0x1E, 0x37, 0xE3, 0xE2, 0xAD, 0x25, 0xC3, 0xC6, 244 0x65, 0x45, 0x11, 0xFF, 0xA8, 0x47, 0x4A, 0x91, 0xA0, 0x03, 0x20, 0x87, 245 0x59, 0x38, 0x52, 0xD3, 0xE7, 0xD7, 0x6B, 0xD3 246 }; 247 248 static const unsigned char bp256_Z[] = { 249 0x89, 0xAF, 0xC3, 0x9D, 0x41, 0xD3, 0xB3, 0x27, 0x81, 0x4B, 0x80, 0x94, 250 0x0B, 0x04, 0x25, 0x90, 0xF9, 0x65, 0x56, 0xEC, 0x91, 0xE6, 0xAE, 0x79, 251 0x39, 0xBC, 0xE3, 0x1F, 0x3A, 0x18, 0xBF, 0x2B 252 }; 253 254 static const unsigned char bp384_da[] = { 255 0x1E, 0x20, 0xF5, 0xE0, 0x48, 0xA5, 0x88, 0x6F, 0x1F, 0x15, 0x7C, 0x74, 256 0xE9, 0x1B, 0xDE, 0x2B, 0x98, 0xC8, 0xB5, 0x2D, 0x58, 0xE5, 0x00, 0x3D, 257 0x57, 0x05, 0x3F, 0xC4, 0xB0, 0xBD, 0x65, 0xD6, 0xF1, 0x5E, 0xB5, 0xD1, 258 0xEE, 0x16, 0x10, 0xDF, 0x87, 0x07, 0x95, 0x14, 0x36, 0x27, 0xD0, 0x42 259 }; 260 261 static const unsigned char bp384_db[] = { 262 0x03, 0x26, 0x40, 0xBC, 0x60, 0x03, 0xC5, 0x92, 0x60, 0xF7, 0x25, 0x0C, 263 0x3D, 0xB5, 0x8C, 0xE6, 0x47, 0xF9, 0x8E, 0x12, 0x60, 0xAC, 0xCE, 0x4A, 264 0xCD, 0xA3, 0xDD, 0x86, 0x9F, 0x74, 0xE0, 0x1F, 0x8B, 0xA5, 0xE0, 0x32, 265 0x43, 0x09, 0xDB, 0x6A, 0x98, 0x31, 0x49, 0x7A, 0xBA, 0xC9, 0x66, 0x70 266 }; 267 268 static const unsigned char bp384_Z[] = { 269 0x0B, 0xD9, 0xD3, 0xA7, 0xEA, 0x0B, 0x3D, 0x51, 0x9D, 0x09, 0xD8, 0xE4, 270 0x8D, 0x07, 0x85, 0xFB, 0x74, 0x4A, 0x6B, 0x35, 0x5E, 0x63, 0x04, 0xBC, 271 0x51, 0xC2, 0x29, 0xFB, 0xBC, 0xE2, 0x39, 0xBB, 0xAD, 0xF6, 0x40, 0x37, 272 0x15, 0xC3, 0x5D, 0x4F, 0xB2, 0xA5, 0x44, 0x4F, 0x57, 0x5D, 0x4F, 0x42 273 }; 274 275 static const unsigned char bp512_da[] = { 276 0x16, 0x30, 0x2F, 0xF0, 0xDB, 0xBB, 0x5A, 0x8D, 0x73, 0x3D, 0xAB, 0x71, 277 0x41, 0xC1, 0xB4, 0x5A, 0xCB, 0xC8, 0x71, 0x59, 0x39, 0x67, 0x7F, 0x6A, 278 0x56, 0x85, 0x0A, 0x38, 0xBD, 0x87, 0xBD, 0x59, 0xB0, 0x9E, 0x80, 0x27, 279 0x96, 0x09, 0xFF, 0x33, 0x3E, 0xB9, 0xD4, 0xC0, 0x61, 0x23, 0x1F, 0xB2, 280 0x6F, 0x92, 0xEE, 0xB0, 0x49, 0x82, 0xA5, 0xF1, 0xD1, 0x76, 0x4C, 0xAD, 281 0x57, 0x66, 0x54, 0x22 282 }; 283 284 static const unsigned char bp512_db[] = { 285 0x23, 0x0E, 0x18, 0xE1, 0xBC, 0xC8, 0x8A, 0x36, 0x2F, 0xA5, 0x4E, 0x4E, 286 0xA3, 0x90, 0x20, 0x09, 0x29, 0x2F, 0x7F, 0x80, 0x33, 0x62, 0x4F, 0xD4, 287 0x71, 0xB5, 0xD8, 0xAC, 0xE4, 0x9D, 0x12, 0xCF, 0xAB, 0xBC, 0x19, 0x96, 288 0x3D, 0xAB, 0x8E, 0x2F, 0x1E, 0xBA, 0x00, 0xBF, 0xFB, 0x29, 0xE4, 0xD7, 289 0x2D, 0x13, 0xF2, 0x22, 0x45, 0x62, 0xF4, 0x05, 0xCB, 0x80, 0x50, 0x36, 290 0x66, 0xB2, 0x54, 0x29 291 }; 292 293 294 static const unsigned char bp512_Z[] = { 295 0xA7, 0x92, 0x70, 0x98, 0x65, 0x5F, 0x1F, 0x99, 0x76, 0xFA, 0x50, 0xA9, 296 0xD5, 0x66, 0x86, 0x5D, 0xC5, 0x30, 0x33, 0x18, 0x46, 0x38, 0x1C, 0x87, 297 0x25, 0x6B, 0xAF, 0x32, 0x26, 0x24, 0x4B, 0x76, 0xD3, 0x64, 0x03, 0xC0, 298 0x24, 0xD7, 0xBB, 0xF0, 0xAA, 0x08, 0x03, 0xEA, 0xFF, 0x40, 0x5D, 0x3D, 299 0x24, 0xF1, 0x1A, 0x9B, 0x5C, 0x0B, 0xEF, 0x67, 0x9F, 0xE1, 0x45, 0x4B, 300 0x21, 0xC4, 0xCD, 0x1F 301 }; 302 303 /* Given private value and NID, create EC_KEY structure */ 304 305 static EC_KEY * 306 mk_eckey(int nid, const unsigned char *p, size_t plen) 307 { 308 EC_KEY *k = NULL; 309 BIGNUM *priv = NULL; 310 EC_POINT *pub = NULL; 311 const EC_GROUP *grp; 312 int ok = 0; 313 314 k = EC_KEY_new_by_curve_name(nid); 315 if (!k) 316 goto err; 317 priv = BN_bin2bn(p, plen, NULL); 318 if (!priv) 319 goto err; 320 if (!EC_KEY_set_private_key(k, priv)) 321 goto err; 322 grp = EC_KEY_get0_group(k); 323 pub = EC_POINT_new(grp); 324 if (!pub) 325 goto err; 326 if (!EC_POINT_mul(grp, pub, priv, NULL, NULL, NULL)) 327 goto err; 328 if (!EC_KEY_set_public_key(k, pub)) 329 goto err; 330 ok = 1; 331 err: 332 BN_clear_free(priv); 333 EC_POINT_free(pub); 334 if (!ok) { 335 EC_KEY_free(k); 336 k = NULL; 337 } 338 return (k); 339 } 340 341 /* Known answer test: compute shared secret and check it matches 342 * expected value. 343 */ 344 345 static int 346 ecdh_kat(BIO *out, const char *cname, int nid, 347 const unsigned char *k1, size_t k1_len, 348 const unsigned char *k2, size_t k2_len, 349 const unsigned char *Z, size_t Zlen) 350 { 351 int rv = 0; 352 EC_KEY *key1 = NULL, *key2 = NULL; 353 unsigned char *Ztmp = NULL; 354 size_t Ztmplen; 355 BIO_puts(out, "Testing ECDH shared secret with "); 356 BIO_puts(out, cname); 357 key1 = mk_eckey(nid, k1, k1_len); 358 key2 = mk_eckey(nid, k2, k2_len); 359 if (!key1 || !key2) 360 goto err; 361 Ztmplen = ECDH_size(key1); 362 if (Ztmplen != Zlen) 363 goto err; 364 Ztmp = malloc(Ztmplen); 365 if (!ECDH_compute_key(Ztmp, Ztmplen, 366 EC_KEY_get0_public_key(key2), key1, 0)) 367 goto err; 368 if (memcmp(Ztmp, Z, Zlen)) 369 goto err; 370 memset(Ztmp, 0, Zlen); 371 if (!ECDH_compute_key(Ztmp, Ztmplen, 372 EC_KEY_get0_public_key(key1), key2, 0)) 373 goto err; 374 if (memcmp(Ztmp, Z, Zlen)) 375 goto err; 376 rv = 1; 377 378 err: 379 if (rv) 380 BIO_puts(out, " ok\n"); 381 else { 382 fprintf(stderr, "Error in ECDH routines\n"); 383 ERR_print_errors_fp(stderr); 384 } 385 386 EC_KEY_free(key1); 387 EC_KEY_free(key2); 388 free(Ztmp); 389 390 return rv; 391 } 392 393 #define test_ecdh_kat(bio, curve, bits) \ 394 ecdh_kat(bio, curve, NID_brainpoolP##bits##r1, \ 395 bp##bits##_da, sizeof(bp##bits##_da), \ 396 bp##bits##_db, sizeof(bp##bits##_db), \ 397 bp##bits##_Z, sizeof(bp##bits##_Z)) 398 399 int 400 main(int argc, char *argv[]) 401 { 402 BN_CTX *ctx = NULL; 403 int ret = 1; 404 BIO *out; 405 406 out = BIO_new(BIO_s_file()); 407 if (out == NULL) 408 exit(1); 409 BIO_set_fp(out, stdout, BIO_NOCLOSE); 410 411 if ((ctx = BN_CTX_new()) == NULL) 412 goto err; 413 414 /* NIST PRIME CURVES TESTS */ 415 if (!test_ecdh_curve(NID_X9_62_prime192v1, "NIST Prime-Curve P-192", 416 ctx, out)) 417 goto err; 418 if (!test_ecdh_curve(NID_secp224r1, "NIST Prime-Curve P-224", ctx, out)) 419 goto err; 420 if (!test_ecdh_curve(NID_X9_62_prime256v1, "NIST Prime-Curve P-256", 421 ctx, out)) 422 goto err; 423 if (!test_ecdh_curve(NID_secp384r1, "NIST Prime-Curve P-384", ctx, out)) 424 goto err; 425 if (!test_ecdh_curve(NID_secp521r1, "NIST Prime-Curve P-521", ctx, out)) 426 goto err; 427 #ifndef OPENSSL_NO_EC2M 428 /* NIST BINARY CURVES TESTS */ 429 if (!test_ecdh_curve(NID_sect163k1, "NIST Binary-Curve K-163", 430 ctx, out)) 431 goto err; 432 if (!test_ecdh_curve(NID_sect163r2, "NIST Binary-Curve B-163", 433 ctx, out)) 434 goto err; 435 if (!test_ecdh_curve(NID_sect233k1, "NIST Binary-Curve K-233", 436 ctx, out)) 437 goto err; 438 if (!test_ecdh_curve(NID_sect233r1, "NIST Binary-Curve B-233", 439 ctx, out)) 440 goto err; 441 if (!test_ecdh_curve(NID_sect283k1, "NIST Binary-Curve K-283", 442 ctx, out)) 443 goto err; 444 if (!test_ecdh_curve(NID_sect283r1, "NIST Binary-Curve B-283", 445 ctx, out)) 446 goto err; 447 if (!test_ecdh_curve(NID_sect409k1, "NIST Binary-Curve K-409", 448 ctx, out)) 449 goto err; 450 if (!test_ecdh_curve(NID_sect409r1, "NIST Binary-Curve B-409", 451 ctx, out)) 452 goto err; 453 if (!test_ecdh_curve(NID_sect571k1, "NIST Binary-Curve K-571", 454 ctx, out)) 455 goto err; 456 if (!test_ecdh_curve(NID_sect571r1, "NIST Binary-Curve B-571", 457 ctx, out)) 458 goto err; 459 #endif 460 if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP256r1", 256)) 461 goto err; 462 if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP384r1", 384)) 463 goto err; 464 if (!test_ecdh_kat(out, "Brainpool Prime-Curve brainpoolP512r1", 512)) 465 goto err; 466 467 ret = 0; 468 469 err: 470 ERR_print_errors_fp(stderr); 471 BN_CTX_free(ctx); 472 BIO_free(out); 473 CRYPTO_cleanup_all_ex_data(); 474 ERR_remove_thread_state(NULL); 475 CRYPTO_mem_leaks_fp(stderr); 476 exit(ret); 477 } 478