From 2c181ac5a6fff474bc26bfa93f0c717eebc1ab1b Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 28 Apr 2021 18:40:37 +0200 Subject: sm2: Cleanup handling of DIGEST and DIGEST_SIZE parameters Fixes #14873 Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/15074) --- providers/implementations/signature/sm2sig.c | 90 +++++++++++++++------------- 1 file changed, 47 insertions(+), 43 deletions(-) (limited to 'providers') diff --git a/providers/implementations/signature/sm2sig.c b/providers/implementations/signature/sm2sig.c index 9016aefc02..8607a8b911 100644 --- a/providers/implementations/signature/sm2sig.c +++ b/providers/implementations/signature/sm2sig.c @@ -25,6 +25,7 @@ #include "internal/nelem.h" #include "internal/sizes.h" #include "internal/cryptlib.h" +#include "internal/sm3.h" #include "prov/implementations.h" #include "prov/provider_ctx.h" #include "crypto/ec.h" @@ -63,13 +64,6 @@ typedef struct { char *propq; EC_KEY *ec; - /* - * Flag to determine if the hash function can be changed (1) or not (0) - * Because it's dangerous to change during a DigestSign or DigestVerify - * operation, this flag is cleared by their Init function, and set again - * by their Final function. - */ - unsigned int flag_allow_md : 1; /* * Flag to termine if the 'z' digest needs to be computed and fed to the * hash function. @@ -95,6 +89,21 @@ typedef struct { size_t id_len; } PROV_SM2_CTX; +static int sm2sig_set_mdname(PROV_SM2_CTX *psm2ctx, const char *mdname) +{ + if (psm2ctx->md == NULL) /* We need an SM3 md to compare with */ + psm2ctx->md = EVP_MD_fetch(psm2ctx->libctx, psm2ctx->mdname, + psm2ctx->propq); + if (psm2ctx->md == NULL + || strlen(mdname) >= sizeof(psm2ctx->mdname) + || !EVP_MD_is_a(psm2ctx->md, mdname)) { + return 0; + } + + OPENSSL_strlcpy(psm2ctx->mdname, mdname, sizeof(psm2ctx->mdname)); + return 1; +} + static void *sm2sig_newctx(void *provctx, const char *propq) { PROV_SM2_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_SM2_CTX)); @@ -108,8 +117,8 @@ static void *sm2sig_newctx(void *provctx, const char *propq) ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return NULL; } - /* don't allow to change MD, and in fact there is no such need */ - ctx->flag_allow_md = 0; + ctx->mdsize = SM3_DIGEST_LENGTH; + strcpy(ctx->mdname, OSSL_DIGEST_NAME_SM3); return ctx; } @@ -170,28 +179,27 @@ static void free_md(PROV_SM2_CTX *ctx) EVP_MD_free(ctx->md); ctx->mdctx = NULL; ctx->md = NULL; - ctx->mdsize = 0; } static int sm2sig_digest_signverify_init(void *vpsm2ctx, const char *mdname, void *ec, const OSSL_PARAM params[]) { PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; - int md_nid = NID_sm3; + int md_nid; WPACKET pkt; int ret = 0; - free_md(ctx); - - if (!sm2sig_signature_init(vpsm2ctx, ec, params)) + if (!sm2sig_signature_init(vpsm2ctx, ec, params) + || !sm2sig_set_mdname(ctx, mdname)) return ret; - ctx->md = EVP_MD_fetch(ctx->libctx, mdname, ctx->propq); - ctx->mdsize = EVP_MD_size(ctx->md); + EVP_MD_CTX_free(ctx->mdctx); ctx->mdctx = EVP_MD_CTX_new(); if (ctx->mdctx == NULL) goto error; + md_nid = EVP_MD_type(ctx->md); + /* * We do not care about DER writing errors. * All it really means is that for some reason, there's no @@ -285,10 +293,11 @@ int sm2sig_digest_verify_final(void *vpsm2ctx, const unsigned char *sig, unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int dlen = 0; - if (psm2ctx == NULL || psm2ctx->mdctx == NULL) + if (psm2ctx == NULL + || psm2ctx->mdctx == NULL + || EVP_MD_size(psm2ctx->md) > (int)sizeof(digest)) return 0; - /* SM2 always use SM3 so it's not possible to exceed the limit */ if (!(sm2sig_compute_z_digest(psm2ctx) && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen))) return 0; @@ -392,7 +401,7 @@ static int sm2sig_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) { PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; const OSSL_PARAM *p; - char *mdname; + size_t mdsize; if (psm2ctx == NULL) return 0; @@ -417,28 +426,29 @@ static int sm2sig_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) psm2ctx->id_len = tmp_idlen; } - if (psm2ctx->md != NULL) { - /* - * You cannot set the digest name/size when doing a DigestSign or - * DigestVerify. - */ - return 1; - } - + /* + * The following code checks that the size is the same as the SM3 digest + * size returning an error otherwise. + * If there is ever any different digest algorithm allowed with SM2 + * this needs to be adjusted accordingly. + */ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); - if (p != NULL && !OSSL_PARAM_get_size_t(p, &psm2ctx->mdsize)) + if (p != NULL && (!OSSL_PARAM_get_size_t(p, &mdsize) + || mdsize != psm2ctx->mdsize)) return 0; - /* - * We never actually use the mdname, but we do support getting it later. - * This can be useful for applications that want to know the MD that they - * previously set. - */ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); - mdname = psm2ctx->mdname; - if (p != NULL - && !OSSL_PARAM_get_utf8_string(p, &mdname, sizeof(psm2ctx->mdname))) - return 0; + if (p != NULL) { + char *mdname = NULL; + + if (!OSSL_PARAM_get_utf8_string(p, &mdname, 0)) + return 0; + if (!sm2sig_set_mdname(psm2ctx, mdname)) { + OPENSSL_free(mdname); + return 0; + } + OPENSSL_free(mdname); + } return 1; } @@ -453,12 +463,6 @@ static const OSSL_PARAM known_settable_ctx_params[] = { static const OSSL_PARAM *sm2sig_settable_ctx_params(ossl_unused void *vpsm2ctx, ossl_unused void *provctx) { - /* - * TODO(3.0): Should this function return a different set of settable ctx - * params if the ctx is being used for a DigestSign/DigestVerify? In that - * case it is not allowed to set the digest size/digest name because the - * digest is explicitly set as part of the init. - */ return known_settable_ctx_params; } -- cgit v1.2.3