Security hardening: Expose Build flags for Position Independed Execution (PIE)
[openssl.git] / providers / implementations / kdfs / hkdf.c
index 867d27c79ebc18bd5d0e47dd0b4e746e9ed1678d..3f65346a2b0b72f5016c587812ae40598c5b0f50 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 The OpenSSL Project Authors. 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
@@ -30,6 +30,7 @@
 #include "prov/implementations.h"
 #include "prov/provider_util.h"
 #include "internal/e_os.h"
+#include "internal/params.h"
 
 #define HKDF_MAXBUF 2048
 #define HKDF_MAXINFO (32*1024)
@@ -274,44 +275,8 @@ static int hkdf_common_set_ctx_params(KDF_HKDF *ctx, const OSSL_PARAM params[])
     return 1;
 }
 
-/*
- * Use WPACKET to concat one or more OSSL_KDF_PARAM_INFO fields into a fixed
- * out buffer of size *outlen.
- * If out is NULL then outlen is used to return the required buffer size.
- */
-static int setinfo_fromparams(const OSSL_PARAM *p, unsigned char *out, size_t *outlen)
-{
-    int ret = 0;
-    WPACKET pkt;
-
-    if (out == NULL) {
-        if (!WPACKET_init_null(&pkt, 0))
-            return 0;
-    } else {
-        if (!WPACKET_init_static_len(&pkt, out, *outlen, 0))
-            return 0;
-    }
-
-    for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_INFO)) {
-        if (p->data_type != OSSL_PARAM_OCTET_STRING)
-            goto err;
-        if (p->data != NULL
-                && p->data_size != 0
-                && !WPACKET_memcpy(&pkt, p->data, p->data_size))
-            goto err;
-    }
-    if (!WPACKET_get_total_written(&pkt, outlen)
-            || !WPACKET_finish(&pkt))
-        goto err;
-    ret = 1;
-err:
-    WPACKET_cleanup(&pkt);
-    return ret;
-}
-
 static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
 {
-    const OSSL_PARAM *p;
     KDF_HKDF *ctx = vctx;
 
     if (params == NULL)
@@ -320,29 +285,11 @@ static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     if (!hkdf_common_set_ctx_params(ctx, params))
         return 0;
 
-    /* The info fields concatenate, so process them all */
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) {
-        size_t sz = 0;
-
-        /* calculate the total size */
-        if (!setinfo_fromparams(p, NULL, &sz))
-            return 0;
-        if (sz > HKDF_MAXINFO)
-            return 0;
+    if (ossl_param_get1_concat_octet_string(params, OSSL_KDF_PARAM_INFO,
+                                            &ctx->info, &ctx->info_len,
+                                            HKDF_MAXINFO) == 0)
+        return 0;
 
-        OPENSSL_clear_free(ctx->info, ctx->info_len);
-        ctx->info = NULL;
-        if (sz == 0)
-            return 1;
-        /* Alloc the buffer */
-        ctx->info = OPENSSL_malloc(sz);
-        if (ctx->info == NULL)
-            return 0;
-        ctx->info_len = sz;
-        /* Concat one or more OSSL_KDF_PARAM_INFO fields */
-        if (!setinfo_fromparams(p, ctx->info, &sz))
-            return 0;
-    }
     return 1;
 }
 
@@ -369,6 +316,13 @@ static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
             return 0;
         return OSSL_PARAM_set_size_t(p, sz);
     }
+    if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_INFO)) != NULL) {
+        if (ctx->info == NULL || ctx->info_len == 0) {
+            p->return_size = 0;
+            return 1;
+        }
+        return OSSL_PARAM_set_octet_string(p, ctx->info, ctx->info_len);
+    }
     return -2;
 }
 
@@ -377,6 +331,7 @@ static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx,
 {
     static const OSSL_PARAM known_gettable_ctx_params[] = {
         OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0),
         OSSL_PARAM_END
     };
     return known_gettable_ctx_params;
@@ -394,7 +349,7 @@ const OSSL_DISPATCH ossl_kdf_hkdf_functions[] = {
     { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
       (void(*)(void))kdf_hkdf_gettable_ctx_params },
     { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };
 
 /*
@@ -584,7 +539,7 @@ static int HKDF_Expand(const EVP_MD *evp_md,
         if (!HMAC_Final(hmac, prev, NULL))
             goto err;
 
-        copy_len = (done_len + dig_len > okm_len) ?
+        copy_len = (dig_len > okm_len - done_len) ?
                        okm_len - done_len :
                        dig_len;
 
@@ -676,7 +631,7 @@ static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx,
     }
     if (prevsecret == NULL) {
         prevsecret = default_zeros;
-        prevsecretlen = 0;
+        prevsecretlen = mdlen;
     } else {
         EVP_MD_CTX *mctx = EVP_MD_CTX_new();
         unsigned char hash[EVP_MAX_MD_SIZE];
@@ -810,5 +765,5 @@ const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[] = {
     { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
       (void(*)(void))kdf_hkdf_gettable_ctx_params },
     { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };