Browse Source

Blake2b: Use OSSL_DIGEST_PARAM_SIZE as settable instead of XOFLEN

BLAKE2 is not really an extensible output function unlike SHAKE
as the digest size must be set during the context initialization.
Thus it makes no sense to use OSSL_DIGEST_PARAM_XOFLEN.

We also need to adjust EVP_DigestFinal_ex() to query the
OSSL_DIGEST_PARAM_SIZE as gettable ctx param for the size.

Fixes #22488

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22491)
Tomas Mraz 7 months ago
parent
commit
6a0ae393dd

+ 9 - 0
crypto/evp/digest.c

@@ -454,6 +454,15 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize)
     if (ctx->digest->prov == NULL)
         goto legacy;
 
+    if (ctx->digest->gettable_ctx_params != NULL) {
+        OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+        params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE,
+                                                &mdsize);
+        if (!EVP_MD_CTX_get_params(ctx, params))
+            return 0;
+    }
+
     if (ctx->digest->dfinal == NULL) {
         ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
         return 0;

+ 5 - 3
doc/man3/EVP_DigestInit.pod

@@ -282,9 +282,11 @@ data.
 Retrieves the digest value from I<ctx> and places it in I<md>. If the I<s>
 parameter is not NULL then the number of bytes of data written (i.e. the
 length of the digest) will be written to the integer at I<s>, at most
-B<EVP_MAX_MD_SIZE> bytes will be written.  After calling EVP_DigestFinal_ex()
-no additional calls to EVP_DigestUpdate() can be made, but
-EVP_DigestInit_ex2() can be called to initialize a new digest operation.
+B<EVP_MAX_MD_SIZE> bytes will be written unless the digest implementation
+allows changing the digest size and it is set to a larger value by the
+application. After calling EVP_DigestFinal_ex() no additional calls to
+EVP_DigestUpdate() can be made, but EVP_DigestInit_ex2() can be called to
+initialize a new digest operation.
 
 =item EVP_DigestFinalXOF()
 

+ 15 - 0
doc/man7/EVP_MD-BLAKE2.pod

@@ -30,6 +30,21 @@ Known names are "BLAKE2B-512" and "BLAKE2b512".
 This implementation supports the common gettable parameters described
 in L<EVP_MD-common(7)>.
 
+=head2 Settable Context Parameters
+
+The BLAKE2B-512 implementation supports the following L<OSSL_PARAM(3)> entries,
+settable for an B<EVP_MD_CTX> with L<EVP_MD_CTX_set_params(3)>:
+
+=over 4
+
+=item "size" (B<OSSL_DIGEST_PARAM_SIZE>) <unsigned integer>
+
+Sets a different digest length for the L<EVP_DigestFinal(3)> output.
+The value of the "size" parameter should not exceed 255 and it must be set
+during the L<EVP_DigestInit_ex2(3)> call.
+
+=back
+
 =head1 SEE ALSO
 
 L<provider-digest(7)>, L<OSSL_PROVIDER-default(7)>

+ 22 - 7
providers/implementations/digests/blake2_prov.c

@@ -8,6 +8,7 @@
  */
 
 #include <openssl/crypto.h>
+#include <openssl/proverr.h>
 #include "prov/blake2.h"
 #include "prov/digestcommon.h"
 #include "prov/implementations.h"
@@ -83,14 +84,23 @@ static int blake2b512_internal_final(void *ctx, unsigned char *out,
                                      size_t *outl, size_t outsz)
 {
     struct blake2b_md_data_st *b_ctx;
-    
+
     b_ctx = (struct blake2b_md_data_st *)ctx;
-    *outl = b_ctx->ctx.outlen;
 
     if (!ossl_prov_is_running())
         return 0;
 
-    return (outsz > 0) ? ossl_blake2b_final(out, ctx) : 1;
+    *outl = b_ctx->ctx.outlen;
+
+    if (outsz == 0)
+       return 1;
+
+    if (outsz < *outl) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE);
+        return 0;
+    }
+
+    return ossl_blake2b_final(out, ctx);
 }
 
 static int blake2b512_get_params(OSSL_PARAM params[])
@@ -98,8 +108,8 @@ static int blake2b512_get_params(OSSL_PARAM params[])
     return ossl_digest_default_get_params(params, BLAKE2B_BLOCKBYTES, 64, 0);
 }
 
