1/* $OpenBSD: hkdf_evp.c,v 1.20 2023/06/26 08:57:17 tb Exp $ */ 2/* ==================================================================== 3 * Copyright (c) 2016-2018 The OpenSSL Project. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. All advertising materials mentioning features or use of this 18 * software must display the following acknowledgment: 19 * "This product includes software developed by the OpenSSL Project 20 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 21 * 22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23 * endorse or promote products derived from this software without 24 * prior written permission. For written permission, please contact 25 * openssl-core@openssl.org. 26 * 27 * 5. Products derived from this software may not be called "OpenSSL" 28 * nor may "OpenSSL" appear in their names without prior written 29 * permission of the OpenSSL Project. 30 * 31 * 6. Redistributions of any form whatsoever must retain the following 32 * acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 * OF THE POSSIBILITY OF SUCH DAMAGE. 48 */ 49 50#include <stdlib.h> 51#include <string.h> 52 53#include <openssl/err.h> 54#include <openssl/evp.h> 55#include <openssl/hmac.h> 56#include <openssl/hkdf.h> 57#include <openssl/kdf.h> 58 59#include "evp_local.h" 60 61#define HKDF_MAXBUF 1024 62 63typedef struct { 64 int mode; 65 const EVP_MD *md; 66 unsigned char *salt; 67 size_t salt_len; 68 unsigned char *key; 69 size_t key_len; 70 unsigned char info[HKDF_MAXBUF]; 71 size_t info_len; 72} HKDF_PKEY_CTX; 73 74static int 75pkey_hkdf_init(EVP_PKEY_CTX *ctx) 76{ 77 HKDF_PKEY_CTX *kctx; 78 79 if ((kctx = calloc(1, sizeof(*kctx))) == NULL) { 80 KDFerror(ERR_R_MALLOC_FAILURE); 81 return 0; 82 } 83 84 ctx->data = kctx; 85 86 return 1; 87} 88 89static void 90pkey_hkdf_cleanup(EVP_PKEY_CTX *ctx) 91{ 92 HKDF_PKEY_CTX *kctx = ctx->data; 93 94 freezero(kctx->salt, kctx->salt_len); 95 freezero(kctx->key, kctx->key_len); 96 freezero(kctx, sizeof(*kctx)); 97} 98 99static int 100pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) 101{ 102 HKDF_PKEY_CTX *kctx = ctx->data; 103 104 switch (type) { 105 case EVP_PKEY_CTRL_HKDF_MD: 106 if (p2 == NULL) 107 return 0; 108 109 kctx->md = p2; 110 return 1; 111 112 case EVP_PKEY_CTRL_HKDF_MODE: 113 kctx->mode = p1; 114 return 1; 115 116 case EVP_PKEY_CTRL_HKDF_SALT: 117 if (p1 == 0 || p2 == NULL) 118 return 1; 119 120 if (p1 < 0) 121 return 0; 122 123 freezero(kctx->salt, kctx->salt_len); 124 if ((kctx->salt = malloc(p1)) == NULL) 125 return 0; 126 memcpy(kctx->salt, p2, p1); 127 128 kctx->salt_len = p1; 129 return 1; 130 131 case EVP_PKEY_CTRL_HKDF_KEY: 132 if (p1 < 0) 133 return 0; 134 135 freezero(kctx->key, kctx->key_len); 136 kctx->key = NULL; 137 kctx->key_len = 0; 138 139 /* Match OpenSSL's behavior. */ 140 if (p1 == 0 || p2 == NULL) 141 return 0; 142 143 if ((kctx->key = malloc(p1)) == NULL) 144 return 0; 145 memcpy(kctx->key, p2, p1); 146 147 kctx->key_len = p1; 148 return 1; 149 150 case EVP_PKEY_CTRL_HKDF_INFO: 151 if (p1 == 0 || p2 == NULL) 152 return 1; 153 154 if (p1 < 0 || p1 > (int)(HKDF_MAXBUF - kctx->info_len)) 155 return 0; 156 157 memcpy(kctx->info + kctx->info_len, p2, p1); 158 kctx->info_len += p1; 159 return 1; 160 161 default: 162 return -2; 163 } 164} 165 166static int 167pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, 168 const char *value) 169{ 170 if (strcmp(type, "mode") == 0) { 171 int mode; 172 173 if (strcmp(value, "EXTRACT_AND_EXPAND") == 0) 174 mode = EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND; 175 else if (strcmp(value, "EXTRACT_ONLY") == 0) 176 mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY; 177 else if (strcmp(value, "EXPAND_ONLY") == 0) 178 mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY; 179 else 180 return 0; 181 182 return EVP_PKEY_CTX_hkdf_mode(ctx, mode); 183 } 184 185 if (strcmp(type, "md") == 0) 186 return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_DERIVE, 187 EVP_PKEY_CTRL_HKDF_MD, value); 188 189 if (strcmp(type, "salt") == 0) 190 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, 191 value); 192 193 if (strcmp(type, "hexsalt") == 0) 194 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, 195 value); 196 197 if (strcmp(type, "key") == 0) 198 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value); 199 200 if (strcmp(type, "hexkey") == 0) 201 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value); 202 203 if (strcmp(type, "info") == 0) 204 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, 205 value); 206 207 if (strcmp(type, "hexinfo") == 0) 208 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, 209 value); 210 211 KDFerror(KDF_R_UNKNOWN_PARAMETER_TYPE); 212 return -2; 213} 214 215static int 216pkey_hkdf_derive_init(EVP_PKEY_CTX *ctx) 217{ 218 HKDF_PKEY_CTX *kctx = ctx->data; 219 220 freezero(kctx->key, kctx->key_len); 221 freezero(kctx->salt, kctx->salt_len); 222 explicit_bzero(kctx, sizeof(*kctx)); 223 224 return 1; 225} 226 227static int 228pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, 229 size_t *keylen) 230{ 231 HKDF_PKEY_CTX *kctx = ctx->data; 232 233 if (kctx->md == NULL) { 234 KDFerror(KDF_R_MISSING_MESSAGE_DIGEST); 235 return 0; 236 } 237 if (kctx->key == NULL) { 238 KDFerror(KDF_R_MISSING_KEY); 239 return 0; 240 } 241 242 switch (kctx->mode) { 243 case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND: 244 return HKDF(key, *keylen, kctx->md, kctx->key, kctx->key_len, 245 kctx->salt, kctx->salt_len, kctx->info, kctx->info_len); 246 247 case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY: 248 if (key == NULL) { 249 *keylen = EVP_MD_size(kctx->md); 250 return 1; 251 } 252 return HKDF_extract(key, keylen, kctx->md, kctx->key, 253 kctx->key_len, kctx->salt, kctx->salt_len); 254 255 case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY: 256 return HKDF_expand(key, *keylen, kctx->md, kctx->key, 257 kctx->key_len, kctx->info, kctx->info_len); 258 259 default: 260 return 0; 261 } 262} 263 264const EVP_PKEY_METHOD hkdf_pkey_meth = { 265 .pkey_id = EVP_PKEY_HKDF, 266 .flags = 0, 267 268 .init = pkey_hkdf_init, 269 .copy = NULL, 270 .cleanup = pkey_hkdf_cleanup, 271 272 .derive_init = pkey_hkdf_derive_init, 273 .derive = pkey_hkdf_derive, 274 .ctrl = pkey_hkdf_ctrl, 275 .ctrl_str = pkey_hkdf_ctrl_str, 276}; 277