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:
parent
6049cb926c
commit
285db1ef29
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue