diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 01f54792f6f377caf208a07d3ba31a9d86a0e539..42331703da3223fda7107f679df23256bb2ab016 100644 --- a/crypto/evp/digest.c +++ b/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; diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod index 9b5fda08ee9f4bd326dc64e092cbd095fef94bbb..409630e5d4db88105241d5c5a91d0e084e556494 100644 --- a/doc/man3/EVP_DigestInit.pod +++ b/doc/man3/EVP_DigestInit.pod @@ -282,9 +282,11 @@ data. Retrieves the digest value from I and places it in I. If the I 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, at most -B 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 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() diff --git a/doc/man7/EVP_MD-BLAKE2.pod b/doc/man7/EVP_MD-BLAKE2.pod index f72d3da1ce8e13c8c43d9ef26aff030c6f5c909c..205b0c59be6f339ba1d61cf92fcdad86fcfdea0b 100644 --- a/doc/man7/EVP_MD-BLAKE2.pod +++ b/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. +=head2 Settable Context Parameters + +The BLAKE2B-512 implementation supports the following L entries, +settable for an B with L: + +=over 4 + +=item "size" (B) + +Sets a different digest length for the L output. +The value of the "size" parameter should not exceed 255 and it must be set +during the L call. + +=back + =head1 SEE ALSO L, L diff --git a/providers/implementations/digests/blake2_prov.c b/providers/implementations/digests/blake2_prov.c index 34bbd7ed37d5468d8cda1fef997bb522a344b0f8..d31627b92eefcd80ccb53863d55ac1130a208327 100644 --- a/providers/implementations/digests/blake2_prov.c +++ b/providers/implementations/digests/blake2_prov.c @@ -8,6 +8,7 @@ */ #include +#include #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} +}; diff --git a/providers/implementations/digests/blake2b_prov.c b/providers/implementations/digests/blake2b_prov.c index 0e3e894a43bd44f1eee1e978897e15288de69211..ee61de8a72b501ac9c9a54e124c0358509a15cca 100644 --- a/providers/implementations/digests/blake2b_prov.c +++ b/providers/implementations/digests/blake2b_prov.c @@ -20,23 +20,52 @@ #include #include #include +#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; diff --git a/providers/implementations/include/prov/blake2.h b/providers/implementations/include/prov/blake2.h index bcd0bb9bcd4a4fca00de471cebbb19f27aa4cec9..445fd89aa21b5f958ac33a8934bebab9739741a8 100644 --- a/providers/implementations/include/prov/blake2.h +++ b/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; /* diff --git a/providers/implementations/kdfs/argon2.c b/providers/implementations/kdfs/argon2.c index d93381c410440cdee906d8a41d1b8fdcdb2b38a4..fe84ab54cad7c399b75010867ae537d30dfc243a 100644 --- a/providers/implementations/kdfs/argon2.c +++ b/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; diff --git a/test/evp_test.c b/test/evp_test.c index bd1a7cc122f370e811000e36d538ff44ee8f9016..487d6a1ad2e06e9c8c5e980a39f7a69c0fd0f6fc 100644 --- a/test/evp_test.c +++ b/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); diff --git a/test/recipes/30-test_evp_data/evpmd_blake.txt b/test/recipes/30-test_evp_data/evpmd_blake.txt index 02b3df9e9c6d14bdc35af39c5979d752aafe1d79..474e659142981bae07ca455e3cdc03671ed11766 100644 --- a/test/recipes/30-test_evp_data/evpmd_blake.txt +++ b/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