### Changes between 3.3 and 3.4 [xx XXX xxxx]
+ * XOF Digest API changes.
+
+ EVP_MD_CTX_get_size() and EVP_MD_CTX_size are macros that were aliased to
+ EVP_MD_get_size which returns a constant value. XOF Digests such as SHAKE
+ have an output size that is not fixed, so calling EVP_MD_get_size() is not
+ sufficent. The existing macros now point to the new function
+ EVP_MD_CTX_get_size_ex() which will retrieve the "size" for a XOF digest,
+ otherwise it falls back to calling EVP_MD_get_size(). Note that the SHAKE
+ implementation did not have a context getter previously, so the "size" will
+ only be able to be retrieved with new providers.
+
+ Also added a EVP_xof() helper.
+
+ *Shane Lontis*
+
* Add FIPS indicators to the FIPS provider.
FIPS 140-3 requires indicators to be used if the FIPS provider allows
non-approved algorithms. An algorithm is approved if it passes all
if (ctx->digest == NULL)
return 0;
- sz = EVP_MD_get_size(ctx->digest);
+ sz = EVP_MD_CTX_get_size(ctx);
if (sz < 0)
return 0;
mdsize = sz;
if (ctx->digest->prov == NULL)
goto legacy;
- if (sz == 0) /* Assuming a xoflen must have been set. */
- mdsize = SIZE_MAX;
- 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;
return ret;
legacy:
- if (ctx->digest->flags & EVP_MD_FLAG_XOF
+ if (EVP_MD_xof(ctx->digest)
&& size <= INT_MAX
&& ctx->digest->md_ctrl(ctx, EVP_MD_CTRL_XOF_LEN, (int)size, NULL)) {
ret = ctx->digest->final(ctx, md);
size_t mdsize = 0;
OSSL_PARAM params[5];
+ /*
+ * Note that these parameters are 'constants' that are only set up
+ * during the EVP_MD_fetch(). For this reason the XOF functions set the
+ * md_size to 0, since the output size is unknown.
+ */
params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, &blksz);
params[1] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE, &mdsize);
params[2] = OSSL_PARAM_construct_int(OSSL_DIGEST_PARAM_XOF, &xof);
return md->md_size;
}
+int EVP_MD_xof(const EVP_MD *md)
+{
+ return md != NULL && ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0);
+}
+
unsigned long EVP_MD_get_flags(const EVP_MD *md)
{
return md->flags;
return md;
}
+int EVP_MD_CTX_get_size_ex(const EVP_MD_CTX *ctx)
+{
+ EVP_MD_CTX *c = (EVP_MD_CTX *)ctx;
+ const OSSL_PARAM *gettables;
+
+ gettables = EVP_MD_CTX_gettable_params(c);
+ if (gettables != NULL
+ && OSSL_PARAM_locate_const(gettables,
+ OSSL_DIGEST_PARAM_SIZE) != NULL) {
+ OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+ size_t sz = 0;
+
+ /*
+ * For XOF's EVP_MD_get_size() returns 0
+ * So try to get the xoflen instead. This will return -1 if the
+ * xof length has not been set.
+ */
+ params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE, &sz);
+ if (EVP_MD_CTX_get_params(c, params) != 1
+ || sz == SIZE_MAX
+ || sz == 0)
+ return -1;
+ return sz;
+ }
+ /* Normal digests have a constant fixed size output */
+ return EVP_MD_get_size(EVP_MD_CTX_get0_md(ctx));
+}
+
EVP_PKEY_CTX *EVP_MD_CTX_get_pkey_ctx(const EVP_MD_CTX *ctx)
{
return ctx->pctx;
EVP_MD_names_do_all, EVP_MD_get0_provider, EVP_MD_get_type,
EVP_MD_get_pkey_type, EVP_MD_get_size, EVP_MD_get_block_size, EVP_MD_get_flags,
EVP_MD_CTX_get0_name, EVP_MD_CTX_md, EVP_MD_CTX_get0_md, EVP_MD_CTX_get1_md,
-EVP_MD_CTX_get_type, EVP_MD_CTX_get_size, EVP_MD_CTX_get_block_size,
+EVP_MD_CTX_get_type, EVP_MD_CTX_get_size_ex, EVP_MD_CTX_get_block_size,
EVP_MD_CTX_get0_md_data, EVP_MD_CTX_update_fn, EVP_MD_CTX_set_update_fn,
EVP_md_null,
EVP_get_digestbyname, EVP_get_digestbynid, EVP_get_digestbyobj,
EVP_MD_CTX_get_pkey_ctx, EVP_MD_CTX_set_pkey_ctx,
EVP_MD_do_all_provided,
EVP_MD_type, EVP_MD_nid, EVP_MD_name, EVP_MD_pkey_type, EVP_MD_size,
-EVP_MD_block_size, EVP_MD_flags, EVP_MD_CTX_size, EVP_MD_CTX_block_size,
+EVP_MD_block_size, EVP_MD_flags, EVP_MD_xof,
+EVP_MD_CTX_size, EVP_MD_CTX_get_size, EVP_MD_CTX_block_size,
EVP_MD_CTX_type, EVP_MD_CTX_pkey_ctx, EVP_MD_CTX_md_data
- EVP digest routines
int EVP_MD_get_size(const EVP_MD *md);
int EVP_MD_get_block_size(const EVP_MD *md);
unsigned long EVP_MD_get_flags(const EVP_MD *md);
+ int EVP_MD_xof(const EVP_MD *md);
const EVP_MD *EVP_MD_CTX_get0_md(const EVP_MD_CTX *ctx);
EVP_MD *EVP_MD_CTX_get1_md(EVP_MD_CTX *ctx);
const char *EVP_MD_CTX_get0_name(const EVP_MD_CTX *ctx);
- int EVP_MD_CTX_get_size(const EVP_MD_CTX *ctx);
+ int EVP_MD_CTX_get_size_ex(const EVP_MD_CTX *ctx);
int EVP_MD_CTX_get_block_size(const EVP_MD_CTX *ctx);
int EVP_MD_CTX_get_type(const EVP_MD_CTX *ctx);
void *EVP_MD_CTX_get0_md_data(const EVP_MD_CTX *ctx);
#define EVP_MD_size EVP_MD_get_size
#define EVP_MD_block_size EVP_MD_get_block_size
#define EVP_MD_flags EVP_MD_get_flags
- #define EVP_MD_CTX_size EVP_MD_CTX_get_size
+ #define EVP_MD_CTX_get_size EVP_MD_CTX_get_size_ex
+ #define EVP_MD_CTX_size EVP_MD_CTX_get_size_ex
#define EVP_MD_CTX_block_size EVP_MD_CTX_get_block_size
#define EVP_MD_CTX_type EVP_MD_CTX_get_type
#define EVP_MD_CTX_pkey_ctx EVP_MD_CTX_get_pkey_ctx
=head1 DESCRIPTION
-The EVP digest routines are a high-level interface to message digests,
-and should be used instead of the digest-specific functions.
+The EVP digest routines are a high-level interface to message digests, and
+Extendable Output Functions (XOF).
The B<EVP_MD> type is a structure for digest method implementation.
+Each Message digest algorithm (such as SHA256) produces a fixed size output
+length which is returned when EVP_DigestFinal_ex() is called.
+Extendable Output Functions (XOF) such as SHAKE256 have a variable sized output
+length I<outlen> which can be used with either EVP_DigestFinalXOF() or
+EVP_DigestSqueeze(). EVP_DigestFinal_ex() may also be used for an XOF, but the
+"xoflen" must be set beforehand (See L</PARAMETERS>).
+Note that EVP_MD_get_size() and EVP_MD_CTX_get_size_ex() behave differently for
+an XOF.
+
=over 4
=item EVP_MD_fetch()
names registered with the default library context (see
L<OSSL_LIB_CTX(3)>) will be considered.
+=item EVP_MD_xof()
+
+Returns 1 if I<md> is an Extendable-output Function (XOF) otherwise it returns
+0. SHAKE128 and SHAKE256 are XOF functions.
+It returns 0 for BLAKE2B algorithms.
+
=item EVP_MD_get0_name(),
EVP_MD_CTX_get0_name()
Returns an B<OSSL_PROVIDER> pointer to the provider that implements the given
B<EVP_MD>.
-=item EVP_MD_get_size(),
-EVP_MD_CTX_get_size()
+=item EVP_MD_get_size()
Return the size of the message digest when passed an B<EVP_MD> or an
B<EVP_MD_CTX> structure, i.e. the size of the hash.
+For an XOF this returns 0.
+
+=item EVP_MD_CTX_get_size_ex(), EVP_MD_CTX_get_size()
+
+For a normal digest this is the same as EVP_MD_get_size().
+For an XOF this returns the "xoflen" if it has been set, otherwise it returns 0.
=item EVP_MD_get_block_size(),
EVP_MD_CTX_get_block_size()
See L<OSSL_PARAM(3)> for information about passing parameters.
-EVP_MD_CTX_set_params() can be used with the following OSSL_PARAM keys:
+EVP_MD_CTX_set_params() and EVP_MD_CTX_get_params() can be used with the
+following OSSL_PARAM keys:
=over 4
=item "xoflen" (B<OSSL_DIGEST_PARAM_XOFLEN>) <unsigned integer>
-Sets the digest length for extendable output functions.
+Sets or gets the digest length for extendable output functions.
The value should not exceed what can be given using a B<size_t>.
-It may be used by BLAKE2B-512, SHAKE-128 and SHAKE-256 to set the
+It may be used by SHAKE-128 and SHAKE-256 to set the
output length used by EVP_DigestFinal_ex() and EVP_DigestFinal().
+=item "size" (B<OSSL_DIGEST_PARAM_SIZE>) <unsigned integer>
+
+Sets or gets a fixed digest length.
+The value should not exceed what can be given using a B<size_t>.
+It may be used by BLAKE2B-512 to set the output length used by
+EVP_DigestFinal_ex() and EVP_DigestFinal().
+
+=back
+
+EVP_MD_CTX_set_params() can be used with the following OSSL_PARAM keys:
+
+=over 4
+
=item "pad-type" (B<OSSL_DIGEST_PARAM_PAD_TYPE>) <unsigned integer>
Sets the padding type.
This control sets the digest length for extendable output functions to I<p1>.
Sending this control directly should not be necessary, the use of
EVP_DigestFinalXOF() is preferred.
-Currently used by SHAKE.
+Currently used by SHAKE algorithms.
When used with a fetched B<EVP_MD>, EVP_MD_CTX_get_params() gets called with
an L<OSSL_PARAM(3)> item with the key "xoflen" (B<OSSL_DIGEST_PARAM_XOFLEN>).
The EVP_DigestSqueeze() function was added in OpenSSL 3.3.
+The EVP_MD_CTX_get_size_ex() and EVP_xof() functions were added in OpenSSL 3.4.
+The macros EVP_MD_CTX_get_size() and EVP_MD_CTX_size were changed in OpenSSL 3.4
+to be aliases for EVP_MD_CTX_get_size_ex(), previously they were aliases for
+EVP_MD_get_size which returned a constant value. This is required for XOF
+digests since they do not have a fixed size.
+
=head1 COPYRIGHT
Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
=head2 Settable Parameters
"BLAKE2B-512" supports the following EVP_MD_CTX_set_params() key
-described in L<EVP_DigestInit(3)/PARAMETERS>.
+described in L<EVP_DigestInit(3)/PARAMETERS>.
=over 4
-=item "xoflen" (B<OSSL_DIGEST_PARAM_XOFLEN>) <unsigned integer>
+=item "size" (B<OSSL_DIGEST_PARAM_SIZE>) <unsigned integer>
=back
=back
-=head2 Gettable Parameters
+=head2 Parameters
-This implementation supports the common gettable parameters described
-in L<EVP_MD-common(7)>.
-
-=head2 Settable Context Parameters
-
-These implementations support the following L<OSSL_PARAM(3)> entries,
-settable for an B<EVP_MD_CTX> with L<EVP_MD_CTX_set_params(3)>:
+This implementation supports the following L<OSSL_PARAM(3)> entries:
=over 4
=item "xoflen" (B<OSSL_DIGEST_PARAM_XOFLEN>) <unsigned integer>
-Sets the digest length for extendable output functions.
+Sets or Gets the digest length for extendable output functions.
The length of the "xoflen" parameter should not exceed that of a B<size_t>.
The SHAKE-128 and SHAKE-256 implementations do not have any default digest
length output. It is recommended to either use EVP_DigestSqueeze() or
EVP_DigestFinalXOF() instead.
+=item "size" (B<OSSL_DIGEST_PARAM_SIZE>) <unsigned integer>
+
+An alias of "xoflen".
+
=back
+See L<EVP_DigestInit(3)/PARAMETERS> for further information related to parameters
+
=head1 NOTES
For SHAKE-128, to ensure the maximum security strength of 128 bits, the output
=head1 SEE ALSO
-L<EVP_MD_get_params(3)>, L<provider-digest(7)>
+L<EVP_DigestInit(3)/PARAMETERS>, L<EVP_MD_get_params(3)>, L<provider-digest(7)>
=head1 COPYRIGHT
# define EVP_MD_block_size EVP_MD_get_block_size
unsigned long EVP_MD_get_flags(const EVP_MD *md);
# define EVP_MD_flags EVP_MD_get_flags
+int EVP_MD_xof(const EVP_MD *md);
const EVP_MD *EVP_MD_CTX_get0_md(const EVP_MD_CTX *ctx);
EVP_MD *EVP_MD_CTX_get1_md(EVP_MD_CTX *ctx);
int (*update) (EVP_MD_CTX *ctx,
const void *data, size_t count));
# endif
+int EVP_MD_CTX_get_size_ex(const EVP_MD_CTX *ctx);
+
# define EVP_MD_CTX_get0_name(e) EVP_MD_get0_name(EVP_MD_CTX_get0_md(e))
-# define EVP_MD_CTX_get_size(e) EVP_MD_get_size(EVP_MD_CTX_get0_md(e))
-# define EVP_MD_CTX_size EVP_MD_CTX_get_size
+# define EVP_MD_CTX_get_size(e) EVP_MD_CTX_get_size_ex(e)
+# define EVP_MD_CTX_size EVP_MD_CTX_get_size_ex
# define EVP_MD_CTX_get_block_size(e) EVP_MD_get_block_size(EVP_MD_CTX_get0_md(e))
# define EVP_MD_CTX_block_size EVP_MD_CTX_get_block_size
# define EVP_MD_CTX_get_type(e) EVP_MD_get_type(EVP_MD_CTX_get0_md(e))
static OSSL_FUNC_digest_freectx_fn keccak_freectx;
static OSSL_FUNC_digest_dupctx_fn keccak_dupctx;
static OSSL_FUNC_digest_squeeze_fn shake_squeeze;
+static OSSL_FUNC_digest_get_ctx_params_fn shake_get_ctx_params;
+static OSSL_FUNC_digest_gettable_ctx_params_fn shake_gettable_ctx_params;
static OSSL_FUNC_digest_set_ctx_params_fn shake_set_ctx_params;
static OSSL_FUNC_digest_settable_ctx_params_fn shake_settable_ctx_params;
static sha3_absorb_fn generic_sha3_absorb;
{ OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))shake_set_ctx_params }, \
{ OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS, \
(void (*)(void))shake_settable_ctx_params }, \
+ { OSSL_FUNC_DIGEST_GET_CTX_PARAMS, (void (*)(void))shake_get_ctx_params }, \
+ { OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))shake_gettable_ctx_params }, \
PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END
static void keccak_freectx(void *vctx)
return ret;
}
-static const OSSL_PARAM known_shake_settable_ctx_params[] = {
- {OSSL_DIGEST_PARAM_XOFLEN, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
- OSSL_PARAM_END
-};
+static const OSSL_PARAM *shake_gettable_ctx_params(ossl_unused void *ctx,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM known_shake_gettable_ctx_params[] = {
+ {OSSL_DIGEST_PARAM_XOFLEN, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
+ {OSSL_DIGEST_PARAM_SIZE, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
+ OSSL_PARAM_END
+ };
+ return known_shake_gettable_ctx_params;
+}
+
+static int shake_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+ KECCAK1600_CTX *ctx = (KECCAK1600_CTX *)vctx;
+
+ if (ctx == NULL)
+ return 0;
+ if (params == NULL)
+ return 1;
+
+ p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_XOFLEN);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->md_size)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ /* Size is an alias of xoflen */
+ p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->md_size)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ return 1;
+}
+
static const OSSL_PARAM *shake_settable_ctx_params(ossl_unused void *ctx,
ossl_unused void *provctx)
{
+ static const OSSL_PARAM known_shake_settable_ctx_params[] = {
+ {OSSL_DIGEST_PARAM_XOFLEN, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
+ {OSSL_DIGEST_PARAM_SIZE, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
+ OSSL_PARAM_END
+ };
+
return known_shake_settable_ctx_params;
}
return 1;
p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_XOFLEN);
+ if (p == NULL)
+ p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_SIZE);
+
if (p != NULL && !OSSL_PARAM_get_size_t(p, &ctx->md_size)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
SHAKE_newctx(shake, SHAKE_##bitlen, shake_##bitlen, bitlen, \
0 /* no default md length */, '\x1f') \
PROV_FUNC_SHAKE_DIGEST(shake_##bitlen, bitlen, \
- SHA3_BLOCKSIZE(bitlen), 0, \
- SHAKE_FLAGS)
+ SHA3_BLOCKSIZE(bitlen), 0, \
+ SHAKE_FLAGS)
#define IMPLEMENT_KMAC_functions(bitlen) \
KMAC_newctx(keccak_kmac_##bitlen, bitlen, '\x04') \
int ret = 0;
unsigned int digest_length = 0;
EVP_MD_CTX *ctx = NULL;
+ const EVP_MD *md;
unsigned char out[sizeof(shake256_output)];
OSSL_PARAM params[2];
size_t sz = 12;
if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
return 0;
+ md = EVP_MD_CTX_get0_md(ctx);
memset(out, 0, sizeof(out));
params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &sz);
params[1] = OSSL_PARAM_construct_end();
- if (!TEST_int_eq(EVP_MD_CTX_set_params(ctx, params), 1)
+ if (!TEST_int_eq(EVP_MD_CTX_size(ctx), -1)
+ || !TEST_int_eq(EVP_MD_CTX_set_params(ctx, params), 1)
+ || !TEST_int_eq(EVP_MD_CTX_size(ctx), sz)
+ || !TEST_int_eq(EVP_MD_get_size(md), 0)
+ || !TEST_true(EVP_MD_xof(md))
|| !TEST_true(EVP_DigestUpdate(ctx, shake256_input,
sizeof(shake256_input)))
|| !TEST_true(EVP_DigestFinal(ctx, out, &digest_length))
return ret;
}
+static int xof_fail_test(void)
+{
+ int ret;
+ EVP_MD *md = NULL;
+
+ ret = TEST_ptr(md = EVP_MD_fetch(NULL, "SHA256", NULL))
+ && TEST_false(EVP_MD_xof(md));
+ EVP_MD_free(md);
+ return ret;
+}
+
int setup_tests(void)
{
ADD_TEST(shake_kat_test);
ADD_ALL_TESTS(shake_squeeze_kat_test, OSSL_NELEM(stride_tests));
ADD_ALL_TESTS(shake_squeeze_large_test, OSSL_NELEM(stride_tests));
ADD_ALL_TESTS(shake_squeeze_dup_test, OSSL_NELEM(dupoffset_tests));
+ ADD_TEST(xof_fail_test);
return 1;
}