Raise an error on syscall failure in tls_retry_write_records
[openssl.git] / providers / implementations / kdfs / sskdf.c
index 1e538a9c0afc1b80a96ad54c1c7762303f8f95a8..db750a4f23366dc2ef185e93e51130c55b42c0fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright (c) 2019, Oracle and/or its affiliates.  All rights reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
 #include <openssl/kdf.h>
 #include <openssl/core_names.h>
 #include <openssl/params.h>
+#include <openssl/proverr.h>
 #include "internal/cryptlib.h"
 #include "internal/numbers.h"
 #include "crypto/evp.h"
-#include "internal/provider_ctx.h"
-#include "internal/providercommonerr.h"
-#include "internal/provider_algs.h"
-#include "internal/provider_util.h"
+#include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/provider_util.h"
+#include "internal/params.h"
 
 typedef struct {
     void *provctx;
@@ -61,6 +63,7 @@ typedef struct {
     unsigned char *salt;
     size_t salt_len;
     size_t out_len; /* optional KMAC parameter */
+    int is_kmac;
 } KDF_SSKDF;
 
 #define SSKDF_MAX_INLEN (1<<30)
@@ -70,15 +73,16 @@ typedef struct {
 /* KMAC uses a Customisation string of 'KDF' */
 static const unsigned char kmac_custom_str[] = { 0x4B, 0x44, 0x46 };
 
-static OSSL_OP_kdf_newctx_fn sskdf_new;
-static OSSL_OP_kdf_freectx_fn sskdf_free;
-static OSSL_OP_kdf_reset_fn sskdf_reset;
-static OSSL_OP_kdf_derive_fn sskdf_derive;
-static OSSL_OP_kdf_derive_fn x963kdf_derive;
-static OSSL_OP_kdf_settable_ctx_params_fn sskdf_settable_ctx_params;
-static OSSL_OP_kdf_set_ctx_params_fn sskdf_set_ctx_params;
-static OSSL_OP_kdf_gettable_ctx_params_fn sskdf_gettable_ctx_params;
-static OSSL_OP_kdf_get_ctx_params_fn sskdf_get_ctx_params;
+static OSSL_FUNC_kdf_newctx_fn sskdf_new;
+static OSSL_FUNC_kdf_dupctx_fn sskdf_dup;
+static OSSL_FUNC_kdf_freectx_fn sskdf_free;
+static OSSL_FUNC_kdf_reset_fn sskdf_reset;
+static OSSL_FUNC_kdf_derive_fn sskdf_derive;
+static OSSL_FUNC_kdf_derive_fn x963kdf_derive;
+static OSSL_FUNC_kdf_settable_ctx_params_fn sskdf_settable_ctx_params;
+static OSSL_FUNC_kdf_set_ctx_params_fn sskdf_set_ctx_params;
+static OSSL_FUNC_kdf_gettable_ctx_params_fn sskdf_gettable_ctx_params;
+static OSSL_FUNC_kdf_get_ctx_params_fn sskdf_get_ctx_params;
 
 /*
  * Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final
@@ -107,7 +111,7 @@ static int SSKDF_hash_kdm(const EVP_MD *kdf_md,
             || derived_key_len == 0)
         return 0;
 
-    hlen = EVP_MD_size(kdf_md);
+    hlen = EVP_MD_get_size(kdf_md);
     if (hlen <= 0)
         return 0;
     out_len = (size_t)hlen;
@@ -222,31 +226,23 @@ static int SSKDF_mac_kdm(EVP_MAC_CTX *ctx_init,
     unsigned char *out = derived_key;
     EVP_MAC_CTX *ctx = NULL;
     unsigned char *mac = mac_buf, *kmac_buffer = NULL;
-    OSSL_PARAM params[2], *p = params;
 
     if (z_len > SSKDF_MAX_INLEN || info_len > SSKDF_MAX_INLEN
             || derived_key_len > SSKDF_MAX_INLEN
             || derived_key_len == 0)
         return 0;
 
-    *p++ = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
-                                             (void *)salt, salt_len);
-    *p = OSSL_PARAM_construct_end();
-
-    if (!EVP_MAC_CTX_set_params(ctx_init, params))
-        goto end;
-
     if (!kmac_init(ctx_init, kmac_custom, kmac_custom_len, kmac_out_len,
                    derived_key_len, &kmac_buffer))
         goto end;
     if (kmac_buffer != NULL)
         mac = kmac_buffer;
 
-    if (!EVP_MAC_init(ctx_init))
+    if (!EVP_MAC_init(ctx_init, salt, salt_len, NULL))
         goto end;
 
-    out_len = EVP_MAC_size(ctx_init); /* output size */
-    if (out_len <= 0)
+    out_len = EVP_MAC_CTX_get_mac_size(ctx_init); /* output size */
+    if (out_len <= 0 || (mac == mac_buf && out_len > sizeof(mac_buf)))
         goto end;
     len = derived_key_len;
 
@@ -270,7 +266,7 @@ static int SSKDF_mac_kdm(EVP_MAC_CTX *ctx_init,
             if (len == 0)
                 break;
         } else {
-            if (!EVP_MAC_final(ctx, mac, NULL, len))
+            if (!EVP_MAC_final(ctx, mac, NULL, out_len))
                 goto end;
             memcpy(out, mac, len);
             break;
@@ -293,15 +289,18 @@ static void *sskdf_new(void *provctx)
 {
     KDF_SSKDF *ctx;
 
-    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
-        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
-    ctx->provctx = provctx;
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL)
+        ctx->provctx = provctx;
     return ctx;
 }
 
 static void sskdf_reset(void *vctx)
 {
     KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
+    void *provctx = ctx->provctx;
 
     EVP_MAC_CTX_free(ctx->macctx);
     ossl_prov_digest_reset(&ctx->digest);
@@ -309,48 +308,79 @@ static void sskdf_reset(void *vctx)
     OPENSSL_clear_free(ctx->info, ctx->info_len);
     OPENSSL_clear_free(ctx->salt, ctx->salt_len);
     memset(ctx, 0, sizeof(*ctx));
+    ctx->provctx = provctx;
 }
 
 static void sskdf_free(void *vctx)
 {
     KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
 
-    sskdf_reset(ctx);
-    OPENSSL_free(ctx);
+    if (ctx != NULL) {
+        sskdf_reset(ctx);
+        OPENSSL_free(ctx);
+    }
 }
 
-static int sskdf_set_buffer(unsigned char **out, size_t *out_len,
-                            const OSSL_PARAM *p)
+static void *sskdf_dup(void *vctx)
 {
-    if (p->data == NULL || p->data_size == 0)
-        return 1;
-    OPENSSL_free(*out);
-    *out = NULL;
-    return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len);
+    const KDF_SSKDF *src = (const KDF_SSKDF *)vctx;
+    KDF_SSKDF *dest;
+
+    dest = sskdf_new(src->provctx);
+    if (dest != NULL) {
+        if (src->macctx != NULL) {
+            dest->macctx = EVP_MAC_CTX_dup(src->macctx);
+            if (dest->macctx == NULL)
+                goto err;
+        }
+        if (!ossl_prov_memdup(src->info, src->info_len,
+                              &dest->info, &dest->info_len)
+                || !ossl_prov_memdup(src->salt, src->salt_len,
+                                     &dest->salt , &dest->salt_len)
+                || !ossl_prov_memdup(src->secret, src->secret_len,
+                                     &dest->secret, &dest->secret_len)
+                || !ossl_prov_digest_copy(&dest->digest, &src->digest))
+            goto err;
+        dest->out_len = src->out_len;
+        dest->is_kmac = src->is_kmac;
+    }
+    return dest;
+
+ err:
+    sskdf_free(dest);
+    return NULL;
 }
 
 static size_t sskdf_size(KDF_SSKDF *ctx)
 {
     int len;
-    const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+    const EVP_MD *md = NULL;
 
+    if (ctx->is_kmac)
+        return SIZE_MAX;
+
+    md = ossl_prov_digest_md(&ctx->digest);
     if (md == NULL) {
         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
         return 0;
     }
-    len = EVP_MD_size(md);
+    len = EVP_MD_get_size(md);
     return (len <= 0) ? 0 : (size_t)len;
 }
 
-static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
+static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen,
+                        const OSSL_PARAM params[])
 {
     KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
-    const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+    const EVP_MD *md;
 
+    if (!ossl_prov_is_running() || !sskdf_set_ctx_params(ctx, params))
+        return 0;
     if (ctx->secret == NULL) {
         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET);
         return 0;
     }
+    md = ossl_prov_digest_md(&ctx->digest);
 
     if (ctx->macctx != NULL) {
         /* H(x) = KMAC or H(x) = HMAC */
@@ -358,24 +388,18 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
         const unsigned char *custom = NULL;
         size_t custom_len = 0;
         int default_salt_len;
-        EVP_MAC *mac = EVP_MAC_CTX_mac(ctx->macctx);
+        EVP_MAC *mac = EVP_MAC_CTX_get0_mac(ctx->macctx);
 
-        /*
-         * TODO(3.0) investigate the necessity to have all these controls.
-         * Why does KMAC require a salt length that's shorter than the MD
-         * block size?
-         */
         if (EVP_MAC_is_a(mac, OSSL_MAC_NAME_HMAC)) {
             /* H(x) = HMAC(x, salt, hash) */
             if (md == NULL) {
                 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
                 return 0;
             }
-            default_salt_len = EVP_MD_size(md);
+            default_salt_len = EVP_MD_get_size(md);
             if (default_salt_len <= 0)
                 return 0;
-        } else if (EVP_MAC_is_a(mac, OSSL_MAC_NAME_KMAC128)
-                   || EVP_MAC_is_a(mac, OSSL_MAC_NAME_KMAC256)) {
+        } else if (ctx->is_kmac) {
             /* H(x) = KMACzzz(x, salt, custom) */
             custom = kmac_custom_str;
             custom_len = sizeof(kmac_custom_str);
@@ -390,10 +414,8 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
         /* If no salt is set then use a default_salt of zeros */
         if (ctx->salt == NULL || ctx->salt_len <= 0) {
             ctx->salt = OPENSSL_zalloc(default_salt_len);
-            if (ctx->salt == NULL) {
-                ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+            if (ctx->salt == NULL)
                 return 0;
-            }
             ctx->salt_len = default_salt_len;
         }
         ret = SSKDF_mac_kdm(ctx->macctx,
@@ -413,10 +435,14 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
     }
 }
 
-static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen)
+static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen,
+                          const OSSL_PARAM params[])
 {
     KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
-    const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+    const EVP_MD *md;
+
+    if (!ossl_prov_is_running() || !sskdf_set_ctx_params(ctx, params))
+        return 0;
 
     if (ctx->secret == NULL) {
         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET);
@@ -429,6 +455,7 @@ static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen)
     }
 
     /* H(x) = hash */
