Skip to content

Commit d634253

Browse files
ColtonWilleypadelsbach
authored andcommitted
Add digest size checks for ECC sign/verify
1 parent a8af207 commit d634253

4 files changed

Lines changed: 161 additions & 12 deletions

File tree

src/wp_ecdsa_sig.c

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
#ifdef WP_HAVE_ECDSA
3434

35+
/* SHA-1 digest size; literal because WC_SHA_DIGEST_SIZE is !NO_SHA-gated. */
36+
#define WP_ECDSA_MIN_HASH_LEN 20
37+
3538
/**
3639
* ECDSA signature context.
3740
*
@@ -271,14 +274,20 @@ static int wp_ecdsa_sign(wp_EcdsaSigCtx *ctx, unsigned char *sig,
271274
*sigLen = wc_ecc_sig_size(wp_ecc_get_key(ctx->ecc));
272275
}
273276
else {
277+
/* Enforce digest-size invariants the FIPS-validated
278+
* wc_ecc_sign_hash boundary cannot. */
274279
#if LIBWOLFSSL_VERSION_HEX >= 0x05007004
275-
if ((ctx->hash.type != WC_HASH_TYPE_NONE) &&
276-
(tbsLen != (size_t)wc_HashGetDigestSize(ctx->hash.type)))
280+
enum wc_HashType hashType = ctx->hash.type;
277281
#else
278-
if ((ctx->hashType != WC_HASH_TYPE_NONE) &&
279-
(tbsLen != (size_t)wc_HashGetDigestSize(ctx->hashType)))
282+
enum wc_HashType hashType = ctx->hashType;
280283
#endif
281-
{
284+
int digestSize = wc_HashGetDigestSize(hashType);
285+
if ((hashType != WC_HASH_TYPE_NONE) &&
286+
((digestSize < 0) || (tbsLen != (size_t)digestSize))) {
287+
ok = 0;
288+
}
289+
else if ((hashType == WC_HASH_TYPE_NONE) &&
290+
(tbsLen < WP_ECDSA_MIN_HASH_LEN)) {
282291
ok = 0;
283292
}
284293
else if ((ok = wp_ecc_check_usage(ctx->ecc))) {
@@ -362,17 +371,35 @@ static int wp_ecdsa_verify(wp_EcdsaSigCtx *ctx, const unsigned char *sig,
362371
ok = 0;
363372
}
364373
else {
365-
int res;
366-
int rc = wc_ecc_verify_hash(sig, (word32)sigLen, tbs, (word32)tbsLen,
367-
&res, wp_ecc_get_key(ctx->ecc));
368-
if (rc != 0) {
369-
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_ecc_verify_hash", rc);
374+
/* Enforce digest-size invariants the FIPS-validated
375+
* wc_ecc_verify_hash boundary cannot. */
376+
#if LIBWOLFSSL_VERSION_HEX >= 0x05007004
377+
enum wc_HashType hashType = ctx->hash.type;
378+
#else
379+
enum wc_HashType hashType = ctx->hashType;
380+
#endif
381+
int digestSize = wc_HashGetDigestSize(hashType);
382+
if ((hashType != WC_HASH_TYPE_NONE) &&
383+
((digestSize < 0) || (tbsLen != (size_t)digestSize))) {
370384
ok = 0;
371385
}
372-
if (res == 0) {
373-
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "Signature verification", rc);
386+
else if ((hashType == WC_HASH_TYPE_NONE) &&
387+
(tbsLen < WP_ECDSA_MIN_HASH_LEN)) {
374388
ok = 0;
375389
}
390+
else {
391+
int res;
392+
int rc = wc_ecc_verify_hash(sig, (word32)sigLen, tbs, (word32)tbsLen,
393+
&res, wp_ecc_get_key(ctx->ecc));
394+
if (rc != 0) {
395+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_ecc_verify_hash", rc);
396+
ok = 0;
397+
}
398+
else if (res == 0) {
399+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "Signature verification", rc);
400+
ok = 0;
401+
}
402+
}
376403
}
377404

378405
WOLFPROV_LEAVE(WP_LOG_COMP_ECDSA, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);

test/test_ecc.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,36 @@ static int test_pkey_verify_ecc(EVP_PKEY *pkey, OSSL_LIB_CTX* libCtx,
990990
return test_pkey_verify(pkey, libCtx, hash, hashLen, sig, sigLen, 0, NULL, NULL);
991991
}
992992

993+
/* As test_pkey_verify_ecc, but sets signature_md before verifying. */
994+
static int test_pkey_verify_ecc_md(EVP_PKEY *pkey, OSSL_LIB_CTX* libCtx,
995+
const EVP_MD *md, unsigned char *hash, size_t hashLen,
996+
unsigned char *sig, size_t sigLen)
997+
{
998+
int err;
999+
EVP_PKEY_CTX *ctx = NULL;
1000+
1001+
err = (ctx = EVP_PKEY_CTX_new_from_pkey(libCtx, pkey, NULL)) == NULL;
1002+
if (err == 0) {
1003+
err = EVP_PKEY_verify_init(ctx) != 1;
1004+
}
1005+
if (err == 0) {
1006+
err = EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0;
1007+
}
1008+
if (err == 0) {
1009+
err = EVP_PKEY_verify(ctx, sig, sigLen, hash, hashLen) != 1;
1010+
}
1011+
if (err == 0) {
1012+
PRINT_MSG("Signature verified");
1013+
}
1014+
else {
1015+
PRINT_MSG("Signature not verified");
1016+
}
1017+
1018+
EVP_PKEY_CTX_free(ctx);
1019+
1020+
return err;
1021+
}
1022+
9931023
#ifdef WP_HAVE_EC_P192
9941024
int test_ecdsa_p192_pkey(void *data)
9951025
{
@@ -1165,6 +1195,94 @@ int test_ecdsa_p256_pkey(void *data)
11651195

11661196
return err;
11671197
}
1198+
1199+
/* Raw EVP_PKEY_verify must reject sub-SHA-1 inputs. */
1200+
int test_ecdsa_verify_undersized_hash(void *data)
1201+
{
1202+
static const size_t sizes[] = { 0, 19, 20, 32 };
1203+
static const int expectFail[] = { 1, 1, 0, 0 };
1204+
int err;
1205+
size_t i;
1206+
EVP_PKEY *pkey = NULL;
1207+
unsigned char ecdsaSig[80];
1208+
size_t ecdsaSigLen;
1209+
unsigned char buf[32];
1210+
const unsigned char *p = ecc_key_der_256;
1211+
1212+
(void)data;
1213+
1214+
err = RAND_bytes(buf, sizeof(buf)) == 0;
1215+
if (err == 0) {
1216+
pkey = d2i_PrivateKey(EVP_PKEY_EC, NULL, &p, sizeof(ecc_key_der_256));
1217+
err = pkey == NULL;
1218+
}
1219+
1220+
for (i = 0; (err == 0) && (i < sizeof(sizes)/sizeof(sizes[0])); i++) {
1221+
PRINT_MSG("verify tbsLen=%zu", sizes[i]);
1222+
ecdsaSigLen = sizeof(ecdsaSig);
1223+
err = test_pkey_sign_ecc(pkey, osslLibCtx, buf, sizes[i], ecdsaSig,
1224+
&ecdsaSigLen);
1225+
if (err == 0) {
1226+
int verifyErr = test_pkey_verify_ecc(pkey, wpLibCtx, buf, sizes[i],
1227+
ecdsaSig, ecdsaSigLen);
1228+
err = (verifyErr != 0) != expectFail[i];
1229+
}
1230+
}
1231+
1232+
/* Same minimum applies on the sign side: wolfProvider must refuse to
1233+
* produce a raw signature it would later refuse to verify. */
1234+
for (i = 0; (err == 0) && (i < sizeof(sizes)/sizeof(sizes[0])); i++) {
1235+
int signErr;
1236+
PRINT_MSG("sign tbsLen=%zu", sizes[i]);
1237+
ecdsaSigLen = sizeof(ecdsaSig);
1238+
signErr = test_pkey_sign_ecc(pkey, wpLibCtx, buf, sizes[i], ecdsaSig,
1239+
&ecdsaSigLen);
1240+
err = (signErr != 0) != expectFail[i];
1241+
}
1242+
1243+
EVP_PKEY_free(pkey);
1244+
1245+
return err;
1246+
}
1247+
1248+
/* EVP_PKEY_verify with signature_md=SHA-256 must require tbsLen == 32. */
1249+
int test_ecdsa_verify_md_len_mismatch(void *data)
1250+
{
1251+
static const size_t sizes[] = { 19, 31, 32, 33 };
1252+
static const int expectFail[] = { 1, 1, 0, 1 };
1253+
int err;
1254+
size_t i;
1255+
EVP_PKEY *pkey = NULL;
1256+
unsigned char ecdsaSig[80];
1257+
size_t ecdsaSigLen;
1258+
unsigned char buf[64];
1259+
const unsigned char *p = ecc_key_der_256;
1260+
1261+
(void)data;
1262+
1263+
err = RAND_bytes(buf, sizeof(buf)) == 0;
1264+
if (err == 0) {
1265+
pkey = d2i_PrivateKey(EVP_PKEY_EC, NULL, &p, sizeof(ecc_key_der_256));
1266+
err = pkey == NULL;
1267+
}
1268+
1269+
for (i = 0; (err == 0) && (i < sizeof(sizes)/sizeof(sizes[0])); i++) {
1270+
PRINT_MSG("tbsLen=%zu", sizes[i]);
1271+
ecdsaSigLen = sizeof(ecdsaSig);
1272+
err = test_pkey_sign_ecc(pkey, osslLibCtx, buf, sizes[i], ecdsaSig,
1273+
&ecdsaSigLen);
1274+
if (err == 0) {
1275+
int verifyErr = test_pkey_verify_ecc_md(pkey, wpLibCtx, EVP_sha256(),
1276+
buf, sizes[i], ecdsaSig,
1277+
ecdsaSigLen);
1278+
err = (verifyErr != 0) != expectFail[i];
1279+
}
1280+
}
1281+
1282+
EVP_PKEY_free(pkey);
1283+
1284+
return err;
1285+
}
11681286
#endif /* WP_HAVE_EC_P256 */
11691287

11701288
#ifdef WP_HAVE_EC_P384

test/unit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ TEST_CASE test_case[] = {
362362
#ifdef WP_HAVE_ECDSA
363363
TEST_DECL(test_ecdsa_p256_pkey, NULL),
364364
TEST_DECL(test_ecdsa_p256, NULL),
365+
TEST_DECL(test_ecdsa_verify_undersized_hash, NULL),
366+
TEST_DECL(test_ecdsa_verify_md_len_mismatch, NULL),
365367
#endif
366368
TEST_DECL(test_ec_decode, NULL),
367369
TEST_DECL(test_ec_import, NULL),

test/unit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@ int test_ecdsa_p521_pkey(void *data);
396396
#ifdef WP_HAVE_EC_P256
397397
int test_ecdsa_p256_pkey(void *data);
398398
int test_ecdsa_p256(void *data);
399+
int test_ecdsa_verify_undersized_hash(void *data);
400+
int test_ecdsa_verify_md_len_mismatch(void *data);
399401
#endif /* WP_HAVE_EC_P256 */
400402

401403
#ifdef WP_HAVE_EC_P384

0 commit comments

Comments
 (0)