Skip to content

Commit 1873acb

Browse files
douzzerFrauschi
andcommitted
wolfcrypt: add additional enforcement of correct digest sizes in signature gen and verify ops:
* add WC_FIPS_186_4, WC_FIPS_186_4_PLUS, WC_FIPS_186_5, and WC_FIPS_186_5_PLUS feature macros. * add WC_HASH_CUSTOM_MIN_DIGEST_SIZE for use with custom digest algorithms. * add SigOidMatchesKeyOid() and wc_HashGetMinDigestSize() helper functions, the latter an API. * add additional size and OID agreement checks for sig gen and verify ops. * update ecc_test_vector() with FIPS 186-5 vectors. Co-authored-by: Tobias Frauenschläger <tobias@wolfssl.com>
1 parent 0c9b639 commit 1873acb

File tree

18 files changed

+506
-15
lines changed

18 files changed

+506
-15
lines changed

.wolfssl_known_macro_extras

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ WC_DILITHIUM_FIXED_ARRAY
639639
WC_DISABLE_RADIX_ZERO_PAD
640640
WC_FLAG_DONT_USE_AESNI
641641
WC_FORCE_LINUXKM_FORTIFY_SOURCE
642+
WC_HASH_CUSTOM_MIN_DIGEST_SIZE
642643
WC_NO_ASYNC_SLEEP
643644
WC_NO_RNG_SIMPLE
644645
WC_NO_STATIC_ASSERT

doc/dox_comments/header_files/hash.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ int wc_HashGetOID(enum wc_HashType hash_type);
5252
*/
5353
int wc_HashGetDigestSize(enum wc_HashType hash_type);
5454

55+
/*!
56+
\ingroup wolfCrypt
57+
58+
\brief This function returns the minimum size supported for any digest
59+
enabled in the library. In FIPS builds, the value is subject to floor
60+
values controlled by FIPS 186-4 or 186-5 as appropriate.
61+
62+
\return A positive return value, the smallest supported digest size.
63+
64+
_Example_
65+
\code
66+
int min_hash_len = wc_HashGetMinDigestSize();
67+
if (supplied_hash_len < min_hash_len) {
68+
WOLFSSL_MSG("Invalid hash len");
69+
return BAD_FUNC_ARG;
70+
}
71+
\endcode
72+
73+
\sa wc_Hash
74+
*/
75+
int wc_HashGetMinDigestSize(void);
76+
5577
/*!
5678
\ingroup wolfCrypt
5779

src/internal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
#include <wolfssl/error-ssl.h>
158158
#include <wolfssl/wolfcrypt/asn.h>
159159
#include <wolfssl/wolfcrypt/dh.h>
160+
#include <wolfssl/wolfcrypt/hash.h>
160161
#ifdef NO_INLINE
161162
#include <wolfssl/wolfcrypt/misc.h>
162163
#else
@@ -5720,6 +5721,12 @@ int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* out,
57205721
}
57215722
#endif
57225723

5724+
/* Check hash length */
5725+
if ((outSz > WC_MAX_DIGEST_SIZE) ||
5726+
(outSz < (word32)wc_HashGetMinDigestSize())) {
5727+
return BAD_LENGTH_E;
5728+
}
5729+
57235730
(void)ssl;
57245731
(void)keyBufInfo;
57255732

src/pk_ec.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5264,6 +5264,13 @@ int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen,
52645264
ret = WOLFSSL_FATAL_ERROR;
52655265
}
52665266

5267+
/* Check hash length */
5268+
if ((dLen > WC_MAX_DIGEST_SIZE) ||
5269+
(dLen < wc_HashGetMinDigestSize())) {
5270+
WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad digest size");
5271+
ret = WOLFSSL_FATAL_ERROR;
5272+
}
5273+
52675274
/* Ensure internal EC key is set from external. */
52685275
if ((ret == 1) && (key->inSet == 0)) {
52695276
WOLFSSL_MSG("No EC key internal set, do it");
@@ -5388,6 +5395,13 @@ int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz,
53885395
ret = 0;
53895396
}
53905397

5398+
/* Check hash length */
5399+
if ((digestSz > WC_MAX_DIGEST_SIZE) ||
5400+
(digestSz < wc_HashGetMinDigestSize())) {
5401+
WOLFSSL_MSG("wolfSSL_ECDSA_verify Bad digest size");
5402+
ret = 0;
5403+
}
5404+
53915405
/* Verify signature using digest and key. */
53925406
if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest,
53935407
(word32)digestSz, &verify, (ecc_key*)key->internal) != 0)) {

tests/api.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12284,9 +12284,9 @@ static int test_wc_CheckCertSigPubKey(void)
1228412284
ExpectIntEQ(wc_CheckCertSigPubKey(cert_der, cert_dersz, NULL, keyDer, 0,
1228512285
RSAk), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
1228612286

12287-
/* Wrong aglo. */
12287+
/* Wrong algo. */
1228812288
ExpectIntEQ(wc_CheckCertSigPubKey(cert_der, cert_dersz, NULL, keyDer,
12289-
keyDerSz, ECDSAk), WC_NO_ERR_TRACE(ASN_PARSE_E));
12289+
keyDerSz, ECDSAk), WC_NO_ERR_TRACE(ASN_SIG_OID_E));
1229012290

1229112291
wc_FreeDecodedCert(&decoded);
1229212292
if (cert_der != NULL)

tests/api/api.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,13 @@
3838
#endif
3939

4040

41-
#define TEST_STRING "Everyone gets Friday off."
42-
#define TEST_STRING_SZ 25
41+
#ifdef WC_FIPS_186_5_PLUS
42+
#define TEST_STRING "Everyone works the weekends."
43+
#define TEST_STRING_SZ 28
44+
#else
45+
#define TEST_STRING "Everyone gets Friday off."
46+
#define TEST_STRING_SZ 25
47+
#endif
4348

4449

4550
#ifndef ONEK_BUF

wolfcrypt/src/asn.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16109,6 +16109,116 @@ static int DecodeDsaAsn1Sig(const byte* sig, word32 sigSz, byte* sigCpy,
1610916109
}
1611016110
#endif
1611116111

16112+
/* The certificate's signatureAlgorithm (sigOID) must match the issuer's
16113+
* key type (keyOID). sigOID picks the pre-hash; keyOID picks the
16114+
* verifier. They need to agree or the verifier gets the wrong input. */
16115+
static int SigOidMatchesKeyOid(word32 sigOID, word32 keyOID)
16116+
{
16117+
switch (keyOID) {
16118+
#ifndef NO_RSA
16119+
case RSAk:
16120+
#ifdef WC_RSA_PSS
16121+
case RSAPSSk:
16122+
#endif
16123+
switch (sigOID) {
16124+
case CTC_MD2wRSA:
16125+
case CTC_MD5wRSA:
16126+
case CTC_SHAwRSA:
16127+
case CTC_SHA224wRSA:
16128+
case CTC_SHA256wRSA:
16129+
case CTC_SHA384wRSA:
16130+
case CTC_SHA512wRSA:
16131+
case CTC_SHA3_224wRSA:
16132+
case CTC_SHA3_256wRSA:
16133+
case CTC_SHA3_384wRSA:
16134+
case CTC_SHA3_512wRSA:
16135+
case CTC_RSASSAPSS:
16136+
return 1;
16137+
}
16138+
return 0;
16139+
#endif
16140+
#if !defined(NO_DSA) && !defined(HAVE_SELFTEST)
16141+
case DSAk:
16142+
switch (sigOID) {
16143+
case CTC_SHAwDSA:
16144+
case CTC_SHA256wDSA:
16145+
return 1;
16146+
}
16147+
return 0;
16148+
#endif
16149+
#if defined(HAVE_ECC) && defined(HAVE_ECC_VERIFY)
16150+
case ECDSAk:
16151+
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
16152+
case SM2k:
16153+
#endif
16154+
switch (sigOID) {
16155+
case CTC_SHAwECDSA:
16156+
case CTC_SHA224wECDSA:
16157+
case CTC_SHA256wECDSA:
16158+
case CTC_SHA384wECDSA:
16159+
case CTC_SHA512wECDSA:
16160+
case CTC_SHA3_224wECDSA:
16161+
case CTC_SHA3_256wECDSA:
16162+
case CTC_SHA3_384wECDSA:
16163+
case CTC_SHA3_512wECDSA:
16164+
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
16165+
case CTC_SM3wSM2:
16166+
#endif
16167+
return 1;
16168+
}
16169+
return 0;
16170+
#endif
16171+
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
16172+
case ED25519k:
16173+
return (sigOID == CTC_ED25519);
16174+
#endif
16175+
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
16176+
case ED448k:
16177+
return (sigOID == CTC_ED448);
16178+
#endif
16179+
#if defined(HAVE_FALCON)
16180+
case FALCON_LEVEL1k:
16181+
return (sigOID == CTC_FALCON_LEVEL1);
16182+
case FALCON_LEVEL5k:
16183+
return (sigOID == CTC_FALCON_LEVEL5);
16184+
#endif
16185+
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
16186+
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
16187+
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
16188+
case DILITHIUM_LEVEL2k:
16189+
return (sigOID == CTC_DILITHIUM_LEVEL2);
16190+
case DILITHIUM_LEVEL3k:
16191+
return (sigOID == CTC_DILITHIUM_LEVEL3);
16192+
case DILITHIUM_LEVEL5k:
16193+
return (sigOID == CTC_DILITHIUM_LEVEL5);
16194+
#endif
16195+
case ML_DSA_LEVEL2k:
16196+
return (sigOID == CTC_ML_DSA_LEVEL2);
16197+
case ML_DSA_LEVEL3k:
16198+
return (sigOID == CTC_ML_DSA_LEVEL3);
16199+
case ML_DSA_LEVEL5k:
16200+
return (sigOID == CTC_ML_DSA_LEVEL5);
16201+
#endif
16202+
#if defined(HAVE_SPHINCS)
16203+
case SPHINCS_FAST_LEVEL1k:
16204+
return (sigOID == CTC_SPHINCS_FAST_LEVEL1);
16205+
case SPHINCS_FAST_LEVEL3k:
16206+
return (sigOID == CTC_SPHINCS_FAST_LEVEL3);
16207+
case SPHINCS_FAST_LEVEL5k:
16208+
return (sigOID == CTC_SPHINCS_FAST_LEVEL5);
16209+
case SPHINCS_SMALL_LEVEL1k:
16210+
return (sigOID == CTC_SPHINCS_SMALL_LEVEL1);
16211+
case SPHINCS_SMALL_LEVEL3k:
16212+
return (sigOID == CTC_SPHINCS_SMALL_LEVEL3);
16213+
case SPHINCS_SMALL_LEVEL5k:
16214+
return (sigOID == CTC_SPHINCS_SMALL_LEVEL5);
16215+
#endif
16216+
}
16217+
16218+
/* Default to reject unknown key types */
16219+
return 0;
16220+
}
16221+
1611216222
/* Return codes: 0=Success, Negative (see error-crypt.h), ASN_SIG_CONFIRM_E */
1611316223
int ConfirmSignature(SignatureCtx* sigCtx,
1611416224
const byte* buf, word32 bufSz,
@@ -16177,6 +16287,11 @@ int ConfirmSignature(SignatureCtx* sigCtx,
1617716287

1617816288
case SIG_STATE_HASH:
1617916289
{
16290+
if (!SigOidMatchesKeyOid(sigOID, keyOID)) {
16291+
WOLFSSL_MSG("sigOID incompatible with issuer keyOID");
16292+
ERROR_OUT(ASN_SIG_OID_E, exit_cs);
16293+
}
16294+
1618016295
#if !defined(NO_RSA) && defined(WC_RSA_PSS)
1618116296
if (sigOID == RSAPSSk) {
1618216297
word32 fakeSigOID = 0;

wolfcrypt/src/dilithium.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9273,8 +9273,9 @@ static int dilithium_sign_ctx_hash_with_seed(dilithium_key* key,
92739273
byte oidMsgHash[DILITHIUM_HASH_OID_LEN + WC_MAX_DIGEST_SIZE];
92749274
word32 oidMsgHashLen = 0;
92759275

9276-
if ((ret == 0) && (hashLen > WC_MAX_DIGEST_SIZE)) {
9277-
ret = BUFFER_E;
9276+
/* Check that the input hash length is valid. */
9277+
if ((int)hashLen != wc_HashGetDigestSize((enum wc_HashType)hashAlg)) {
9278+
ret = BAD_LENGTH_E;
92789279
}
92799280

92809281
if (ret == 0) {
@@ -9944,6 +9945,12 @@ static int dilithium_verify_ctx_hash(dilithium_key* key, const byte* ctx,
99449945
if (key == NULL) {
99459946
ret = BAD_FUNC_ARG;
99469947
}
9948+
/* Check that the input hash length is valid. */
9949+
if ((ret == 0) &&
9950+
((int)hashLen != wc_HashGetDigestSize((enum wc_HashType)hashAlg)))
9951+
{
9952+
ret = BAD_LENGTH_E;
9953+
}
99479954

99489955
if (ret == 0) {
99499956
/* Step 6: Hash public key. */

wolfcrypt/src/dsa.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <wolfssl/wolfcrypt/wolfmath.h>
2828
#include <wolfssl/wolfcrypt/sha.h>
2929
#include <wolfssl/wolfcrypt/dsa.h>
30+
#include <wolfssl/wolfcrypt/hash.h>
3031

3132
#ifdef NO_INLINE
3233
#include <wolfssl/wolfcrypt/misc.h>
@@ -689,6 +690,12 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key,
689690
if (digest == NULL || out == NULL || key == NULL || rng == NULL)
690691
return BAD_FUNC_ARG;
691692

693+
if ((digestSz > WC_MAX_DIGEST_SIZE) ||
694+
(digestSz < (word32)wc_HashGetMinDigestSize()))
695+
{
696+
return BAD_LENGTH_E;
697+
}
698+
692699
SAVE_VECTOR_REGISTERS(return _svr_ret;);
693700

694701
do {
@@ -1022,6 +1029,16 @@ int wc_DsaVerify_ex(const byte* digest, word32 digestSz, const byte* sig,
10221029
if (digest == NULL || sig == NULL || key == NULL || answer == NULL)
10231030
return BAD_FUNC_ARG;
10241031

1032+
/* Note the min allowed digestSz here is WC_SHA_DIGEST_SIZE, not
1033+
* wc_HashGetMinDigestSize(), to allow verify-only legacy DSA operations, as
1034+
* expressly allowed under FIPS 186-5, FIPS 140-3, and SP 800-131A.
1035+
*/
1036+
if ((digestSz > WC_MAX_DIGEST_SIZE) ||
1037+
(digestSz < WC_SHA_DIGEST_SIZE))
1038+
{
1039+
return BAD_LENGTH_E;
1040+
}
1041+
10251042
do {
10261043
#ifdef WOLFSSL_SMALL_STACK
10271044
w = (mp_int *)XMALLOC(sizeof *w, key->heap, DYNAMIC_TYPE_TMP_BUFFER);

wolfcrypt/src/ecc.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ ECC Curve Sizes:
213213

214214
#include <wolfssl/wolfcrypt/ecc.h>
215215
#include <wolfssl/wolfcrypt/asn.h>
216+
#include <wolfssl/wolfcrypt/hash.h>
216217

217218
#ifdef WOLFSSL_HAVE_SP_ECC
218219
#include <wolfssl/wolfcrypt/sp.h>
@@ -223,10 +224,6 @@ ECC Curve Sizes:
223224
#include <wolfssl/wolfcrypt/aes.h>
224225
#endif
225226

226-
#ifdef HAVE_X963_KDF
227-
#include <wolfssl/wolfcrypt/hash.h>
228-
#endif
229-
230227
#ifdef WOLF_CRYPTO_CB
231228
#include <wolfssl/wolfcrypt/cryptocb.h>
232229
#endif
@@ -6778,7 +6775,9 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
67786775
if (in == NULL || out == NULL || outlen == NULL || key == NULL) {
67796776
return ECC_BAD_ARG_E;
67806777
}
6781-
if (inlen > WC_MAX_DIGEST_SIZE) {
6778+
if ((inlen > WC_MAX_DIGEST_SIZE) ||
6779+
(inlen < (word32)wc_HashGetMinDigestSize()))
6780+
{
67826781
return BAD_LENGTH_E;
67836782
}
67846783

@@ -7299,6 +7298,11 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
72997298
if (in == NULL || r == NULL || s == NULL || key == NULL || rng == NULL) {
73007299
return ECC_BAD_ARG_E;
73017300
}
7301+
if ((inlen > WC_MAX_DIGEST_SIZE) ||
7302+
(inlen < (word32)wc_HashGetMinDigestSize()))
7303+
{
7304+
return BAD_LENGTH_E;
7305+
}
73027306

73037307
/* is this a private key? */
73047308
if (key->type != ECC_PRIVATEKEY && key->type != ECC_PRIVATEKEY_ONLY) {
@@ -8576,7 +8580,10 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash,
85768580
if (sig == NULL || hash == NULL || res == NULL || key == NULL) {
85778581
return ECC_BAD_ARG_E;
85788582
}
8579-
if (hashlen > WC_MAX_DIGEST_SIZE) {
8583+
8584+
/* Check hash length */
8585+
if ((hashlen > WC_MAX_DIGEST_SIZE) ||
8586+
(hashlen < (word32)wc_HashGetMinDigestSize())) {
85808587
return BAD_LENGTH_E;
85818588
}
85828589

@@ -9284,6 +9291,12 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
92849291
if (r == NULL || s == NULL || hash == NULL || res == NULL || key == NULL)
92859292
return ECC_BAD_ARG_E;
92869293

9294+
/* Check hash length */
9295+
if ((hashlen > WC_MAX_DIGEST_SIZE) ||
9296+
(hashlen < (word32)wc_HashGetMinDigestSize())) {
9297+
return BAD_LENGTH_E;
9298+
}
9299+
92879300
/* default to invalid signature */
92889301
*res = 0;
92899302

0 commit comments

Comments
 (0)