1 /* $OpenBSD: ech_key.c,v 1.13 2022/06/30 11:14:47 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 <limits.h> 71 #include <string.h> 72 73 #include <openssl/opensslconf.h> 74 75 #include <openssl/bn.h> 76 #include <openssl/err.h> 77 #include <openssl/objects.h> 78 #include <openssl/sha.h> 79 80 #include "bn_lcl.h" 81 #include "ech_locl.h" 82 #include "ec_lcl.h" 83 84 static int ecdh_compute_key(void *out, size_t len, const EC_POINT *pub_key, 85 EC_KEY *ecdh, 86 void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)); 87 88 /* 89 * This implementation is based on the following primitives in the IEEE 1363 90 * standard: 91 * - ECKAS-DH1 92 * - ECSVDP-DH 93 * Finally an optional KDF is applied. 94 */ 95 static int 96 ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, 97 EC_KEY *ecdh, 98 void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)) 99 { 100 BN_CTX *ctx; 101 EC_POINT *tmp = NULL; 102 BIGNUM *x = NULL, *y = NULL; 103 const BIGNUM *priv_key; 104 const EC_GROUP* group; 105 int ret = -1; 106 size_t buflen, len; 107 unsigned char *buf = NULL; 108 109 if (outlen > INT_MAX) { 110 /* Sort of, anyway. */ 111 ECDHerror(ERR_R_MALLOC_FAILURE); 112 return -1; 113 } 114 115 if ((ctx = BN_CTX_new()) == NULL) 116 goto err; 117 BN_CTX_start(ctx); 118 if ((x = BN_CTX_get(ctx)) == NULL) 119 goto err; 120 if ((y = BN_CTX_get(ctx)) == NULL) 121 goto err; 122 123 priv_key = EC_KEY_get0_private_key(ecdh); 124 if (priv_key == NULL) { 125 ECDHerror(ECDH_R_NO_PRIVATE_VALUE); 126 goto err; 127 } 128 129 group = EC_KEY_get0_group(ecdh); 130 131 if (!EC_POINT_is_on_curve(group, pub_key, ctx)) 132 goto err; 133 134 if ((tmp = EC_POINT_new(group)) == NULL) { 135 ECDHerror(ERR_R_MALLOC_FAILURE); 136 goto err; 137 } 138 139 if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv_key, ctx)) { 140 ECDHerror(ECDH_R_POINT_ARITHMETIC_FAILURE); 141 goto err; 142 } 143 144 if (!EC_POINT_get_affine_coordinates(group, tmp, x, y, ctx)) { 145 ECDHerror(ECDH_R_POINT_ARITHMETIC_FAILURE); 146 goto err; 147 } 148 149 buflen = ECDH_size(ecdh); 150 len = BN_num_bytes(x); 151 if (len > buflen) { 152 ECDHerror(ERR_R_INTERNAL_ERROR); 153 goto err; 154 } 155 if (KDF == NULL && outlen < buflen) { 156 /* The resulting key would be truncated. */ 157 ECDHerror(ECDH_R_KEY_TRUNCATION); 158 goto err; 159 } 160 if ((buf = malloc(buflen)) == NULL) { 161 ECDHerror(ERR_R_MALLOC_FAILURE); 162 goto err; 163 } 164 165 memset(buf, 0, buflen - len); 166 if (len != (size_t)BN_bn2bin(x, buf + buflen - len)) { 167 ECDHerror(ERR_R_BN_LIB); 168 goto err; 169 } 170 171 if (KDF != NULL) { 172 if (KDF(buf, buflen, out, &outlen) == NULL) { 173 ECDHerror(ECDH_R_KDF_FAILED); 174 goto err; 175 } 176 ret = outlen; 177 } else { 178 /* No KDF, just copy out the key and zero the rest. */ 179 if (outlen > buflen) { 180 memset((void *)((uintptr_t)out + buflen), 0, outlen - buflen); 181 outlen = buflen; 182 } 183 memcpy(out, buf, outlen); 184 ret = outlen; 185 } 186 187 err: 188 EC_POINT_free(tmp); 189 if (ctx) 190 BN_CTX_end(ctx); 191 BN_CTX_free(ctx); 192 free(buf); 193 return (ret); 194 } 195 196 static ECDH_METHOD openssl_ecdh_meth = { 197 .name = "OpenSSL ECDH method", 198 .compute_key = ecdh_compute_key 199 }; 200 201 const ECDH_METHOD * 202 ECDH_OpenSSL(void) 203 { 204 return &openssl_ecdh_meth; 205 } 206 207 /* replace w/ ecdh_compute_key() when ECDH_METHOD gets removed */ 208 int 209 ossl_ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, 210 EC_KEY *eckey, 211 void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)) 212 { 213 ECDH_DATA *ecdh; 214 215 if ((ecdh = ecdh_check(eckey)) == NULL) 216 return 0; 217 return ecdh->meth->compute_key(out, outlen, pub_key, eckey, KDF); 218 } 219 220 int 221 ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, 222 EC_KEY *eckey, 223 void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)) 224 { 225 if (eckey->meth->compute_key != NULL) 226 return eckey->meth->compute_key(out, outlen, pub_key, eckey, KDF); 227 ECerror(EC_R_NOT_IMPLEMENTED); 228 return 0; 229 } 230