1*35671554Stb /* $OpenBSD: ecdhtest.c,v 1.22 2024/12/24 18:32:31 tb Exp $ */ 23c6bd008Smiod /* ==================================================================== 33c6bd008Smiod * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 43c6bd008Smiod * 53c6bd008Smiod * The Elliptic Curve Public-Key Crypto Library (ECC Code) included 63c6bd008Smiod * herein is developed by SUN MICROSYSTEMS, INC., and is contributed 73c6bd008Smiod * to the OpenSSL project. 83c6bd008Smiod * 93c6bd008Smiod * The ECC Code is licensed pursuant to the OpenSSL open source 103c6bd008Smiod * license provided below. 113c6bd008Smiod * 123c6bd008Smiod * The ECDH software is originally written by Douglas Stebila of 133c6bd008Smiod * Sun Microsystems Laboratories. 143c6bd008Smiod * 153c6bd008Smiod */ 163c6bd008Smiod /* ==================================================================== 173c6bd008Smiod * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. 183c6bd008Smiod * 193c6bd008Smiod * Redistribution and use in source and binary forms, with or without 203c6bd008Smiod * modification, are permitted provided that the following conditions 213c6bd008Smiod * are met: 223c6bd008Smiod * 233c6bd008Smiod * 1. Redistributions of source code must retain the above copyright 243c6bd008Smiod * notice, this list of conditions and the following disclaimer. 253c6bd008Smiod * 263c6bd008Smiod * 2. Redistributions in binary form must reproduce the above copyright 273c6bd008Smiod * notice, this list of conditions and the following disclaimer in 283c6bd008Smiod * the documentation and/or other materials provided with the 293c6bd008Smiod * distribution. 303c6bd008Smiod * 313c6bd008Smiod * 3. All advertising materials mentioning features or use of this 323c6bd008Smiod * software must display the following acknowledgment: 333c6bd008Smiod * "This product includes software developed by the OpenSSL Project 343c6bd008Smiod * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 353c6bd008Smiod * 363c6bd008Smiod * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 373c6bd008Smiod * endorse or promote products derived from this software without 383c6bd008Smiod * prior written permission. For written permission, please contact 393c6bd008Smiod * openssl-core@openssl.org. 403c6bd008Smiod * 413c6bd008Smiod * 5. Products derived from this software may not be called "OpenSSL" 423c6bd008Smiod * nor may "OpenSSL" appear in their names without prior written 433c6bd008Smiod * permission of the OpenSSL Project. 443c6bd008Smiod * 453c6bd008Smiod * 6. Redistributions of any form whatsoever must retain the following 463c6bd008Smiod * acknowledgment: 473c6bd008Smiod * "This product includes software developed by the OpenSSL Project 483c6bd008Smiod * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 493c6bd008Smiod * 503c6bd008Smiod * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 513c6bd008Smiod * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 523c6bd008Smiod * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 533c6bd008Smiod * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 543c6bd008Smiod * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 553c6bd008Smiod * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 563c6bd008Smiod * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 573c6bd008Smiod * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 583c6bd008Smiod * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 593c6bd008Smiod * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 603c6bd008Smiod * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 613c6bd008Smiod * OF THE POSSIBILITY OF SUCH DAMAGE. 623c6bd008Smiod * ==================================================================== 633c6bd008Smiod * 643c6bd008Smiod * This product includes cryptographic software written by Eric Young 653c6bd008Smiod * (eay@cryptsoft.com). This product includes software written by Tim 663c6bd008Smiod * Hudson (tjh@cryptsoft.com). 673c6bd008Smiod * 683c6bd008Smiod */ 693c6bd008Smiod 7023b02498Stb #include <err.h> 713c6bd008Smiod #include <stdio.h> 723c6bd008Smiod #include <stdlib.h> 733c6bd008Smiod #include <string.h> 743c6bd008Smiod 753c6bd008Smiod #include <openssl/bn.h> 763c6bd008Smiod #include <openssl/objects.h> 773c6bd008Smiod #include <openssl/sha.h> 783c6bd008Smiod #include <openssl/err.h> 793c6bd008Smiod 803c6bd008Smiod #include <openssl/ec.h> 813c6bd008Smiod #include <openssl/ecdh.h> 823c6bd008Smiod 8323b02498Stb static void 8423b02498Stb hexdump(const unsigned char *buf, size_t len) 8523b02498Stb { 8623b02498Stb size_t i; 8723b02498Stb 8823b02498Stb for (i = 1; i <= len; i++) 8923b02498Stb fprintf(stdout, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 9023b02498Stb 9123b02498Stb if (len % 8) 9223b02498Stb fprintf(stdout, "\n"); 9323b02498Stb } 9423b02498Stb 95e2a6b165Sjsing static void * 96e2a6b165Sjsing KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen) 973c6bd008Smiod { 985c040a06Stb #ifdef OPENSSL_NO_SHA 995c040a06Stb return NULL; 1005c040a06Stb #else 1013c6bd008Smiod if (*outlen < SHA_DIGEST_LENGTH) 1023c6bd008Smiod return NULL; 1033c6bd008Smiod *outlen = SHA_DIGEST_LENGTH; 1043c6bd008Smiod return SHA1(in, inlen, out); 1053c6bd008Smiod #endif 1063c6bd008Smiod } 1073c6bd008Smiod 108e2a6b165Sjsing static int 10923b02498Stb ecdh_keygen_test(int nid) 1103c6bd008Smiod { 11123b02498Stb EC_KEY *keya = NULL, *keyb = NULL; 11223b02498Stb const EC_POINT *puba, *pubb; 1133c6bd008Smiod unsigned char *abuf = NULL, *bbuf = NULL; 1145c040a06Stb int len = SHA_DIGEST_LENGTH; 11523b02498Stb int failed = 1; 1163c6bd008Smiod 11723b02498Stb if ((keya = EC_KEY_new_by_curve_name(nid)) == NULL) 11823b02498Stb goto err; 11923b02498Stb if (!EC_KEY_generate_key(keya)) 12023b02498Stb goto err; 12123b02498Stb if ((puba = EC_KEY_get0_public_key(keya)) == NULL) 1223c6bd008Smiod goto err; 1233c6bd008Smiod 12423b02498Stb if ((keyb = EC_KEY_new_by_curve_name(nid)) == NULL) 125e2a6b165Sjsing goto err; 12623b02498Stb if (!EC_KEY_generate_key(keyb)) 127e2a6b165Sjsing goto err; 12823b02498Stb if ((pubb = EC_KEY_get0_public_key(keyb)) == NULL) 129e2a6b165Sjsing goto err; 1303c6bd008Smiod 13123b02498Stb if ((abuf = calloc(1, len)) == NULL) 13223b02498Stb goto err; 13323b02498Stb if ((bbuf = calloc(1, len)) == NULL) 134e2a6b165Sjsing goto err; 1353c6bd008Smiod 13623b02498Stb if (ECDH_compute_key(abuf, len, pubb, keya, KDF1_SHA1) != len) 13723b02498Stb goto err; 13823b02498Stb if (ECDH_compute_key(bbuf, len, puba, keyb, KDF1_SHA1) != len) 139e2a6b165Sjsing goto err; 1403c6bd008Smiod 14123b02498Stb if (memcmp(abuf, bbuf, len) != 0) { 14223b02498Stb printf("key generation with %s failed\n", OBJ_nid2sn(nid)); 1433c6bd008Smiod 14423b02498Stb EC_KEY_print_fp(stdout, keya, 1); 14523b02498Stb printf(" shared secret:\n"); 14623b02498Stb hexdump(abuf, len); 1473c6bd008Smiod 14823b02498Stb EC_KEY_print_fp(stdout, keyb, 1); 14923b02498Stb printf(" shared secret:\n"); 150f8783f21Stb hexdump(bbuf, len); 1513c6bd008Smiod 1523c6bd008Smiod fprintf(stderr, "Error in ECDH routines\n"); 15323b02498Stb 15423b02498Stb goto err; 1553c6bd008Smiod } 156e7bd14d7Sjsing 15723b02498Stb failed = 0; 158f8783f21Stb 1593c6bd008Smiod err: 1603c6bd008Smiod ERR_print_errors_fp(stderr); 1613c6bd008Smiod 16223b02498Stb EC_KEY_free(keya); 16323b02498Stb EC_KEY_free(keyb); 16423b02498Stb freezero(abuf, len); 16523b02498Stb freezero(bbuf, len); 1662f13a30dSjsing 16723b02498Stb return failed; 1683c6bd008Smiod } 1693c6bd008Smiod 17023b02498Stb static const struct ecdh_kat_test { 17123b02498Stb const int nid; 17223b02498Stb const char *keya; 17323b02498Stb const char *keyb; 17423b02498Stb const char *want; 17523b02498Stb } ecdh_kat_tests[] = { 17623b02498Stb /* Keys and shared secrets from RFC 5114 */ 17723b02498Stb { 17823b02498Stb .nid = NID_secp224r1, 17923b02498Stb .keya = "b558eb6c288da707bbb4f8fbae2ab9e9cb62e3bc5c7573e2" 18023b02498Stb "2e26d37f", 18123b02498Stb .keyb = "ac3b1add3d9770e6f6a708ee9f3b8e0ab3b480e9f27f85c8" 18223b02498Stb "8b5e6d18", 18323b02498Stb .want = "52272f50f46f4edc9151569092f46df2d96ecc3b6dc1714a" 18423b02498Stb "4ea949fa", 18523b02498Stb }, 18623b02498Stb { 18723b02498Stb .nid = NID_X9_62_prime256v1, 18823b02498Stb .keya = "814264145f2f56f2e96a8e337a1284993faf432a5abce59e" 18923b02498Stb "867b7291d507a3af", 19023b02498Stb .keyb = "2ce1788ec197e096db95a200cc0ab26a19ce6bccad562b8e" 19123b02498Stb "ee1b593761cf7f41", 19223b02498Stb .want = "dd0f5396219d1ea393310412d19a08f1f5811e9dc8ec8eea" 19323b02498Stb "7f80d21c820c2788", 19423b02498Stb }, 19523b02498Stb { 19623b02498Stb .nid = NID_secp384r1, 19723b02498Stb .keya = "d27335ea71664af244dd14e9fd1260715dfd8a7965571c48" 19823b02498Stb "d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1", 19923b02498Stb .keyb = "52d1791fdb4b70f89c0f00d456c2f7023b6125262c36a7df" 20023b02498Stb "1f80231121cce3d39be52e00c194a4132c4a6c768bcd94d2", 20123b02498Stb .want = "5ea1fc4af7256d2055981b110575e0a8cae53160137d904c" 20223b02498Stb "59d926eb1b8456e427aa8a4540884c37de159a58028abc0e", 20323b02498Stb }, 20423b02498Stb { 20523b02498Stb .nid = NID_secp521r1, 20623b02498Stb .keya = "0113f82da825735e3d97276683b2b74277bad27335ea7166" 20723b02498Stb "4af2430cc4f33459b9669ee78b3ffb9b8683015d344dcbfe" 20823b02498Stb "f6fb9af4c6c470be254516cd3c1a1fb47362", 20923b02498Stb .keyb = "00cee3480d8645a17d249f2776d28bae616952d1791fdb4b" 21023b02498Stb "70f7c3378732aa1b22928448bcd1dc2496d435b01048066e" 21123b02498Stb "be4f72903c361b1a9dc1193dc2c9d0891b96", 21223b02498Stb .want = "00cdea89621cfa46b132f9e4cfe2261cde2d4368eb565663" 21323b02498Stb "4c7cc98c7a00cde54ed1866a0dd3e6126c9d2f845daff82c" 21423b02498Stb "eb1da08f5d87521bb0ebeca77911169c20cc", 21523b02498Stb }, 21623b02498Stb /* Keys and shared secrets from RFC 5903 */ 21723b02498Stb { 21823b02498Stb .nid = NID_X9_62_prime256v1, 21923b02498Stb .keya = "c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049" 22023b02498Stb "c62a9c57862d1433", 22123b02498Stb .keyb = "c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0" 22223b02498Stb "b283ab46476bee53", 22323b02498Stb .want = "d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03" 22423b02498Stb "812464d04b9442de", 22523b02498Stb }, 22623b02498Stb { 22723b02498Stb .nid = NID_secp384r1, 22823b02498Stb .keya = "099f3c7034d4a2c699884d73a375a67f7624ef7c6b3c0f16" 22923b02498Stb "0647b67414dce655e35b538041e649ee3faef896783ab194", 23023b02498Stb .keyb = "41cb0779b4bdb85d47846725fbec3c9430fab46cc8dc5060" 23123b02498Stb "855cc9bda0aa2942e0308312916b8ed2960e4bd55a7448fc", 23223b02498Stb .want = "11187331c279962d93d604243fd592cb9d0a926f422e4718" 23323b02498Stb "7521287e7156c5c4d603135569b9e9d09cf5d4a270f59746", 23423b02498Stb }, 23523b02498Stb { 23623b02498Stb .nid = NID_secp521r1, 23723b02498Stb .keya = "0037ade9319a89f4dabdb3ef411aaccca5123c61acab57b5" 23823b02498Stb "393dce47608172a095aa85a30fe1c2952c6771d937ba9777" 23923b02498Stb "f5957b2639bab072462f68c27a57382d" 24023b02498Stb "4a52", 24123b02498Stb .keyb = "0145ba99a847af43793fdd0e872e7cdfa16be30fdc780f97" 24223b02498Stb "bccc3f078380201e9c677d600b343757a3bdbf2a3163e4c2" 24323b02498Stb "f869cca7458aa4a4effc311f5cb151685eb9", 24423b02498Stb .want = "01144c7d79ae6956bc8edb8e7c787c4521cb086fa64407f9" 24523b02498Stb "7894e5e6b2d79b04d1427e73ca4baa240a34786859810c06" 24623b02498Stb "b3c715a3a8cc3151f2bee417996d19f3ddea", 24723b02498Stb }, 248be0309a4Smiod /* Keys and shared secrets from RFC 7027 */ 24923b02498Stb { 25023b02498Stb .nid = NID_brainpoolP256r1, 25123b02498Stb .keya = "81db1ee100150ff2ea338d708271be38300cb54241d79950" 25223b02498Stb "f77b063039804f1d", 25323b02498Stb .keyb = "55e40bc41e37e3e2ad25c3c6654511ffa8474a91a0032087" 25423b02498Stb "593852d3e7d76bd3", 25523b02498Stb .want = "89afc39d41d3b327814b80940b042590f96556ec91e6ae79" 25623b02498Stb "39bce31f3a18bf2b", 25723b02498Stb }, 25823b02498Stb { 25923b02498Stb .nid = NID_brainpoolP384r1, 26023b02498Stb .keya = "1e20f5e048a5886f1f157c74e91bde2b98c8b52d58e5003d" 26123b02498Stb "57053fc4b0bd65d6f15eb5d1ee1610df870795143627d042", 26223b02498Stb .keyb = "032640bc6003c59260f7250c3db58ce647f98e1260acce4a" 26323b02498Stb "cda3dd869f74e01f8ba5e0324309db6a9831497abac96670", 26423b02498Stb .want = "0bd9d3a7ea0b3d519d09d8e48d0785fb744a6b355e6304bc" 26523b02498Stb "51c229fbbce239bbadf6403715c35d4fb2a5444f575d4f42", 26623b02498Stb }, 26723b02498Stb { 26823b02498Stb .nid = NID_brainpoolP512r1, 26923b02498Stb .keya = "16302ff0dbbb5a8d733dab7141c1b45acbc8715939677f6a" 27023b02498Stb "56850a38bd87bd59b09e80279609ff333eb9d4c061231fb2" 27123b02498Stb "6f92eeb04982a5f1d1764cad57665422", 27223b02498Stb .keyb = "230e18e1bcc88a362fa54e4ea3902009292f7f8033624fd4" 27323b02498Stb "71b5d8ace49d12cfabbc19963dab8e2f1eba00bffb29e4d7" 27423b02498Stb "2d13f2224562f405cb80503666b25429", 27523b02498Stb .want = "a7927098655f1f9976fa50a9d566865dc530331846381c87" 27623b02498Stb "256baf3226244b76d36403c024d7bbf0aa0803eaff405d3d" 27723b02498Stb "24f11a9b5c0bef679fe1454b21c4cd1f", 27823b02498Stb }, 279be0309a4Smiod }; 280be0309a4Smiod 28123b02498Stb #define N_KATS (sizeof(ecdh_kat_tests) / sizeof(ecdh_kat_tests[0])) 282be0309a4Smiod 283be0309a4Smiod /* Given private value and NID, create EC_KEY structure */ 284be0309a4Smiod 285e2a6b165Sjsing static EC_KEY * 28623b02498Stb mk_eckey(int nid, const char *priv_str) 287be0309a4Smiod { 28823b02498Stb EC_KEY *key = NULL; 289be0309a4Smiod BIGNUM *priv = NULL; 290be0309a4Smiod EC_POINT *pub = NULL; 29123b02498Stb const EC_GROUP *group; 29223b02498Stb EC_KEY *ret = NULL; 2932f13a30dSjsing 29423b02498Stb if ((key = EC_KEY_new_by_curve_name(nid)) == NULL) 295be0309a4Smiod goto err; 29623b02498Stb if (!BN_hex2bn(&priv, priv_str)) 297be0309a4Smiod goto err; 29823b02498Stb if (!EC_KEY_set_private_key(key, priv)) 299be0309a4Smiod goto err; 30023b02498Stb if ((group = EC_KEY_get0_group(key)) == NULL) 301be0309a4Smiod goto err; 30223b02498Stb if ((pub = EC_POINT_new(group)) == NULL) 303be0309a4Smiod goto err; 30423b02498Stb if (!EC_POINT_mul(group, pub, priv, NULL, NULL, NULL)) 305be0309a4Smiod goto err; 30623b02498Stb if (!EC_KEY_set_public_key(key, pub)) 30723b02498Stb goto err; 30823b02498Stb 30923b02498Stb ret = key; 31023b02498Stb key = NULL; 31123b02498Stb 312be0309a4Smiod err: 31323b02498Stb EC_KEY_free(key); 31446c2b081Stb BN_free(priv); 315be0309a4Smiod EC_POINT_free(pub); 31623b02498Stb 31723b02498Stb return ret; 318be0309a4Smiod } 319be0309a4Smiod 32023b02498Stb /* 32123b02498Stb * Known answer test: compute shared secret and check it matches expected value. 322be0309a4Smiod */ 323e2a6b165Sjsing static int 32423b02498Stb ecdh_kat(const struct ecdh_kat_test *kat) 325be0309a4Smiod { 32623b02498Stb EC_KEY *keya = NULL, *keyb = NULL; 32723b02498Stb const EC_POINT *puba, *pubb; 32823b02498Stb BIGNUM *z = NULL; 32923b02498Stb unsigned char *want = NULL, *got = NULL; 33023b02498Stb int len = 0; 331f8783f21Stb int failed = 1; 33223b02498Stb 33323b02498Stb if ((keya = mk_eckey(kat->nid, kat->keya)) == NULL) 334be0309a4Smiod goto err; 33523b02498Stb if ((puba = EC_KEY_get0_public_key(keya)) == NULL) 336be0309a4Smiod goto err; 33723b02498Stb if ((keyb = mk_eckey(kat->nid, kat->keyb)) == NULL) 338062268a7Stb goto err; 33923b02498Stb if ((pubb = EC_KEY_get0_public_key(keyb)) == NULL) 340be0309a4Smiod goto err; 34123b02498Stb 34223b02498Stb if ((len = ECDH_size(keya)) != ECDH_size(keyb)) 343be0309a4Smiod goto err; 34423b02498Stb 34523b02498Stb if ((want = calloc(1, len)) == NULL) 346be0309a4Smiod goto err; 34723b02498Stb if ((got = calloc(1, len)) == NULL) 348be0309a4Smiod goto err; 34923b02498Stb 35023b02498Stb if (!BN_hex2bn(&z, kat->want)) 35123b02498Stb goto err; 35223b02498Stb if (BN_num_bytes(z) > len) 35323b02498Stb goto err; 35423b02498Stb if (BN_bn2binpad(z, want, len) != len) 35523b02498Stb goto err; 35623b02498Stb 35723b02498Stb if (ECDH_compute_key(got, len, pubb, keya, NULL) != len) 35823b02498Stb goto err; 35923b02498Stb if (memcmp(got, want, len) != 0) 36023b02498Stb goto err; 36123b02498Stb 36223b02498Stb memset(got, 0, len); 36323b02498Stb 36423b02498Stb if (ECDH_compute_key(got, len, puba, keyb, NULL) != len) 36523b02498Stb goto err; 36623b02498Stb if (memcmp(got, want, len) != 0) 36723b02498Stb goto err; 36823b02498Stb 36923b02498Stb failed = 0; 3702f13a30dSjsing 371be0309a4Smiod err: 37223b02498Stb if (failed) { 373f8783f21Stb printf("shared secret with %s failed", OBJ_nid2sn(kat->nid)); 37423b02498Stb 375be0309a4Smiod fprintf(stderr, "Error in ECDH routines\n"); 376be0309a4Smiod ERR_print_errors_fp(stderr); 377be0309a4Smiod } 3782f13a30dSjsing 37923b02498Stb EC_KEY_free(keya); 38023b02498Stb EC_KEY_free(keyb); 38123b02498Stb BN_free(z); 38223b02498Stb freezero(want, len); 38323b02498Stb freezero(got, len); 3842f13a30dSjsing 38523b02498Stb return failed; 386be0309a4Smiod } 387be0309a4Smiod 388e2a6b165Sjsing int 389f8783f21Stb main(void) 3903c6bd008Smiod { 39123b02498Stb EC_builtin_curve *curves = NULL; 39223b02498Stb size_t i, n_curves; 39323b02498Stb int failed = 0; 3943c6bd008Smiod 39523b02498Stb if ((n_curves = EC_get_builtin_curves(NULL, 0)) == 0) 39623b02498Stb errx(1, "EC_get_builtin_curves failed"); 39723b02498Stb if ((curves = calloc(n_curves, sizeof(*curves))) == NULL) 39823b02498Stb errx(1, NULL); 39923b02498Stb if (EC_get_builtin_curves(curves, n_curves) != n_curves) 40023b02498Stb errx(1, "EC_get_builtin_curves failed"); 4013c6bd008Smiod 40223b02498Stb for (i = 0; i < n_curves; i++) 40323b02498Stb failed |= ecdh_keygen_test(curves[i].nid); 4043c6bd008Smiod 40523b02498Stb for (i = 0; i < N_KATS; i++) 40623b02498Stb failed |= ecdh_kat(&ecdh_kat_tests[i]); 4073c6bd008Smiod 40823b02498Stb free(curves); 4093c6bd008Smiod ERR_print_errors_fp(stderr); 41023b02498Stb 41123b02498Stb return failed; 4123c6bd008Smiod } 413