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