From b6fcdc71a6e3cbb29a68d412967017c4c9937e5a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 4 May 2020 09:45:39 +0200 Subject: [PATCH] pkcs11: Optionally hash data for PKCS#1 v1.5 RSA signatures in software If cards/libraries don't support signature mechanisms with hashing, we fall back to do it ourselves in software and pass the PKCS#1 digestInfo ASN.1 structure to sign via CKM_RSA_PKCS mechanism. Closes strongswan/strongswan#168. --- .../plugins/pkcs11/pkcs11_private_key.c | 62 +++++++++++++++++-- .../plugins/pkcs11/pkcs11_private_key.h | 7 ++- .../plugins/pkcs11/pkcs11_public_key.c | 19 +++++- 3 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index 77cc9bd44..6b8be6265 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -118,9 +118,33 @@ METHOD(private_key_t, get_keysize, int, } /** - * See header. + * Check if a token supports the given mechanism. */ -CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, +static bool is_mechanism_supported(pkcs11_library_t *p11, CK_SLOT_ID slot, + const CK_MECHANISM_PTR mech) +{ + enumerator_t *mechs; + CK_MECHANISM_TYPE type; + + mechs = p11->create_mechanism_enumerator(p11, slot); + while (mechs->enumerate(mechs, &type, NULL)) + { + if (type == mech->mechanism) + { + mechs->destroy(mechs); + return TRUE; + } + } + mechs->destroy(mechs); + return FALSE; +} + +/* + * Described in header + */ +CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11, + CK_SLOT_ID slot, + signature_scheme_t scheme, key_type_t type, size_t keylen, hash_algorithm_t *hash) { @@ -135,12 +159,20 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, KEY_RSA, 0, HASH_UNKNOWN}, {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_SHA256_RSA_PKCS, NULL, 0}, KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA2_256, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA256}, {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_SHA384_RSA_PKCS, NULL, 0}, KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA2_384, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA384}, {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_SHA512_RSA_PKCS, NULL, 0}, KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA2_512, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA512}, {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0}, KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA1}, {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0}, KEY_RSA, 0, HASH_UNKNOWN}, {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0}, @@ -167,9 +199,11 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, if (mappings[i].scheme == scheme) { size_t len = mappings[i].keylen; - if (mappings[i].type != type || (len && keylen != len)) + + if (mappings[i].type != type || (len && keylen != len) || + !is_mechanism_supported(p11, slot, &mappings[i].mechanism)) { - return NULL; + continue; } if (hash) { @@ -254,8 +288,9 @@ METHOD(private_key_t, sign, bool, hash_algorithm_t hash_alg; chunk_t hash = chunk_empty; - mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, - get_keysize(this), &hash_alg); + mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme, + this->type, get_keysize(this), + &hash_alg); if (!mechanism) { DBG1(DBG_LIB, "signature scheme %N not supported", @@ -293,6 +328,21 @@ METHOD(private_key_t, sign, bool, return FALSE; } hasher->destroy(hasher); + switch (scheme) + { + case SIGN_RSA_EMSA_PKCS1_SHA1: + case SIGN_RSA_EMSA_PKCS1_SHA2_256: + case SIGN_RSA_EMSA_PKCS1_SHA2_384: + case SIGN_RSA_EMSA_PKCS1_SHA2_512: + /* encode PKCS#1 digestInfo if the token does not support it */ + hash = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_algorithmIdentifier( + hasher_algorithm_to_oid(hash_alg)), + asn1_wrap(ASN1_OCTET_STRING, "m", hash)); + break; + default: + break; + } data = hash; } len = (get_keysize(this) + 7) / 8; diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h index b3bf911c2..24565e1ba 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h @@ -30,6 +30,7 @@ typedef struct pkcs11_private_key_t pkcs11_private_key_t; #include #include "pkcs11.h" +#include "pkcs11_library.h" /** * Private Key implementation on top of PKCS#11. @@ -58,12 +59,16 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args); * * Verifies that the given key is usable for this scheme. * + * @param lib PKCS#11 library of the token the key resides on + * @param slot slot of the token * @param scheme signature scheme * @param type key type * @param keylen key length in bits * @param hash hash algorithm to apply first (HASH_UNKNOWN if none) */ -CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, +CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *lib, + CK_SLOT_ID slot, + signature_scheme_t scheme, key_type_t type, size_t keylen, hash_algorithm_t *hash); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index ed450a6c7..5c7a9a102 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -211,8 +211,8 @@ METHOD(public_key_t, verify, bool, chunk_t hash = chunk_empty, parse, r, s; size_t len; - mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k, - &hash_alg); + mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme, + this->type, this->k, &hash_alg); if (!mechanism) { DBG1(DBG_LIB, "signature scheme %N not supported", @@ -277,6 +277,21 @@ METHOD(public_key_t, verify, bool, return FALSE; } hasher->destroy(hasher); + switch (scheme) + { + case SIGN_RSA_EMSA_PKCS1_SHA1: + case SIGN_RSA_EMSA_PKCS1_SHA2_256: + case SIGN_RSA_EMSA_PKCS1_SHA2_384: + case SIGN_RSA_EMSA_PKCS1_SHA2_512: + /* encode PKCS#1 digestInfo if the token does not support it */ + hash = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_algorithmIdentifier( + hasher_algorithm_to_oid(hash_alg)), + asn1_wrap(ASN1_OCTET_STRING, "m", hash)); + break; + default: + break; + } data = hash; } rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len);