1 /* $OpenBSD: ecdh.c,v 1.10 2023/07/28 09:31:21 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 <stdlib.h> 72 #include <string.h> 73 74 #include <openssl/bn.h> 75 #include <openssl/ec.h> 76 #include <openssl/err.h> 77 #include <openssl/evp.h> 78 79 #include "ec_local.h" 80 81 /* 82 * Key derivation function from X9.63/SECG. 83 */ 84 85 /* Way more than we will ever need */ 86 #define ECDH_KDF_MAX (1 << 30) 87 88 int 89 ecdh_KDF_X9_63(unsigned char *out, size_t outlen, const unsigned char *Z, 90 size_t Zlen, const unsigned char *sinfo, size_t sinfolen, const EVP_MD *md) 91 { 92 EVP_MD_CTX *mctx = NULL; 93 unsigned int i; 94 size_t mdlen; 95 unsigned char ctr[4]; 96 int rv = 0; 97 98 if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX || 99 Zlen > ECDH_KDF_MAX) 100 return 0; 101 mctx = EVP_MD_CTX_new(); 102 if (mctx == NULL) 103 return 0; 104 mdlen = EVP_MD_size(md); 105 for (i = 1;; i++) { 106 unsigned char mtmp[EVP_MAX_MD_SIZE]; 107 if (!EVP_DigestInit_ex(mctx, md, NULL)) 108 goto err; 109 ctr[3] = i & 0xFF; 110 ctr[2] = (i >> 8) & 0xFF; 111 ctr[1] = (i >> 16) & 0xFF; 112 ctr[0] = (i >> 24) & 0xFF; 113 if (!EVP_DigestUpdate(mctx, Z, Zlen)) 114 goto err; 115 if (!EVP_DigestUpdate(mctx, ctr, sizeof(ctr))) 116 goto err; 117 if (!EVP_DigestUpdate(mctx, sinfo, sinfolen)) 118 goto err; 119 if (outlen >= mdlen) { 120 if (!EVP_DigestFinal(mctx, out, NULL)) 121 goto err; 122 outlen -= mdlen; 123 if (outlen == 0) 124 break; 125 out += mdlen; 126 } else { 127 if (!EVP_DigestFinal(mctx, mtmp, NULL)) 128 goto err; 129 memcpy(out, mtmp, outlen); 130 explicit_bzero(mtmp, mdlen); 131 break; 132 } 133 } 134 rv = 1; 135 136 err: 137 EVP_MD_CTX_free(mctx); 138 139 return rv; 140 } 141 142 /* 143 * Based on the ECKAS-DH1 and ECSVDP-DH primitives in the IEEE 1363 standard. 144 */ 145 int 146 ecdh_compute_key(unsigned char **out, size_t *out_len, const EC_POINT *pub_key, 147 const EC_KEY *ecdh) 148 { 149 BN_CTX *ctx; 150 BIGNUM *x; 151 const BIGNUM *priv_key; 152 const EC_GROUP *group; 153 EC_POINT *point = NULL; 154 unsigned char *buf = NULL; 155 int buf_len = 0; 156 int ret = 0; 157 158 *out = NULL; 159 *out_len = 0; 160 161 if ((ctx = BN_CTX_new()) == NULL) 162 goto err; 163 164 BN_CTX_start(ctx); 165 166 if ((x = BN_CTX_get(ctx)) == NULL) 167 goto err; 168 169 if ((group = EC_KEY_get0_group(ecdh)) == NULL) 170 goto err; 171 172 if (EC_POINT_is_on_curve(group, pub_key, ctx) <= 0) 173 goto err; 174 175 if ((point = EC_POINT_new(group)) == NULL) { 176 ECerror(ERR_R_MALLOC_FAILURE); 177 goto err; 178 } 179 180 if ((priv_key = EC_KEY_get0_private_key(ecdh)) == NULL) { 181 ECerror(EC_R_MISSING_PRIVATE_KEY); 182 goto err; 183 } 184 185 if (!EC_POINT_mul(group, point, NULL, pub_key, priv_key, ctx)) { 186 ECerror(EC_R_POINT_ARITHMETIC_FAILURE); 187 goto err; 188 } 189 190 if (!EC_POINT_get_affine_coordinates(group, point, x, NULL, ctx)) { 191 ECerror(EC_R_POINT_ARITHMETIC_FAILURE); 192 goto err; 193 } 194 195 if ((buf_len = ECDH_size(ecdh)) < BN_num_bytes(x)) { 196 ECerror(ERR_R_INTERNAL_ERROR); 197 goto err; 198 } 199 if ((buf = calloc(1, buf_len)) == NULL) { 200 ECerror(ERR_R_MALLOC_FAILURE); 201 goto err; 202 } 203 if (BN_bn2binpad(x, buf, buf_len) != buf_len) { 204 ECerror(ERR_R_BN_LIB); 205 goto err; 206 } 207 208 *out = buf; 209 *out_len = buf_len; 210 buf = NULL; 211 buf_len = 0; 212 213 ret = 1; 214 215 err: 216 EC_POINT_free(point); 217 BN_CTX_end(ctx); 218 BN_CTX_free(ctx); 219 freezero(buf, buf_len); 220 221 return ret; 222 } 223 224 int 225 ECDH_compute_key(void *out, size_t out_len, const EC_POINT *pub_key, 226 EC_KEY *eckey, 227 void *(*KDF)(const void *in, size_t inlen, void *out, size_t *out_len)) 228 { 229 unsigned char *secret = NULL; 230 size_t secret_len = 0; 231 int ret = 0; 232 233 if (eckey->meth->compute_key == NULL) { 234 ECerror(EC_R_NOT_IMPLEMENTED); 235 goto err; 236 } 237 238 if (out_len > INT_MAX) { 239 ECerror(EC_R_INVALID_OUTPUT_LENGTH); 240 goto err; 241 } 242 243 if (!eckey->meth->compute_key(&secret, &secret_len, pub_key, eckey)) 244 goto err; 245 246 memset(out, 0, out_len); 247 if (KDF != NULL) { 248 if (KDF(secret, secret_len, out, &out_len) == NULL) { 249 ECerror(EC_R_KDF_FAILED); 250 goto err; 251 } 252 } else { 253 if (out_len < secret_len) { 254 /* The resulting key would be truncated. */ 255 ECerror(EC_R_KEY_TRUNCATION); 256 goto err; 257 } 258 out_len = secret_len; 259 memcpy(out, secret, out_len); 260 } 261 262 if (out_len > INT_MAX) { 263 ECerror(EC_R_INVALID_OUTPUT_LENGTH); 264 goto err; 265 } 266 267 ret = out_len; 268 269 err: 270 freezero(secret, secret_len); 271 272 return ret; 273 } 274 LCRYPTO_ALIAS(ECDH_compute_key); 275 276 int 277 ECDH_size(const EC_KEY *d) 278 { 279 return (EC_GROUP_get_degree(EC_KEY_get0_group(d)) + 7) / 8; 280 } 281 LCRYPTO_ALIAS(ECDH_size); 282