Skip to content

Commit 73cc972

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 support for WC_HASH_CUSTOM_MIN_DIGEST_SIZE, WC_HASH_CUSTOM_MAX_DIGEST_SIZE, and WC_HASH_CUSTOM_MAX_BLOCK_SIZE, for use with custom digest algorithms. * add SigOidMatchesKeyOid() helper function and WC_MIN_DIGEST_SIZE macro. * 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 73cc972

File tree

26 files changed

+574
-104
lines changed

26 files changed

+574
-104
lines changed

.wolfssl_known_macro_extras

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,9 @@ 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_MAX_BLOCK_SIZE
643+
WC_HASH_CUSTOM_MAX_DIGEST_SIZE
644+
WC_HASH_CUSTOM_MIN_DIGEST_SIZE
642645
WC_NO_ASYNC_SLEEP
643646
WC_NO_RNG_SIMPLE
644647
WC_NO_STATIC_ASSERT
@@ -651,9 +654,6 @@ WC_RSA_NONBLOCK
651654
WC_RSA_NONBLOCK_TIME
652655
WC_RSA_NO_FERMAT_CHECK
653656
WC_RWLOCK_OPS_INLINE
654-
WC_SHA384
655-
WC_SHA384_DIGEST_SIZE
656-
WC_SHA512
657657
WC_SKIP_INCLUDED_C_FILES
658658
WC_SSIZE_TYPE
659659
WC_STRICT_SIG

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 < WC_MIN_DIGEST_SIZE)) {
5727+
return BAD_LENGTH_E;
5728+
}
5729+
57235730
(void)ssl;
57245731
(void)keyBufInfo;
57255732

src/pk_ec.c

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

5267+
/* Check hash length */
5268+
if ((ret == 1) &&
5269+
((dLen > WC_MAX_DIGEST_SIZE) ||
5270+
(dLen < WC_MIN_DIGEST_SIZE))) {
5271+
WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad digest size");
5272+
ret = WOLFSSL_FATAL_ERROR;
5273+
}
5274+
52675275
/* Ensure internal EC key is set from external. */
52685276
if ((ret == 1) && (key->inSet == 0)) {
52695277
WOLFSSL_MSG("No EC key internal set, do it");
@@ -5388,6 +5396,14 @@ int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz,
53885396
ret = 0;
53895397
}
53905398

5399+
/* Check hash length */
5400+
if ((ret == 1) &&
5401+
((digestSz > WC_MAX_DIGEST_SIZE) ||
5402+
(digestSz < WC_MIN_DIGEST_SIZE))) {
5403+
WOLFSSL_MSG("wolfSSL_ECDSA_verify Bad digest size");
5404+
ret = 0;
5405+
}
5406+
53915407
/* Verify signature using digest and key. */
53925408
if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest,
53935409
(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: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,32 @@
3737
#define HEAP_HINT NULL
3838
#endif
3939

40+
#include <wolfssl/wolfcrypt/hash.h>
4041

41-
#define TEST_STRING "Everyone gets Friday off."
42-
#define TEST_STRING_SZ 25
43-
42+
#if defined(WC_FIPS_186_5_PLUS)
43+
#define TEST_STRING "WC_FIPS_186_5_PLUS test test"
44+
#define TEST_STRING_SZ 28
45+
#elif defined(WC_FIPS_186_4_PLUS) || defined(HAVE_SELFTEST)
46+
#define TEST_STRING "WC_FIPS_186_4_PLUS test.."
47+
#define TEST_STRING_SZ 25
48+
#elif WC_MIN_DIGEST_SIZE <= 25
49+
#define TEST_STRING "Everyone gets Friday off."
50+
#define TEST_STRING_SZ 25
51+
#elif WC_MIN_DIGEST_SIZE <= 28
52+
#define TEST_STRING "Everyone works the weekends."
53+
#define TEST_STRING_SZ 28
54+
#elif WC_MIN_DIGEST_SIZE <= 32
55+
#define TEST_STRING "Everyone works through the night"
56+
#define TEST_STRING_SZ 32
57+
#elif WC_MIN_DIGEST_SIZE <= 48
58+
#define TEST_STRING "Everyone gets to summer in Tuscany with Chianti."
59+
#define TEST_STRING_SZ 48
60+
#elif WC_MIN_DIGEST_SIZE <= 64
61+
#define TEST_STRING "Everyone works from Christmas Eve, clear through New Year's Day."
62+
#define TEST_STRING_SZ 64
63+
#else
64+
#error WC_MIN_DIGEST_SIZE value not supported by unit test.
65+
#endif
4466

4567
#ifndef ONEK_BUF
4668
#define ONEK_BUF 1024

tests/api/test_dsa.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ int test_wc_InitDsaKey(void)
6161
int test_wc_DsaSignVerify(void)
6262
{
6363
EXPECT_DECLS;
64-
#if !defined(NO_DSA)
64+
#if !defined(NO_DSA) && !defined(WC_FIPS_186_5_PLUS)
6565
DsaKey key;
6666
WC_RNG rng;
6767
wc_Sha sha;
@@ -130,7 +130,8 @@ int test_wc_DsaSignVerify(void)
130130
DoExpectIntEQ(wc_FreeRng(&rng),0);
131131
wc_FreeDsaKey(&key);
132132
wc_ShaFree(&sha);
133-
#endif
133+
#endif /* !NO_DSA && !WC_FIPS_186_5_PLUS */
134+
134135
return EXPECT_RESULT();
135136
} /* END test_wc_DsaSign */
136137

tests/api/test_evp_pkey.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ int test_wolfSSL_EVP_PKEY_set1_get1_DSA(void)
742742
{
743743
EXPECT_DECLS;
744744
#if defined(OPENSSL_ALL) && !defined (NO_DSA) && !defined(HAVE_SELFTEST) && \
745-
defined(WOLFSSL_KEY_GEN)
745+
!defined(WC_FIPS_186_5_PLUS) && defined(WOLFSSL_KEY_GEN)
746746
DSA *dsa = NULL;
747747
DSA *setDsa = NULL;
748748
EVP_PKEY *pkey = NULL;
@@ -829,7 +829,8 @@ int test_wolfSSL_EVP_PKEY_set1_get1_DSA(void)
829829
DSA_free(setDsa);
830830
EVP_PKEY_free(pkey);
831831
EVP_PKEY_free(set1Pkey);
832-
#endif /* OPENSSL_ALL && !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */
832+
#endif /* OPENSSL_ALL && !NO_DSA && !HAVE_SELFTEST && !WC_FIPS_186_5_PLUS */
833+
/* && WOLFSSL_KEY_GEN */
833834
return EXPECT_RESULT();
834835
} /* END test_EVP_PKEY_set1_get1_DSA */
835836

@@ -1606,7 +1607,8 @@ int test_wolfSSL_EVP_PKEY_sign_verify_dsa(void)
16061607
{
16071608
EXPECT_DECLS;
16081609
#if defined(OPENSSL_EXTRA)
1609-
#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN)
1610+
#if !defined (NO_DSA) && !defined(WC_FIPS_186_5_PLUS) && \
1611+
!defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN)
16101612
ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_DSA), TEST_SUCCESS);
16111613
#endif
16121614
#endif

wolfcrypt/src/asn.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16109,6 +16109,118 @@ 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+
switch (sigOID) {
16121+
case CTC_MD2wRSA:
16122+
case CTC_MD5wRSA:
16123+
case CTC_SHAwRSA:
16124+
case CTC_SHA224wRSA:
16125+
case CTC_SHA256wRSA:
16126+
case CTC_SHA384wRSA:
16127+
case CTC_SHA512wRSA:
16128+
case CTC_SHA3_224wRSA:
16129+
case CTC_SHA3_256wRSA:
16130+
case CTC_SHA3_384wRSA:
16131+
case CTC_SHA3_512wRSA:
16132+
case CTC_RSASSAPSS:
16133+
return 1;
16134+
}
16135+
return 0;
16136+
#ifdef WC_RSA_PSS
16137+
case RSAPSSk:
16138+
return (sigOID == CTC_RSASSAPSS);
16139+
#endif
16140+
#endif
16141+
#if !defined(NO_DSA) && !defined(HAVE_SELFTEST)
16142+
case DSAk:
16143+
switch (sigOID) {
16144+
case CTC_SHAwDSA:
16145+
case CTC_SHA256wDSA:
16146+
return 1;
16147+
}
16148+
return 0;
16149+
#endif
16150+
#if defined(HAVE_ECC) && defined(HAVE_ECC_VERIFY)
16151+
case ECDSAk:
16152+
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
16153+
case SM2k:
16154+
#endif
16155+
switch (sigOID) {
16156+
case CTC_SHAwECDSA:
16157+
case CTC_SHA224wECDSA:
16158+
case CTC_SHA256wECDSA:
16159+
case CTC_SHA384wECDSA:
16160+
case CTC_SHA512wECDSA:
16161+
case CTC_SHA3_224wECDSA:
16162+
case CTC_SHA3_256wECDSA:
16163+
case CTC_SHA3_384wECDSA:
16164+
case CTC_SHA3_512wECDSA:
16165+
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
16166+
case CTC_SM3wSM2:
16167+
#endif
16168+
return 1;
16169+
}
16170+
return 0;
16171+
#endif
16172+
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
16173+
case ED25519k:
16174+
return (sigOID == CTC_ED25519);
16175+
#endif
16176+
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
16177+
case ED448k:
16178+
return (sigOID == CTC_ED448);
16179+
#endif
16180+
#if defined(HAVE_FALCON)
16181+
case FALCON_LEVEL1k:
16182+
return (sigOID == CTC_FALCON_LEVEL1);
16183+
case FALCON_LEVEL5k:
16184+
return (sigOID == CTC_FALCON_LEVEL5);
16185+
#endif
16186+
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
16187+
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
16188+
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
16189+
case DILITHIUM_LEVEL2k:
16190+
return (sigOID == CTC_DILITHIUM_LEVEL2);
16191+
case DILITHIUM_LEVEL3k:
16192+
return (sigOID == CTC_DILITHIUM_LEVEL3);
16193+
case DILITHIUM_LEVEL5k:
16194+
return (sigOID == CTC_DILITHIUM_LEVEL5);
16195+
#endif
16196+
case ML_DSA_LEVEL2k:
16197+
return (sigOID == CTC_ML_DSA_LEVEL2);
16198+
case ML_DSA_LEVEL3k:
16199+
return (sigOID == CTC_ML_DSA_LEVEL3);
16200+
case ML_DSA_LEVEL5k:
16201+
return (sigOID == CTC_ML_DSA_LEVEL5);
16202+
#endif
16203+
#if defined(HAVE_SPHINCS)
16204+
case SPHINCS_FAST_LEVEL1k:
16205+
return (sigOID == CTC_SPHINCS_FAST_LEVEL1);
16206+
case SPHINCS_FAST_LEVEL3k:
16207+
return (sigOID == CTC_SPHINCS_FAST_LEVEL3);
16208+
case SPHINCS_FAST_LEVEL5k:
16209+
return (sigOID == CTC_SPHINCS_FAST_LEVEL5);
16210+
case SPHINCS_SMALL_LEVEL1k:
16211+
return (sigOID == CTC_SPHINCS_SMALL_LEVEL1);
16212+
case SPHINCS_SMALL_LEVEL3k:
16213+
return (sigOID == CTC_SPHINCS_SMALL_LEVEL3);
16214+
case SPHINCS_SMALL_LEVEL5k:
16215+
return (sigOID == CTC_SPHINCS_SMALL_LEVEL5);
16216+
#endif
16217+
}
16218+
16219+
/* Default to reject unknown key types */
16220+
(void)sigOID;
16221+
return 0;
16222+
}
16223+
1611216224
/* Return codes: 0=Success, Negative (see error-crypt.h), ASN_SIG_CONFIRM_E */
1611316225
int ConfirmSignature(SignatureCtx* sigCtx,
1611416226
const byte* buf, word32 bufSz,
@@ -16177,6 +16289,11 @@ int ConfirmSignature(SignatureCtx* sigCtx,
1617716289

1617816290
case SIG_STATE_HASH:
1617916291
{
16292+
if (!SigOidMatchesKeyOid(sigOID, keyOID)) {
16293+
WOLFSSL_MSG("sigOID incompatible with issuer keyOID");
16294+
ERROR_OUT(ASN_SIG_OID_E, exit_cs);
16295+
}
16296+
1618016297
#if !defined(NO_RSA) && defined(WC_RSA_PSS)
1618116298
if (sigOID == RSAPSSk) {
1618216299
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 < WC_MIN_DIGEST_SIZE))
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_MIN_DIGEST_SIZE, 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);

0 commit comments

Comments
 (0)