Fix migration guide mappings for i2o/o2i_ECPublicKey
[openssl.git] / providers / implementations / kdfs / scrypt.c
index 77869f957d77f7d08601f6c1e04401c776773cd2..ee2d4a7d321c9697f746761dbb11325246e6cb02 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017-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
 #include <openssl/kdf.h>
 #include <openssl/err.h>
 #include <openssl/core_names.h>
+#include <openssl/proverr.h>
 #include "crypto/evp.h"
 #include "internal/numbers.h"
 #include "prov/implementations.h"
 #include "prov/provider_ctx.h"
-#include "prov/providercommonerr.h"
-#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_util.h"
 
 #ifndef OPENSSL_NO_SCRYPT
 
 static OSSL_FUNC_kdf_newctx_fn kdf_scrypt_new;
+static OSSL_FUNC_kdf_dupctx_fn kdf_scrypt_dup;
 static OSSL_FUNC_kdf_freectx_fn kdf_scrypt_free;
 static OSSL_FUNC_kdf_reset_fn kdf_scrypt_reset;
 static OSSL_FUNC_kdf_derive_fn kdf_scrypt_derive;
 static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_scrypt_settable_ctx_params;
 static OSSL_FUNC_kdf_set_ctx_params_fn kdf_scrypt_set_ctx_params;
+static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_scrypt_gettable_ctx_params;
+static OSSL_FUNC_kdf_get_ctx_params_fn kdf_scrypt_get_ctx_params;
 
 static int scrypt_alg(const char *pass, size_t passlen,
                       const unsigned char *salt, size_t saltlen,
                       uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
-                      unsigned char *key, size_t keylen, EVP_MD *sha256);
+                      unsigned char *key, size_t keylen, EVP_MD *sha256,
+                      OSSL_LIB_CTX *libctx, const char *propq);
 
 typedef struct {
-    void *provctx;
+    OSSL_LIB_CTX *libctx;
+    char *propq;
     unsigned char *pass;
     size_t pass_len;
     unsigned char *salt;
@@ -49,32 +55,32 @@ typedef struct {
 
 static void kdf_scrypt_init(KDF_SCRYPT *ctx);
 
-static void *kdf_scrypt_new(void *provctx)
+static void *kdf_scrypt_new_inner(OSSL_LIB_CTX *libctx)
 {
     KDF_SCRYPT *ctx;
 
-    ctx = OPENSSL_zalloc(sizeof(*ctx));
-    if (ctx == NULL) {
-        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+    if (!ossl_prov_is_running())
         return NULL;
-    }
-    ctx->provctx = provctx;
-    ctx->sha256 = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(provctx),
-                               "sha256", NULL);
-    if (ctx->sha256 == NULL) {
-        OPENSSL_free(ctx);
-        ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256);
+
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx == NULL)
         return NULL;
-    }
+    ctx->libctx = libctx;
     kdf_scrypt_init(ctx);
     return ctx;
 }
 
+static void *kdf_scrypt_new(void *provctx)
+{
+    return kdf_scrypt_new_inner(PROV_LIBCTX_OF(provctx));
+}
+
 static void kdf_scrypt_free(void *vctx)
 {
     KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx;
 
     if (ctx != NULL) {
+        OPENSSL_free(ctx->propq);
         EVP_MD_free(ctx->sha256);
         kdf_scrypt_reset(ctx);
         OPENSSL_free(ctx);
@@ -90,6 +96,38 @@ static void kdf_scrypt_reset(void *vctx)
     kdf_scrypt_init(ctx);
 }
 
+static void *kdf_scrypt_dup(void *vctx)
+{
+    const KDF_SCRYPT *src = (const KDF_SCRYPT *)vctx;
+    KDF_SCRYPT *dest;
+
+    dest = kdf_scrypt_new_inner(src->libctx);
+    if (dest != NULL) {
+        if (src->sha256 != NULL && !EVP_MD_up_ref(src->sha256))
+            goto err;
+        if (src->propq != NULL) {
+            dest->propq = OPENSSL_strdup(src->propq);
+            if (dest->propq == NULL)
+                goto err;
+        }
+        if (!ossl_prov_memdup(src->salt, src->salt_len,
+                              &dest->salt, &dest->salt_len)
+                || !ossl_prov_memdup(src->pass, src->pass_len,
+                                     &dest->pass , &dest->pass_len))
+            goto err;
+        dest->N = src->N;
+        dest->r = src->r;
+        dest->p = src->p;
+        dest->maxmem_bytes = src->maxmem_bytes;
+        dest->sha256 = src->sha256;
+    }
+    return dest;
+
+ err:
+    kdf_scrypt_free(dest);
+    return NULL;
+}
+
 static void kdf_scrypt_init(KDF_SCRYPT *ctx)
 {
     /* Default values are the most conservative recommendation given in the
@@ -106,24 +144,51 @@ static int scrypt_set_membuf(unsigned char **buffer, size_t *buflen,
                              const OSSL_PARAM *p)
 {
     OPENSSL_clear_free(*buffer, *buflen);
+    *buffer = NULL;
+    *buflen = 0;
+
     if (p->data_size == 0) {
-        if ((*buffer = OPENSSL_malloc(1)) == NULL) {
-            ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        if ((*buffer = OPENSSL_malloc(1)) == NULL)
             return 0;
-        }
     } else if (p->data != NULL) {
-        *buffer = NULL;
         if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen))
             return 0;
     }
     return 1;
 }
 
-static int kdf_scrypt_derive(void *vctx, unsigned char *key,
-                             size_t keylen)
+static int set_digest(KDF_SCRYPT *ctx)
+{
+    EVP_MD_free(ctx->sha256);
+    ctx->sha256 = EVP_MD_fetch(ctx->libctx, "sha256", ctx->propq);
+    if (ctx->sha256 == NULL) {
+        OPENSSL_free(ctx);
+        ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256);
+        return 0;
+    }
+    return 1;
+}
+
+static int set_property_query(KDF_SCRYPT *ctx, const char *propq)
+{
+    OPENSSL_free(ctx->propq);
+    ctx->propq = NULL;
+    if (propq != NULL) {
+        ctx->propq = OPENSSL_strdup(propq);
+        if (ctx->propq == NULL)
+            return 0;
+    }
+    return 1;
+}
+
+static int kdf_scrypt_derive(void *vctx, unsigned char *key, size_t keylen,
+                             const OSSL_PARAM params[])
 {
     KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx;
 
+    if (!ossl_prov_is_running() || !kdf_scrypt_set_ctx_params(ctx, params))
+        return 0;
+
     if (ctx->pass == NULL) {
         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS);
         return 0;
@@ -134,9 +199,13 @@ static int kdf_scrypt_derive(void *vctx, unsigned char *key,
         return 0;
     }
 
+    if (ctx->sha256 == NULL && !set_digest(ctx))
+        return 0;
+
     return scrypt_alg((char *)ctx->pass, ctx->pass_len, ctx->salt,
                       ctx->salt_len, ctx->N, ctx->r, ctx->p,
-                      ctx->maxmem_bytes, key, keylen, ctx->sha256);
+                      ctx->maxmem_bytes, key, keylen, ctx->sha256,
+                      ctx->libctx, ctx->propq);
 }
 
 static int is_power_of_two(uint64_t value)
@@ -150,6 +219,9 @@ static int kdf_scrypt_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     KDF_SCRYPT *ctx = vctx;
     uint64_t u64_value;
 
+    if (params == NULL)
+        return 1;
+
     if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL)
         if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
             return 0;
@@ -187,10 +259,19 @@ static int kdf_scrypt_set_ctx_params(void *vctx, const OSSL_PARAM params[])
             return 0;
         ctx->maxmem_bytes = u64_value;
     }
+
+    p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES);
+    if (p != NULL) {
+        if (p->data_type != OSSL_PARAM_UTF8_STRING
+            || !set_property_query(ctx, p->data)
+            || !set_digest(ctx))
+            return 0;
+    }
     return 1;
 }
 
-static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(void)
+static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(ossl_unused void *ctx,
+                                                        ossl_unused void *p_ctx)
 {
     static const OSSL_PARAM known_settable_ctx_params[] = {
         OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0),
@@ -199,6 +280,7 @@ static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(void)
         OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_R, NULL),
         OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_P, NULL),
         OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, NULL),
+        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
         OSSL_PARAM_END
     };
     return known_settable_ctx_params;
@@ -213,7 +295,8 @@ static int kdf_scrypt_get_ctx_params(void *vctx, OSSL_PARAM params[])
     return -2;
 }
 
-static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(void)
+static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(ossl_unused void *ctx,
+                                                        ossl_unused void *p_ctx)
 {
     static const OSSL_PARAM known_gettable_ctx_params[] = {
         OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
@@ -222,8 +305,9 @@ static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(void)
     return known_gettable_ctx_params;
 }
 
-const OSSL_DISPATCH kdf_scrypt_functions[] = {
+const OSSL_DISPATCH ossl_kdf_scrypt_functions[] = {
     { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_scrypt_new },
+    { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_scrypt_dup },
     { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_scrypt_free },
     { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_scrypt_reset },
     { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_scrypt_derive },
@@ -233,7 +317,7 @@ const OSSL_DISPATCH kdf_scrypt_functions[] = {
     { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
       (void(*)(void))kdf_scrypt_gettable_ctx_params },
     { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_scrypt_get_ctx_params },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };
 
 #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
@@ -359,7 +443,8 @@ static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N,
 static int scrypt_alg(const char *pass, size_t passlen,
                       const unsigned char *salt, size_t saltlen,
                       uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
-                      unsigned char *key, size_t keylen, EVP_MD *sha256)
+                      unsigned char *key, size_t keylen, EVP_MD *sha256,
+                      OSSL_LIB_CTX *libctx, const char *propq)
 {
     int rv = 0;
     unsigned char *B;
@@ -372,7 +457,7 @@ static int scrypt_alg(const char *pass, size_t passlen,
         return 0;
     /* Check p * r < SCRYPT_PR_MAX avoiding overflow */
     if (p > SCRYPT_PR_MAX / r) {
-        EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+        ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
         return 0;
     }
 
@@ -383,7 +468,7 @@ static int scrypt_alg(const char *pass, size_t passlen,
 
     if (16 * r <= LOG2_UINT64_MAX) {
         if (N >= (((uint64_t)1) << (16 * r))) {
-            EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+            ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
             return 0;
         }
     }
@@ -401,7 +486,7 @@ static int scrypt_alg(const char *pass, size_t passlen,
      * have to be revised when/if PKCS5_PBKDF2_HMAC accepts size_t.]
      */
     if (Blen > INT_MAX) {
-        EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+        ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
         return 0;
     }
 
@@ -411,14 +496,14 @@ static int scrypt_alg(const char *pass, size_t passlen,
      */
     i = UINT64_MAX / (32 * sizeof(uint32_t));
     if (N + 2 > i / r) {
-        EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+        ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
         return 0;
     }
     Vlen = 32 * r * (N + 2) * sizeof(uint32_t);
 
     /* check total allocated size fits in uint64_t */
     if (Blen > UINT64_MAX - Vlen) {
-        EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+        ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
         return 0;
     }
 
@@ -427,7 +512,7 @@ static int scrypt_alg(const char *pass, size_t passlen,
         maxmem = SIZE_MAX;
 
     if (Blen + Vlen > maxmem) {
-        EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+        ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
         return 0;
     }
 
@@ -436,27 +521,25 @@ static int scrypt_alg(const char *pass, size_t passlen,
         return 1;
 
     B = OPENSSL_malloc((size_t)(Blen + Vlen));
-    if (B == NULL) {
-        EVPerr(EVP_F_SCRYPT_ALG, ERR_R_MALLOC_FAILURE);
+    if (B == NULL)
         return 0;
-    }
     X = (uint32_t *)(B + Blen);
     T = X + 32 * r;
     V = T + 32 * r;
-    if (PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, 1, sha256,
-                          (int)Blen, B) == 0)
+    if (ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, salt, saltlen, 1, sha256,
+                                  (int)Blen, B, libctx, propq) == 0)
         goto err;
 
     for (i = 0; i < p; i++)
         scryptROMix(B + 128 * r * i, r, N, X, T, V);
 
-    if (PKCS5_PBKDF2_HMAC(pass, passlen, B, (int)Blen, 1, sha256,
-                          keylen, key) == 0)
+    if (ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, B, (int)Blen, 1, sha256,
+                                  keylen, key, libctx, propq) == 0)
         goto err;
     rv = 1;
  err:
     if (rv == 0)
-        EVPerr(EVP_F_SCRYPT_ALG, EVP_R_PBKDF2_ERROR);
+        ERR_raise(ERR_LIB_EVP, EVP_R_PBKDF2_ERROR);
 
     OPENSSL_clear_free(B, (size_t)(Blen + Vlen));
     return rv;