-const OSSL_DISPATCH ossl_blake2b512_functions[] =
-    { {OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))blake2b512_newctx},
+const OSSL_DISPATCH ossl_blake2b512_functions[] = {
+    {OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))blake2b512_newctx},
     {OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))ossl_blake2b_update},
     {OSSL_FUNC_DIGEST_FINAL, (void (*)(void))blake2b512_internal_final},
     {OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))blake2b512_freectx},
@@ -108,8 +118,13 @@ const OSSL_DISPATCH ossl_blake2b512_functions[] =
     {OSSL_FUNC_DIGEST_GETTABLE_PARAMS,
      (void (*)(void))ossl_digest_default_gettable_params},
     {OSSL_FUNC_DIGEST_INIT, (void (*)(void))blake2b512_internal_init},
+    {OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS,
+     (void (*)(void))ossl_blake2b_gettable_ctx_params},
     {OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS,
      (void (*)(void))ossl_blake2b_settable_ctx_params},
+    {OSSL_FUNC_DIGEST_GET_CTX_PARAMS,
+     (void (*)(void))ossl_blake2b_get_ctx_params},
     {OSSL_FUNC_DIGEST_SET_CTX_PARAMS,
-     (void (*)(void))ossl_blake2b_set_ctx_params}, {0, NULL} };
-
+     (void (*)(void))ossl_blake2b_set_ctx_params},
+    {0, NULL}
+};

+ 40 - 7
providers/implementations/digests/blake2b_prov.c

@@ -20,23 +20,52 @@
 #include <openssl/core_names.h>
 #include <openssl/proverr.h>
 #include <openssl/err.h>
+#include "internal/numbers.h"
 #include "blake2_impl.h"
 #include "prov/blake2.h"
 
-static const OSSL_PARAM known_blake2b_settable_ctx_params[] = {
-    {OSSL_DIGEST_PARAM_XOFLEN, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
+static const OSSL_PARAM known_blake2b_ctx_params[] = {
+    {OSSL_DIGEST_PARAM_SIZE, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
     OSSL_PARAM_END
 };
 
+const OSSL_PARAM *ossl_blake2b_gettable_ctx_params(ossl_unused void *ctx,
+                                                   ossl_unused void *pctx)
+{
+    return known_blake2b_ctx_params;
+}
+
 const OSSL_PARAM *ossl_blake2b_settable_ctx_params(ossl_unused void *ctx,
                                                    ossl_unused void *pctx)
 {
-    return known_blake2b_settable_ctx_params;
+    return known_blake2b_ctx_params;
+}
+
+int ossl_blake2b_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+    struct blake2b_md_data_st *mdctx = vctx;
+    OSSL_PARAM *p;
+
+    BLAKE2B_CTX *ctx = &mdctx->ctx;
+
+    if (ctx == NULL)
+        return 0;
+    if (params == NULL)
+        return 1;
+
+    p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE);
+    if (p != NULL
+        && !OSSL_PARAM_set_uint(p, (unsigned int)mdctx->params.digest_length)) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+
+    return 1;
 }
 
 int ossl_blake2b_set_ctx_params(void *vctx, const OSSL_PARAM params[])
 {
-    size_t xoflen;
+    size_t size;
     struct blake2b_md_data_st *mdctx = vctx;
     const OSSL_PARAM *p;
 
@@ -47,13 +76,17 @@ int ossl_blake2b_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     if (params == NULL)
         return 1;
 
-    p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_XOFLEN);
+    p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_SIZE);
     if (p != NULL) {
-        if (!OSSL_PARAM_get_size_t(p, &xoflen)) {
+        if (!OSSL_PARAM_get_size_t(p, &size)) {
             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
             return 0;
         }
-        ossl_blake2b_param_set_digest_length(&mdctx->params, (uint8_t)xoflen);
+        if (size < 1 || size > UINT8_MAX) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE);
+            return 0;
+        }
+        ossl_blake2b_param_set_digest_length(&mdctx->params, (uint8_t)size);
     }
 
     return 1;

+ 2 - 0
providers/implementations/include/prov/blake2.h

