1/* 2 * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include "internal/deprecated.h" 11 12#include <openssl/core_names.h> 13#include <openssl/err.h> 14#include <openssl/ec.h> 15#include "crypto/evp.h" 16#include "crypto/ec.h" 17 18/* 19 * This file is meant to contain functions to provide EVP_PKEY support for EC 20 * keys. 21 */ 22 23static ossl_inline 24int evp_pkey_ctx_getset_ecdh_param_checks(const EVP_PKEY_CTX *ctx) 25{ 26 if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { 27 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 28 /* Uses the same return values as EVP_PKEY_CTX_ctrl */ 29 return -2; 30 } 31 32 /* If key type not EC return error */ 33 if (evp_pkey_ctx_is_legacy(ctx) 34 && ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_EC) 35 return -1; 36 37 return 1; 38} 39 40int EVP_PKEY_CTX_set_ecdh_cofactor_mode(EVP_PKEY_CTX *ctx, int cofactor_mode) 41{ 42 int ret; 43 OSSL_PARAM params[2], *p = params; 44 45 ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx); 46 if (ret != 1) 47 return ret; 48 49 /* 50 * Valid input values are: 51 * * 0 for disable 52 * * 1 for enable 53 * * -1 for reset to default for associated priv key 54 */ 55 if (cofactor_mode < -1 || cofactor_mode > 1) { 56 /* Uses the same return value of pkey_ec_ctrl() */ 57 return -2; 58 } 59 60 *p++ = OSSL_PARAM_construct_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, 61 &cofactor_mode); 62 *p++ = OSSL_PARAM_construct_end(); 63 64 ret = evp_pkey_ctx_set_params_strict(ctx, params); 65 if (ret == -2) 66 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 67 return ret; 68} 69 70int EVP_PKEY_CTX_get_ecdh_cofactor_mode(EVP_PKEY_CTX *ctx) 71{ 72 int ret, mode; 73 OSSL_PARAM params[2], *p = params; 74 75 ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx); 76 if (ret != 1) 77 return ret; 78 79 *p++ = OSSL_PARAM_construct_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, 80 &mode); 81 *p++ = OSSL_PARAM_construct_end(); 82 83 ret = evp_pkey_ctx_get_params_strict(ctx, params); 84 85 switch (ret) { 86 case -2: 87 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 88 break; 89 case 1: 90 ret = mode; 91 if (mode < 0 || mode > 1) { 92 /* 93 * The provider should return either 0 or 1, any other value is a 94 * provider error. 95 */ 96 ret = -1; 97 } 98 break; 99 default: 100 ret = -1; 101 break; 102 } 103 104 return ret; 105} 106 107/* 108 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper, 109 * simply because that's easier. 110 */ 111int EVP_PKEY_CTX_set_ecdh_kdf_type(EVP_PKEY_CTX *ctx, int kdf) 112{ 113 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE, 114 EVP_PKEY_CTRL_EC_KDF_TYPE, kdf, NULL); 115} 116 117/* 118 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper, 119 * simply because that's easier. 120 */ 121int EVP_PKEY_CTX_get_ecdh_kdf_type(EVP_PKEY_CTX *ctx) 122{ 123 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE, 124 EVP_PKEY_CTRL_EC_KDF_TYPE, -2, NULL); 125} 126 127/* 128 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper, 129 * simply because that's easier. 130 */ 131int EVP_PKEY_CTX_set_ecdh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) 132{ 133 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE, 134 EVP_PKEY_CTRL_EC_KDF_MD, 0, (void *)(md)); 135} 136 137/* 138 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper, 139 * simply because that's easier. 140 */ 141int EVP_PKEY_CTX_get_ecdh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **pmd) 142{ 143 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE, 144 EVP_PKEY_CTRL_GET_EC_KDF_MD, 0, (void *)(pmd)); 145} 146 147int EVP_PKEY_CTX_set_ecdh_kdf_outlen(EVP_PKEY_CTX *ctx, int outlen) 148{ 149 int ret; 150 size_t len = outlen; 151 OSSL_PARAM params[2], *p = params; 152 153 ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx); 154 if (ret != 1) 155 return ret; 156 157 if (outlen <= 0) { 158 /* 159 * This would ideally be -1 or 0, but we have to retain compatibility 160 * with legacy behaviour of EVP_PKEY_CTX_ctrl() which returned -2 if 161 * in <= 0 162 */ 163 return -2; 164 } 165 166 *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, 167 &len); 168 *p++ = OSSL_PARAM_construct_end(); 169 170 ret = evp_pkey_ctx_set_params_strict(ctx, params); 171 if (ret == -2) 172 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 173 return ret; 174} 175 176int EVP_PKEY_CTX_get_ecdh_kdf_outlen(EVP_PKEY_CTX *ctx, int *plen) 177{ 178 size_t len = UINT_MAX; 179 int ret; 180 OSSL_PARAM params[2], *p = params; 181 182 ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx); 183 if (ret != 1) 184 return ret; 185 186 *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, 187 &len); 188 *p++ = OSSL_PARAM_construct_end(); 189 190 ret = evp_pkey_ctx_get_params_strict(ctx, params); 191 192 switch (ret) { 193 case -2: 194 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 195 break; 196 case 1: 197 if (len <= INT_MAX) 198 *plen = (int)len; 199 else 200 ret = -1; 201 break; 202 default: 203 ret = -1; 204 break; 205 } 206 207 return ret; 208} 209 210int EVP_PKEY_CTX_set0_ecdh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len) 211{ 212 int ret; 213 OSSL_PARAM params[2], *p = params; 214 215 ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx); 216 if (ret != 1) 217 return ret; 218 219 *p++ = OSSL_PARAM_construct_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, 220 /* 221 * Cast away the const. This is read 222 * only so should be safe 223 */ 224 (void *)ukm, 225 (size_t)len); 226 *p++ = OSSL_PARAM_construct_end(); 227 228 ret = evp_pkey_ctx_set_params_strict(ctx, params); 229 230 switch (ret) { 231 case -2: 232 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 233 break; 234 case 1: 235 OPENSSL_free(ukm); 236 break; 237 } 238 239 return ret; 240} 241 242#ifndef OPENSSL_NO_DEPRECATED_3_0 243int EVP_PKEY_CTX_get0_ecdh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **pukm) 244{ 245 size_t ukmlen; 246 int ret; 247 OSSL_PARAM params[2], *p = params; 248 249 ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx); 250 if (ret != 1) 251 return ret; 252 253 *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM, 254 (void **)pukm, 0); 255 *p++ = OSSL_PARAM_construct_end(); 256 257 ret = evp_pkey_ctx_get_params_strict(ctx, params); 258 259 switch (ret) { 260 case -2: 261 ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); 262 break; 263 case 1: 264 ret = -1; 265 ukmlen = params[0].return_size; 266 if (ukmlen <= INT_MAX) 267 ret = (int)ukmlen; 268 break; 269 default: 270 ret = -1; 271 break; 272 } 273 274 return ret; 275} 276#endif 277 278#ifndef FIPS_MODULE 279/* 280 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper, 281 * simply because that's easier. 282 * ASN1_OBJECT (which would be converted to text internally)? 283 */ 284int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid) 285{ 286 int keytype = nid == EVP_PKEY_SM2 ? EVP_PKEY_SM2 : EVP_PKEY_EC; 287 288 return EVP_PKEY_CTX_ctrl(ctx, keytype, EVP_PKEY_OP_TYPE_GEN, 289 EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, 290 nid, NULL); 291} 292 293/* 294 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper, 295 * simply because that's easier. 296 */ 297int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int param_enc) 298{ 299 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_TYPE_GEN, 300 EVP_PKEY_CTRL_EC_PARAM_ENC, param_enc, NULL); 301} 302#endif 303