ECDSA Signatures with hashes

This PR is based on discussion with @popovec in
https://github.com/OpenSC/OpenSC/issues/2181
and https://github.com/OpenSC/OpenSC/pull/2187
which was cherry-picked as 5e5300816c8

This has been tested with PIV, MyEID and Smartcard-HSM.
with ECDSA keys.

The main fixes include :
 - Setting "flags" in card drivers
 - added code to sc_pkcs15-compute-signature for handle ECDSA with hashes
 - code in framework-pkcs15.c

Signatures made by pkcs11-tool -sigm verify with openssl
but pkcs11-tool --verify  does not work with ECDSA but does with RSA
I suspect it has to do with:
and some  then creating the wrong PKCS11 mechanisms

It should work with the epass2003 which does hashes in the driver.
This commit is contained in:
Doug Engert 2020-12-21 12:02:28 -06:00 committed by Frank Morgner
parent 6049cb926c
commit 285db1ef29
4 changed files with 137 additions and 53 deletions

View File

@ -245,9 +245,7 @@ static int myeid_init(struct sc_card *card)
int i;
flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN;
flags |= SC_ALGORITHM_ECDSA_HASH_NONE | SC_ALGORITHM_ECDSA_HASH_SHA1;
flags |= SC_ALGORITHM_ECDSA_HASH_SHA224 | SC_ALGORITHM_ECDSA_HASH_SHA256;
flags |= SC_ALGORITHM_ECDSA_HASH_SHA384 | SC_ALGORITHM_ECDSA_HASH_SHA512;
flags |= SC_ALGORITHM_ECDSA_HASH_NONE;
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
for (i=0; ec_curves[i].curve_name != NULL; i++) {

View File

@ -608,56 +608,69 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
/* if the card has SC_ALGORITHM_NEED_USAGE set, and the
* key is for signing and decryption, we need to emulate signing */
/* TODO: -DEE assume only RSA keys will ever use _NEED_USAGE */
sc_log(ctx, "supported algorithm flags 0x%X, private key usage 0x%X", alg_info->flags, prkey->usage);
if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) &&
((prkey->usage & USAGE_ANY_SIGN) &&
(prkey->usage & USAGE_ANY_DECIPHER)) ) {
size_t tmplen = sizeof(buf);
if (flags & SC_ALGORITHM_RSA_RAW) {
r = sc_pkcs15_decipher(p15card, obj, flags, in, inlen, out, outlen);
if (obj->type == SC_ALGORITHM_RSA) {
if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) &&
((prkey->usage & USAGE_ANY_SIGN) &&
(prkey->usage & USAGE_ANY_DECIPHER)) ) {
size_t tmplen = sizeof(buf);
if (flags & SC_ALGORITHM_RSA_RAW) {
r = sc_pkcs15_decipher(p15card, obj, flags, in, inlen, out, outlen);
LOG_FUNC_RETURN(ctx, r);
}
if (modlen > tmplen)
LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!");
/* XXX Assuming RSA key here */
r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length);
/* no padding needed - already done */
flags &= ~SC_ALGORITHM_RSA_PADS;
/* instead use raw rsa */
flags |= SC_ALGORITHM_RSA_RAW;
LOG_TEST_RET(ctx, r, "Unable to add padding");
r = sc_pkcs15_decipher(p15card, obj, flags, buf, modlen, out, outlen);
LOG_FUNC_RETURN(ctx, r);
}
if (modlen > tmplen)
LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!");
/* XXX Assuming RSA key here */
r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length);
/* no padding needed - already done */
flags &= ~SC_ALGORITHM_RSA_PADS;
/* instead use raw rsa */
flags |= SC_ALGORITHM_RSA_RAW;
/* If the card doesn't support the requested algorithm, we normally add the
* padding here in software and ask the card to do a raw signature. There's
* one exception to that, where we might be able to get the signature to
* succeed by stripping padding if the card only offers higher-level
* signature operations. The only thing we can strip is the DigestInfo
* block from PKCS1 padding. */
if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
!(alg_info->flags & SC_ALGORITHM_RSA_RAW) &&
!(alg_info->flags & SC_ALGORITHM_RSA_HASH_NONE) &&
(alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
unsigned int algo;
size_t tmplen = sizeof(buf);
LOG_TEST_RET(ctx, r, "Unable to add padding");
r = sc_pkcs15_decipher(p15card, obj, flags, buf, modlen, out, outlen);
LOG_FUNC_RETURN(ctx, r);
r = sc_pkcs1_strip_digest_info_prefix(&algo, tmp, inlen, tmp, &tmplen);
if (r != SC_SUCCESS || algo == SC_ALGORITHM_RSA_HASH_NONE) {
sc_mem_clear(buf, sizeof(buf));
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
}
flags &= ~SC_ALGORITHM_RSA_HASH_NONE;
flags |= algo;
inlen = tmplen;
}
}
/* If the card doesn't support the requested algorithm, we normally add the
* padding here in software and ask the card to do a raw signature. There's
* one exception to that, where we might be able to get the signature to
* succeed by stripping padding if the card only offers higher-level
* signature operations. The only thing we can strip is the DigestInfo
* block from PKCS1 padding. */
if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
!(alg_info->flags & SC_ALGORITHM_RSA_RAW) &&
!(alg_info->flags & SC_ALGORITHM_RSA_HASH_NONE) &&
(alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
unsigned int algo;
size_t tmplen = sizeof(buf);
r = sc_pkcs1_strip_digest_info_prefix(&algo, tmp, inlen, tmp, &tmplen);
if (r != SC_SUCCESS || algo == SC_ALGORITHM_RSA_HASH_NONE) {
sc_mem_clear(buf, sizeof(buf));
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
/* ECDSA sofware hash has already been done, or is not needed, or card will do hash */
/* if card can not do the hash, will use SC_ALGORITHM_ECDSA_RAW */
if (obj->type == SC_PKCS15_TYPE_PRKEY_EC) {
if ((alg_info->flags & SC_ALGORITHM_ECDSA_RAW)
&& !(flags & SC_ALGORITHM_ECDSA_HASHES & alg_info->flags)) {
sc_log(ctx, "ECDSA using SC_ALGORITHM_ECDSA_RAW flags before 0x%8.8lx", flags);
flags |= SC_ALGORITHM_ECDSA_RAW;
flags &= ~SC_ALGORITHM_ECDSA_HASHES;
}
flags &= ~SC_ALGORITHM_RSA_HASH_NONE;
flags |= algo;
inlen = tmplen;
}
r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
@ -665,6 +678,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
sc_mem_clear(buf, sizeof(buf));
LOG_FUNC_RETURN(ctx, r);
}
/* senv now has flags card or driver will do */
senv.algorithm_flags = sec_flags;
sc_log(ctx, "DEE flags:0x%8.8lx alg_info->flags:0x%8.8x pad:0x%8.8lx sec:0x%8.8lx",
@ -695,9 +709,10 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
* If the length of the hash value is larger than the bit length of n, only
* the leftmost bits of the hash up to the length of n will be used. Any
* truncation is done by the token.
* But if card is going to do the hash, pass in all the data
*/
else if (senv.algorithm == SC_ALGORITHM_EC &&
(flags & SC_ALGORITHM_ECDSA_HASHES)) {
(senv.flags & SC_ALGORITHM_ECDSA_HASHES) == 0) {
inlen = MIN(inlen, (prkey->field_length+7)/8);
}

View File

@ -5649,11 +5649,12 @@ static CK_RV register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
if (ext_flags & SC_ALGORITHM_EXT_EC_COMPRESS)
ec_flags |= CKF_EC_COMPRESS;
mech_info.flags = CKF_HW | CKF_SIGN; /* check for more */
mech_info.flags = CKF_HW | CKF_SIGN | CKF_VERIFY;
mech_info.flags |= ec_flags;
mech_info.ulMinKeySize = min_key_size;
mech_info.ulMaxKeySize = max_key_size;
/* add mechs card or driver support */
if (flags & SC_ALGORITHM_ECDSA_RAW) {
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA, &mech_info, CKK_EC, NULL, NULL);
if (!mt)
@ -5661,38 +5662,89 @@ static CK_RV register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
}
#ifdef ENABLE_OPENSSL
/* Hashing is always done in openssl, if the card driver requests hashes, we enable them here. */
/* if card supports RAW add sign_and_hash using RAW for mechs card does not support */
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA1) {
if (flags & SC_ALGORITHM_ECDSA_RAW) {
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA1)) {
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA1, CKM_SHA_1, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA224) {
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA224)) {
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA224, CKM_SHA224, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA256) {
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA256)) {
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA256, CKM_SHA256, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA384) {
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA384)) {
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA384, CKM_SHA384, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA512) {
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA512)) {
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA512, CKM_SHA512, mt);
if (rc != CKR_OK)
return rc;
}
}
#endif
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA1) {
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1, &mech_info, CKK_EC, NULL, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA224) {
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA224, &mech_info, CKK_EC, NULL, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA256) {
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA256, &mech_info, CKK_EC, NULL, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA384) {
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA384, &mech_info, CKK_EC, NULL, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
}
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA512) {
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA512, &mech_info, CKK_EC, NULL, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
}
/* ADD ECDH mechanisms */
/* The PIV uses curves where CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE produce the same results */
if(flags & SC_ALGORITHM_ECDH_CDH_RAW) {
@ -5725,6 +5777,11 @@ static CK_RV register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
return rc;
}
#ifdef ENABLE_OPNSSL
/* if card does not support a HASH but supports RAW add split mech */
#endif
return CKR_OK;
}
@ -5786,6 +5843,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
sc_pkcs11_mechanism_type_t *mt;
unsigned int num;
int rsa_flags = 0, ec_flags = 0, gostr_flags = 0, aes_flags = 0;
int ec_found;
CK_RV rc;
/* Register generic mechanisms */
@ -5805,6 +5863,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
mech_info.ulMaxKeySize = 0;
ec_min_key_size = ~0;
ec_max_key_size = 0;
ec_found = 0;
aes_min_key_size = ~0;
aes_max_key_size = 0;
@ -5831,6 +5890,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
ec_max_key_size = alg_info->key_length;
ec_flags |= alg_info->flags;
ec_ext_flags |= alg_info->u._ec.ext_flags;
ec_found = 1;
break;
case SC_ALGORITHM_GOSTR3410:
gostr_flags |= alg_info->flags;
@ -5846,7 +5906,12 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
alg_info++;
}
if (ec_flags & SC_ALGORITHM_ECDSA_RAW) {
/*
* TODO this looked like a bug:
* if (ec_flags & SC_ALGORITHM_ECDSA_RAW)
* Card driver driver should not have to specify SC_ALGORITHM_ECDSA_RAW
*/
if (ec_found) {
rc = register_ec_mechanisms(p11card, ec_flags, ec_ext_flags, ec_min_key_size, ec_max_key_size);
if (rc != CKR_OK)
return rc;

View File

@ -475,7 +475,13 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, unsigned int pubkey_len
|| mech->mechanism == CKM_SHA224_RSA_PKCS
|| mech->mechanism == CKM_SHA256_RSA_PKCS
|| mech->mechanism == CKM_SHA384_RSA_PKCS
|| mech->mechanism == CKM_SHA512_RSA_PKCS)) {
|| mech->mechanism == CKM_SHA512_RSA_PKCS
|| mech->mechanism == CKM_ECDSA_SHA1
|| mech->mechanism == CKM_ECDSA_SHA224
|| mech->mechanism == CKM_ECDSA_SHA256
|| mech->mechanism == CKM_ECDSA_SHA384
|| mech->mechanism == CKM_ECDSA_SHA512
)) {
EVP_MD_CTX *md_ctx = DIGEST_CTX(md);
/* This does not really use the data argument, but the data