+    md = ossl_prov_digest_md(&ctx->digest);
     if (md == NULL) {
         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
         return 0;
@@ -442,27 +469,42 @@ static int sskdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
 {
     const OSSL_PARAM *p;
     KDF_SSKDF *ctx = vctx;
-    OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+    OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
     size_t sz;
+    int r;
 
-    if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
-        return 0;
+    if (params == NULL)
+        return 1;
 
     if (!ossl_prov_macctx_load_from_params(&ctx->macctx, params,
                                            NULL, NULL, NULL, libctx))
         return 0;
+    if (ctx->macctx != NULL) {
+         if (EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx),
+                          OSSL_MAC_NAME_KMAC128)
+             || EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx),
+                             OSSL_MAC_NAME_KMAC256)) {
+             ctx->is_kmac = 1;
+         }
+    }
+
+    if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
+        return 0;
 
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL
-        || (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
-        if (!sskdf_set_buffer(&ctx->secret, &ctx->secret_len, p))
-            return 0;
+    r = ossl_param_get1_octet_string(params, OSSL_KDF_PARAM_SECRET,
+                                     &ctx->secret, &ctx->secret_len);
+    if (r == -1)
+        r = ossl_param_get1_octet_string(params, OSSL_KDF_PARAM_KEY,
+                                         &ctx->secret, &ctx->secret_len);
+    if (r == 0)
+        return 0;
 
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL)
-        if (!sskdf_set_buffer(&ctx->info, &ctx->info_len, p))
-            return 0;
+    if (ossl_param_get1_concat_octet_string(params, OSSL_KDF_PARAM_INFO,
+                                            &ctx->info, &ctx->info_len, 0) == 0)
+        return 0;
 
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL)
-        if (!sskdf_set_buffer(&ctx->salt, &ctx->salt_len, p))
+    if (ossl_param_get1_octet_string(params, OSSL_KDF_PARAM_SALT,
+                                     &ctx->salt, &ctx->salt_len) == 0)
             return 0;
 
     if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MAC_SIZE))
@@ -474,7 +516,8 @@ static int sskdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     return 1;
 }
 
-static const OSSL_PARAM *sskdf_settable_ctx_params(void)
+static const OSSL_PARAM *sskdf_settable_ctx_params(ossl_unused void *ctx,
+                                                   ossl_unused void *provctx)
 {
     static const OSSL_PARAM known_settable_ctx_params[] = {
         OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0),
@@ -500,7 +543,8 @@ static int sskdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
     return -2;
 }
 
-static const OSSL_PARAM *sskdf_gettable_ctx_params(void)
+static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx,
+                                                   ossl_unused void *provctx)
 {
     static const OSSL_PARAM known_gettable_ctx_params[] = {
         OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
@@ -509,8 +553,9 @@ static const OSSL_PARAM *sskdf_gettable_ctx_params(void)
     return known_gettable_ctx_params;
 }
 
-const OSSL_DISPATCH kdf_sskdf_functions[] = {
+const OSSL_DISPATCH ossl_kdf_sskdf_functions[] = {
     { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new },
+    { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))sskdf_dup },
     { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free },
     { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset },
     { OSSL_FUNC_KDF_DERIVE, (void(*)(void))sskdf_derive },
@@ -520,11 +565,12 @@ const OSSL_DISPATCH kdf_sskdf_functions[] = {
     { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
       (void(*)(void))sskdf_gettable_ctx_params },
     { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))sskdf_get_ctx_params },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };
 
-const OSSL_DISPATCH kdf_x963_kdf_functions[] = {
+const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[] = {
     { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new },
+    { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))sskdf_dup },
     { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free },
     { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset },
     { OSSL_FUNC_KDF_DERIVE, (void(*)(void))x963kdf_derive },
@@ -534,5 +580,5 @@ const OSSL_DISPATCH kdf_x963_kdf_functions[] = {
     { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
       (void(*)(void))sskdf_gettable_ctx_params },
     { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))sskdf_get_ctx_params },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };