1/* 2 * Copyright 2022-2024 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{- 10use OpenSSL::paramnames qw(produce_param_decoder); 11-} 12 13#include <stdlib.h> 14#include <string.h> 15#include <openssl/crypto.h> 16#include <openssl/err.h> 17#include <openssl/kdf.h> 18#include <openssl/proverr.h> 19#include <openssl/core_names.h> 20#include "internal/common.h" 21#include "prov/providercommon.h" 22#include "prov/implementations.h" 23#include "prov/hmac_drbg.h" 24#include "prov/provider_ctx.h" 25 26static OSSL_FUNC_kdf_newctx_fn hmac_drbg_kdf_new; 27static OSSL_FUNC_kdf_dupctx_fn hmac_drbg_kdf_dup; 28static OSSL_FUNC_kdf_freectx_fn hmac_drbg_kdf_free; 29static OSSL_FUNC_kdf_reset_fn hmac_drbg_kdf_reset; 30static OSSL_FUNC_kdf_derive_fn hmac_drbg_kdf_derive; 31static OSSL_FUNC_kdf_settable_ctx_params_fn hmac_drbg_kdf_settable_ctx_params; 32static OSSL_FUNC_kdf_set_ctx_params_fn hmac_drbg_kdf_set_ctx_params; 33static OSSL_FUNC_kdf_gettable_ctx_params_fn hmac_drbg_kdf_gettable_ctx_params; 34static OSSL_FUNC_kdf_get_ctx_params_fn hmac_drbg_kdf_get_ctx_params; 35 36typedef struct { 37 PROV_DRBG_HMAC base; 38 void *provctx; 39 unsigned char *entropy, *nonce; 40 size_t entropylen, noncelen; 41 int init; 42} KDF_HMAC_DRBG; 43 44static void *hmac_drbg_kdf_new(void *provctx) 45{ 46 KDF_HMAC_DRBG *ctx; 47 48 if (!ossl_prov_is_running()) 49 return NULL; 50 51 ctx = OPENSSL_zalloc(sizeof(*ctx)); 52 if (ctx == NULL) { 53 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 54 return NULL; 55 } 56 ctx->provctx = provctx; 57 return ctx; 58} 59 60static void hmac_drbg_kdf_reset(void *vctx) 61{ 62 KDF_HMAC_DRBG *ctx = (KDF_HMAC_DRBG *)vctx; 63 PROV_DRBG_HMAC *drbg = &ctx->base; 64 void *provctx = ctx->provctx; 65 66 EVP_MAC_CTX_free(drbg->ctx); 67 ossl_prov_digest_reset(&drbg->digest); 68 OPENSSL_clear_free(ctx->entropy, ctx->entropylen); 69 OPENSSL_clear_free(ctx->nonce, ctx->noncelen); 70 OPENSSL_cleanse(ctx, sizeof(*ctx)); 71 ctx->provctx = provctx; 72} 73 74static void hmac_drbg_kdf_free(void *vctx) 75{ 76 KDF_HMAC_DRBG *ctx = (KDF_HMAC_DRBG *)vctx; 77 78 if (ctx != NULL) { 79 hmac_drbg_kdf_reset(ctx); 80 OPENSSL_free(ctx); 81 } 82} 83 84static int ossl_drbg_hmac_dup(PROV_DRBG_HMAC *dst, const PROV_DRBG_HMAC *src) { 85 if (src->ctx != NULL) { 86 dst->ctx = EVP_MAC_CTX_dup(src->ctx); 87 if (dst->ctx == NULL) 88 return 0; 89 } 90 if (!ossl_prov_digest_copy(&dst->digest, &src->digest)) 91 return 0; 92 memcpy(dst->K, src->K, sizeof(dst->K)); 93 memcpy(dst->V, src->V, sizeof(dst->V)); 94 dst->blocklen = src->blocklen; 95 return 1; 96} 97 98static void *hmac_drbg_kdf_dup(void *vctx) 99{ 100 const KDF_HMAC_DRBG *src = (const KDF_HMAC_DRBG *)vctx; 101 KDF_HMAC_DRBG *dst; 102 103 dst = hmac_drbg_kdf_new(src->provctx); 104 if (dst != NULL) { 105 if (!ossl_drbg_hmac_dup(&dst->base, &src->base) 106 || !ossl_prov_memdup(src->entropy, src->entropylen, 107 &dst->entropy , &dst->entropylen) 108 || !ossl_prov_memdup(src->nonce, src->noncelen, 109 &dst->nonce, &dst->noncelen)) 110 goto err; 111 dst->init = src->init; 112 } 113 return dst; 114 115 err: 116 hmac_drbg_kdf_free(dst); 117 return NULL; 118} 119 120static int hmac_drbg_kdf_derive(void *vctx, unsigned char *out, size_t outlen, 121 const OSSL_PARAM params[]) 122{ 123 KDF_HMAC_DRBG *ctx = (KDF_HMAC_DRBG *)vctx; 124 PROV_DRBG_HMAC *drbg = &ctx->base; 125 126 if (!ossl_prov_is_running() 127 || !hmac_drbg_kdf_set_ctx_params(vctx, params)) 128 return 0; 129 if (!ctx->init) { 130 if (ctx->entropy == NULL 131 || ctx->entropylen == 0 132 || ctx->nonce == NULL 133 || ctx->noncelen == 0 134 || !ossl_drbg_hmac_init(drbg, ctx->entropy, ctx->entropylen, 135 ctx->nonce, ctx->noncelen, NULL, 0)) 136 return 0; 137 ctx->init = 1; 138 } 139 140 return ossl_drbg_hmac_generate(drbg, out, outlen, NULL, 0); 141} 142 143{- produce_param_decoder('hmac_drbg_kdf_get_ctx_params', 144 (['KDF_PARAM_MAC', 'mac', 'utf8_string'], 145 ['KDF_PARAM_DIGEST', 'digest', 'utf8_string'], 146 )); -} 147 148static int hmac_drbg_kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) 149{ 150 KDF_HMAC_DRBG *hmac = (KDF_HMAC_DRBG *)vctx; 151 PROV_DRBG_HMAC *drbg = &hmac->base; 152 const char *name; 153 const EVP_MD *md; 154 struct hmac_drbg_kdf_get_ctx_params_st p; 155 156 if (hmac == NULL || !hmac_drbg_kdf_get_ctx_params_decoder(params, &p)) 157 return 0; 158 159 if (p.mac != NULL) { 160 if (drbg->ctx == NULL) 161 return 0; 162 name = EVP_MAC_get0_name(EVP_MAC_CTX_get0_mac(drbg->ctx)); 163 if (!OSSL_PARAM_set_utf8_string(p.mac, name)) 164 return 0; 165 } 166 167 if (p.digest != NULL) { 168 md = ossl_prov_digest_md(&drbg->digest); 169 if (md == NULL 170 || !OSSL_PARAM_set_utf8_string(p.digest, EVP_MD_get0_name(md))) 171 return 0; 172 } 173 return 1; 174} 175 176static const OSSL_PARAM *hmac_drbg_kdf_gettable_ctx_params( 177 ossl_unused void *vctx, ossl_unused void *p_ctx) 178{ 179 return hmac_drbg_kdf_get_ctx_params_list; 180} 181 182{- produce_param_decoder('hmac_drbg_kdf_set_ctx_params', 183 (['KDF_PARAM_PROPERTIES', 'propq', 'utf8_string'], 184 ['ALG_PARAM_ENGINE', 'engine', 'utf8_string', 'hidden'], 185 ['KDF_PARAM_DIGEST', 'digest', 'utf8_string'], 186 ['KDF_PARAM_HMACDRBG_ENTROPY', 'ent', 'octet_string'], 187 ['KDF_PARAM_HMACDRBG_NONCE', 'nonce', 'octet_string'], 188 )); -} 189 190static int hmac_drbg_kdf_set_ctx_params(void *vctx, 191 const OSSL_PARAM params[]) 192{ 193 KDF_HMAC_DRBG *hmac = (KDF_HMAC_DRBG *)vctx; 194 PROV_DRBG_HMAC *drbg; 195 OSSL_LIB_CTX *libctx; 196 const EVP_MD *md; 197 struct hmac_drbg_kdf_set_ctx_params_st p; 198 void *ptr = NULL; 199 size_t size = 0; 200 int md_size; 201 202 if (hmac == NULL || !hmac_drbg_kdf_set_ctx_params_decoder(params, &p)) 203 return 0; 204 205 drbg = &hmac->base; 206 libctx = PROV_LIBCTX_OF(hmac->provctx); 207 208 if (p.ent != NULL) { 209 if (!OSSL_PARAM_get_octet_string(p.ent, &ptr, 0, &size)) 210 return 0; 211 OPENSSL_free(hmac->entropy); 212 hmac->entropy = ptr; 213 hmac->entropylen = size; 214 hmac->init = 0; 215 ptr = NULL; 216 } 217 218 if (p.nonce != NULL) { 219 if (!OSSL_PARAM_get_octet_string(p.nonce, &ptr, 0, &size)) 220 return 0; 221 OPENSSL_free(hmac->nonce); 222 hmac->nonce = ptr; 223 hmac->noncelen = size; 224 hmac->init = 0; 225 } 226 227 if (p.digest != NULL) { 228 if (!ossl_prov_digest_load(&drbg->digest, p.digest, 229 p.propq, p.engine, libctx)) 230 return 0; 231 232 /* Confirm digest is allowed. Allow all digests that are not XOF */ 233 md = ossl_prov_digest_md(&drbg->digest); 234 if (md != NULL) { 235 if (EVP_MD_xof(md)) { 236 ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); 237 return 0; 238 } 239 md_size = EVP_MD_get_size(md); 240 if (md_size <= 0) 241 return 0; 242 drbg->blocklen = (size_t)md_size; 243 } 244 if (!ossl_prov_macctx_load(&drbg->ctx, NULL, NULL, p.digest, p.propq, 245 p.engine, "HMAC", NULL, NULL, libctx)) 246 return 0; 247 } 248 return 1; 249} 250 251static const OSSL_PARAM *hmac_drbg_kdf_settable_ctx_params( 252 ossl_unused void *vctx, ossl_unused void *p_ctx) 253{ 254 return hmac_drbg_kdf_set_ctx_params_list; 255} 256 257const OSSL_DISPATCH ossl_kdf_hmac_drbg_functions[] = { 258 { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))hmac_drbg_kdf_new }, 259 { OSSL_FUNC_KDF_FREECTX, (void(*)(void))hmac_drbg_kdf_free }, 260 { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))hmac_drbg_kdf_dup }, 261 { OSSL_FUNC_KDF_RESET, (void(*)(void))hmac_drbg_kdf_reset }, 262 { OSSL_FUNC_KDF_DERIVE, (void(*)(void))hmac_drbg_kdf_derive }, 263 { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, 264 (void(*)(void))hmac_drbg_kdf_settable_ctx_params }, 265 { OSSL_FUNC_KDF_SET_CTX_PARAMS, 266 (void(*)(void))hmac_drbg_kdf_set_ctx_params }, 267 { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, 268 (void(*)(void))hmac_drbg_kdf_gettable_ctx_params }, 269 { OSSL_FUNC_KDF_GET_CTX_PARAMS, 270 (void(*)(void))hmac_drbg_kdf_get_ctx_params }, 271 OSSL_DISPATCH_END 272}; 273