From 5a285addbf39f91d567f95f04b2b41764127950d Mon Sep 17 00:00:00 2001 From: David Makepeace Date: Fri, 22 Jun 2018 07:16:18 +1000 Subject: Added new EVP/KDF API. Changed PKEY/KDF API to call the new API. Added wrappers for PKCS5_PBKDF2_HMAC() and EVP_PBE_scrypt() to call the new EVP KDF APIs. Documentation updated. Reviewed-by: Paul Dale Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/6674) --- crypto/evp/pkey_kdf.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 crypto/evp/pkey_kdf.c (limited to 'crypto/evp/pkey_kdf.c') diff --git a/crypto/evp/pkey_kdf.c b/crypto/evp/pkey_kdf.c new file mode 100644 index 0000000000..ddb682c1ed --- /dev/null +++ b/crypto/evp/pkey_kdf.c @@ -0,0 +1,255 @@ +/* + * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include "internal/evp_int.h" + +static int pkey_kdf_init(EVP_PKEY_CTX *ctx) +{ + EVP_KDF_CTX *kctx; + + kctx = EVP_KDF_CTX_new_id(ctx->pmeth->pkey_id); + if (kctx == NULL) + return 0; + + ctx->data = kctx; + return 1; +} + +static void pkey_kdf_cleanup(EVP_PKEY_CTX *ctx) +{ + EVP_KDF_CTX *kctx = ctx->data; + + EVP_KDF_CTX_free(kctx); +} + +static int pkey_kdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) +{ + EVP_KDF_CTX *kctx = ctx->data; + uint64_t u64_value; + int cmd; + int ret; + + switch (type) { + case EVP_PKEY_CTRL_PASS: + cmd = EVP_KDF_CTRL_SET_PASS; + break; + case EVP_PKEY_CTRL_HKDF_SALT: + case EVP_PKEY_CTRL_SCRYPT_SALT: + cmd = EVP_KDF_CTRL_SET_SALT; + break; + case EVP_PKEY_CTRL_TLS_MD: + case EVP_PKEY_CTRL_HKDF_MD: + cmd = EVP_KDF_CTRL_SET_MD; + break; + case EVP_PKEY_CTRL_TLS_SECRET: + cmd = EVP_KDF_CTRL_SET_TLS_SECRET; + ret = EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_RESET_TLS_SEED); + if (ret < 1) + return ret; + break; + case EVP_PKEY_CTRL_TLS_SEED: + cmd = EVP_KDF_CTRL_ADD_TLS_SEED; + break; + case EVP_PKEY_CTRL_HKDF_KEY: + cmd = EVP_KDF_CTRL_SET_KEY; + break; + case EVP_PKEY_CTRL_HKDF_INFO: + cmd = EVP_KDF_CTRL_ADD_HKDF_INFO; + break; + case EVP_PKEY_CTRL_HKDF_MODE: + cmd = EVP_KDF_CTRL_SET_HKDF_MODE; + break; + case EVP_PKEY_CTRL_SCRYPT_N: + cmd = EVP_KDF_CTRL_SET_SCRYPT_N; + break; + case EVP_PKEY_CTRL_SCRYPT_R: + cmd = EVP_KDF_CTRL_SET_SCRYPT_R; + break; + case EVP_PKEY_CTRL_SCRYPT_P: + cmd = EVP_KDF_CTRL_SET_SCRYPT_P; + break; + case EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES: + cmd = EVP_KDF_CTRL_SET_MAXMEM_BYTES; + break; + default: + return -2; + } + + switch (cmd) { + case EVP_KDF_CTRL_SET_PASS: + case EVP_KDF_CTRL_SET_SALT: + case EVP_KDF_CTRL_SET_KEY: + case EVP_KDF_CTRL_SET_TLS_SECRET: + case EVP_KDF_CTRL_ADD_TLS_SEED: + case EVP_KDF_CTRL_ADD_HKDF_INFO: + return EVP_KDF_ctrl(kctx, cmd, (const unsigned char *)p2, (size_t)p1); + + case EVP_KDF_CTRL_SET_MD: + return EVP_KDF_ctrl(kctx, cmd, (const EVP_MD *)p2); + + case EVP_KDF_CTRL_SET_HKDF_MODE: + return EVP_KDF_ctrl(kctx, cmd, (int)p1); + + case EVP_KDF_CTRL_SET_SCRYPT_R: + case EVP_KDF_CTRL_SET_SCRYPT_P: + u64_value = *(uint64_t *)p2; + if (u64_value > UINT32_MAX) { + EVPerr(EVP_F_PKEY_KDF_CTRL, EVP_R_PARAMETER_TOO_LARGE); + return 0; + } + + return EVP_KDF_ctrl(kctx, cmd, (uint32_t)u64_value); + + case EVP_KDF_CTRL_SET_SCRYPT_N: + case EVP_KDF_CTRL_SET_MAXMEM_BYTES: + return EVP_KDF_ctrl(kctx, cmd, *(uint64_t *)p2); + + default: + return 0; + } +} + +static int pkey_kdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, + const char *value) +{ + EVP_KDF_CTX *kctx = ctx->data; + + if (strcmp(type, "md") == 0) + return EVP_KDF_ctrl_str(kctx, "digest", value); + return EVP_KDF_ctrl_str(kctx, type, value); +} + +static int pkey_kdf_derive_init(EVP_PKEY_CTX *ctx) +{ + EVP_KDF_CTX *kctx = ctx->data; + + EVP_KDF_reset(kctx); + return 1; +} + +/* + * For fixed-output algorithms the keylen parameter is an "out" parameter + * otherwise it is an "in" parameter. + */ +static int pkey_kdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, + size_t *keylen) +{ + EVP_KDF_CTX *kctx = ctx->data; + size_t outlen = EVP_KDF_size(kctx); + + if (outlen == 0 || outlen == SIZE_MAX) { + /* Variable-output algorithm */ + if (key == NULL) + return 0; + } else { + /* Fixed-output algorithm */ + *keylen = outlen; + if (key == NULL) + return 1; + } + return EVP_KDF_derive(kctx, key, *keylen); +} + +#ifndef OPENSSL_NO_SCRYPT +const EVP_PKEY_METHOD scrypt_pkey_meth = { + EVP_PKEY_SCRYPT, + 0, + pkey_kdf_init, + 0, + pkey_kdf_cleanup, + + 0, 0, + 0, 0, + + 0, + 0, + + 0, + 0, + + 0, 0, + + 0, 0, 0, 0, + + 0, 0, + + 0, 0, + + pkey_kdf_derive_init, + pkey_kdf_derive, + pkey_kdf_ctrl, + pkey_kdf_ctrl_str +}; +#endif + +const EVP_PKEY_METHOD tls1_prf_pkey_meth = { + EVP_PKEY_TLS1_PRF, + 0, + pkey_kdf_init, + 0, + pkey_kdf_cleanup, + + 0, 0, + 0, 0, + + 0, + 0, + + 0, + 0, + + 0, 0, + + 0, 0, 0, 0, + + 0, 0, + + 0, 0, + + pkey_kdf_derive_init, + pkey_kdf_derive, + pkey_kdf_ctrl, + pkey_kdf_ctrl_str +}; + +const EVP_PKEY_METHOD hkdf_pkey_meth = { + EVP_PKEY_HKDF, + 0, + pkey_kdf_init, + 0, + pkey_kdf_cleanup, + + 0, 0, + 0, 0, + + 0, + 0, + + 0, + 0, + + 0, 0, + + 0, 0, 0, 0, + + 0, 0, + + 0, 0, + + pkey_kdf_derive_init, + pkey_kdf_derive, + pkey_kdf_ctrl, + pkey_kdf_ctrl_str +}; + -- cgit v1.2.1