@@ -94,7 +94,9 @@ int ossl_blake2b_init_key(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P,
 int ossl_blake2b_update(BLAKE2B_CTX *c, const void *data, size_t datalen);
 int ossl_blake2b_final(unsigned char *md, BLAKE2B_CTX *c);
 
+OSSL_FUNC_digest_get_ctx_params_fn ossl_blake2b_get_ctx_params;
 OSSL_FUNC_digest_set_ctx_params_fn ossl_blake2b_set_ctx_params;
+OSSL_FUNC_digest_gettable_ctx_params_fn ossl_blake2b_gettable_ctx_params;
 OSSL_FUNC_digest_settable_ctx_params_fn ossl_blake2b_settable_ctx_params;
 
 /*

+ 5 - 5
providers/implementations/kdfs/argon2.c

@@ -823,12 +823,12 @@ static int blake2b_md(EVP_MD *md, void *out, size_t outlen, const void *in,
     if ((ctx = EVP_MD_CTX_create()) == NULL)
         return 0;
 
-    par[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &outlen);
+    par[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE, &outlen);
     par[1] = OSSL_PARAM_construct_end();
 
     ret = EVP_DigestInit_ex2(ctx, md, par) == 1
         && EVP_DigestUpdate(ctx, in, inlen) == 1
-        && EVP_DigestFinalXOF(ctx, out, outlen) == 1;
+        && EVP_DigestFinal_ex(ctx, out, NULL) == 1;
 
     EVP_MD_CTX_free(ctx);
     return ret;
@@ -868,14 +868,14 @@ static int blake2b_long(EVP_MD *md, EVP_MAC *mac, unsigned char *out,
         return 0;
 
     outlen_md = (outlen <= BLAKE2B_OUTBYTES) ? outlen : BLAKE2B_OUTBYTES;
-    par[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &outlen_md);
+    par[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE, &outlen_md);
     par[1] = OSSL_PARAM_construct_end();
 
     ret = EVP_DigestInit_ex2(ctx, md, par) == 1
         && EVP_DigestUpdate(ctx, outlen_bytes, sizeof(outlen_bytes)) == 1
         && EVP_DigestUpdate(ctx, in, inlen) == 1
-        && EVP_DigestFinalXOF(ctx, (outlen > BLAKE2B_OUTBYTES) ? outbuf : out,
-                outlen_md) == 1;
+        && EVP_DigestFinal_ex(ctx, (outlen > BLAKE2B_OUTBYTES) ? outbuf : out,
+                              NULL) == 1;
 
     if (ret == 0)
         goto fail;

+ 15 - 0
test/evp_test.c

@@ -355,6 +355,8 @@ typedef struct digest_data_st {
     int pad_type;
     /* XOF mode? */
     int xof;
+    /* Size for variable output length but non-XOF */
+    size_t digest_size;
 } DIGEST_DATA;
 
 static int digest_test_init(EVP_TEST *t, const char *alg)
@@ -410,6 +412,15 @@ static int digest_test_parse(EVP_TEST *t,
         return (mdata->pad_type = atoi(value)) > 0;
     if (strcmp(keyword, "XOF") == 0)
         return (mdata->xof = atoi(value)) > 0;
+    if (strcmp(keyword, "OutputSize") == 0) {
+        int sz;
+
+        sz = atoi(value);
+        if (sz < 0)
+            return -1;
+        mdata->digest_size = sz;
+        return 1;
+    }
     return 0;
 }
 
@@ -463,6 +474,10 @@ static int digest_test_run(EVP_TEST *t)
         *p++ = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN,
                                            &expected->output_len);
     }
+    if (expected->digest_size > 0) {
+        *p++ = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE,
+                                           &expected->digest_size);
+    }
     if (expected->pad_type > 0)
         *p++ = OSSL_PARAM_construct_int(OSSL_DIGEST_PARAM_PAD_TYPE,
                                         &expected->pad_type);

+ 2 - 2
test/recipes/30-test_evp_data/evpmd_blake.txt

@@ -92,10 +92,10 @@ Output = DF0A9D0C212843A6A934E3902B2DD30D17FBA5F969D2030B12A546D8A6A45E80CF5635F
 
 Digest = BLAKE2b512
 Input =
-XOF = 1
+OutputSize = 32
 Output = 0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8
 
 Digest = BLAKE2b512
 Input = 61
-XOF = 1
+OutputSize = 32
 Output = 8928aae63c84d87ea098564d1e03ad813f107add474e56aedd286349c0c03ea4