summaryrefslogtreecommitdiff
path: root/crypto/evp/pkey_kdf.c
diff options
context:
space:
mode:
authorDavid Makepeace <david.p.makepeace@oracle.com>2018-06-22 07:16:18 +1000
committerRichard Levitte <levitte@openssl.org>2019-02-13 12:11:49 +0100
commit5a285addbf39f91d567f95f04b2b41764127950d (patch)
tree4cdf512d4217da5b6b959552a20a33b6a23a9aaa /crypto/evp/pkey_kdf.c
parente0ae0585bee898184cbbe8144d2fa8ce25e8ca72 (diff)
downloadopenssl-new-5a285addbf39f91d567f95f04b2b41764127950d.tar.gz
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 <paul.dale@oracle.com> Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/6674)
Diffstat (limited to 'crypto/evp/pkey_kdf.c')
-rw-r--r--crypto/evp/pkey_kdf.c255
1 files changed, 255 insertions, 0 deletions
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 <string.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/kdf.h>
+#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
+};
+