Hello Attached patch allowing use of PKCS#11 smartcards/tokens which don't support signing-with-hashing mechanisms.
By default only plain CKM_RSA_PKCS (and if supported by token also CKM_ECDSA) mechanism is now used, hashing is done using external hasher. Old behaviour can be restored using charon.plugins.pkcs11.use_sign_hasher option. Code may need tweaking. One possibility is to enable this behaviour based on supported mechanisms returned by the token, but it seems unnecessary, as all PKCS#11 tokens supporting signatures with hashing support also non-hashing version of signature. Patch should be applied to the master branch. Comments and suggestions are welcome. Michał Skalski
From 57b04507bff73a822756321eb788ae38bd532257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Skalski?= <[email protected]> Date: Wed, 28 Sep 2016 17:43:55 +0200 Subject: [PATCH] PKCS11 plugin: Enable support for tokens without hashing-with-sign Enabled support for PKCS#11 tokens which don't support sign with hashing operations (onlu single-part Sign() function is supported). TODO: add support configurable per library (configurable) or per token (automatically determined by supported mechanisms). --- conf/plugins/pkcs11.opt | 3 + src/libstrongswan/plugins/pkcs11/pkcs11.h | 2 + .../plugins/pkcs11/pkcs11_private_key.c | 175 ++++++++++++++++++--- .../plugins/pkcs11/pkcs11_private_key.h | 8 + .../plugins/pkcs11/pkcs11_public_key.c | 34 +++- 5 files changed, 195 insertions(+), 27 deletions(-) diff --git a/conf/plugins/pkcs11.opt b/conf/plugins/pkcs11.opt index f5a2028..de0ac7a 100644 --- a/conf/plugins/pkcs11.opt +++ b/conf/plugins/pkcs11.opt @@ -24,3 +24,6 @@ charon.plugins.pkcs11.use_pubkey = no charon.plugins.pkcs11.use_rng = no Whether the PKCS#11 modules should be used as RNG. + +charon.plugins.pkcs11.use_sign_hasher = no + Whether the PKCS#11 modules should use signature mechanisms with hashing. diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11.h b/src/libstrongswan/plugins/pkcs11/pkcs11.h index da29a77..bf6a326 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11.h +++ b/src/libstrongswan/plugins/pkcs11/pkcs11.h @@ -512,6 +512,8 @@ typedef unsigned long ck_mechanism_type_t; #define CKM_SHA256_RSA_PKCS_PSS (0x43) #define CKM_SHA384_RSA_PKCS_PSS (0x44) #define CKM_SHA512_RSA_PKCS_PSS (0x45) +#define CKM_SHA224_RSA_PKCS (0x46) +#define CKM_SHA224_RSA_PKCS_PSS (0x47) #define CKM_RC2_KEY_GEN (0x100) #define CKM_RC2_ECB (0x101) #define CKM_RC2_CBC (0x102) diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index aec4550..eef37c9 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -96,6 +96,9 @@ METHOD(private_key_t, get_keysize, int, return this->pubkey->get_keysize(this->pubkey); } + +#define HASH_NOT_USED (hash_algorithm_t)(-1) + /** * See header. */ @@ -110,22 +113,26 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, size_t keylen; hash_algorithm_t hash; } mappings[] = { + /* versions for external hashers or no hashers at all*/ {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0}, - KEY_RSA, 0, HASH_UNKNOWN}, - {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0}, - KEY_RSA, 0, HASH_UNKNOWN}, - {SIGN_RSA_EMSA_PKCS1_SHA256, {CKM_SHA256_RSA_PKCS, NULL, 0}, - KEY_RSA, 0, HASH_UNKNOWN}, - {SIGN_RSA_EMSA_PKCS1_SHA384, {CKM_SHA384_RSA_PKCS, NULL, 0}, - KEY_RSA, 0, HASH_UNKNOWN}, - {SIGN_RSA_EMSA_PKCS1_SHA512, {CKM_SHA512_RSA_PKCS, NULL, 0}, - KEY_RSA, 0, HASH_UNKNOWN}, - {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0}, - KEY_RSA, 0, HASH_UNKNOWN}, + KEY_RSA, 0, HASH_NOT_USED}, + {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA1}, + {SIGN_RSA_EMSA_PKCS1_SHA224, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA224}, + {SIGN_RSA_EMSA_PKCS1_SHA256, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA256}, + {SIGN_RSA_EMSA_PKCS1_SHA384, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA384}, + {SIGN_RSA_EMSA_PKCS1_SHA512, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_SHA512}, + {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_MD5}, + {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0}, - KEY_ECDSA, 0, HASH_UNKNOWN}, - {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0}, - KEY_ECDSA, 0, HASH_UNKNOWN}, + KEY_ECDSA, 0, HASH_NOT_USED}, + {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 0, HASH_SHA1}, {SIGN_ECDSA_WITH_SHA256_DER, {CKM_ECDSA, NULL, 0}, KEY_ECDSA, 0, HASH_SHA256}, {SIGN_ECDSA_WITH_SHA384_DER, {CKM_ECDSA, NULL, 0}, @@ -138,6 +145,22 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, KEY_ECDSA, 384, HASH_SHA384}, {SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0}, KEY_ECDSA, 521, HASH_SHA512}, + + /* versions with use of hasher inside PKCS#11 library */ + {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA224, {CKM_SHA224_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA256, {CKM_SHA256_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA384, {CKM_SHA384_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA512, {CKM_SHA512_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0}, + KEY_ECDSA, 0, HASH_UNKNOWN}, }; int i; @@ -148,13 +171,19 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, size_t len = mappings[i].keylen; if (mappings[i].type != type || (len && keylen != len)) { - return NULL; + continue; + } + if (mappings[i].hash == HASH_NOT_USED ) + { + *hash = HASH_UNKNOWN; + return &mappings[i].mechanism; } - if (hash) + else if ((hash && mappings[i].hash != HASH_UNKNOWN) || + (!hash && mappings[i].hash == HASH_UNKNOWN)) { *hash = mappings[i].hash; + return &mappings[i].mechanism; } - return &mappings[i].mechanism; } } return NULL; @@ -221,20 +250,105 @@ static bool reauth(private_pkcs11_private_key_t *this, return success; } +/* + MD5: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 + 10 || H. + SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H. + SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 + 04 20 || H. + SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 + 04 30 || H. + SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 + 04 40 || H. + */ + +static chunk_t ssa_pkcs1v15_md5_prolog = chunk_from_chars( + 0x30, 0x20, /* DigestInfo tag + length */ + 0x30, 0x0c, /* AlgorithmIdentifier tag + length */ + 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* MD5 OID tag + length + value*/ + 0x05, 0x00, /* NULL*/ + 0x04, 0x10 /* Digest value + length (prolog, no value) */ + ); + +static chunk_t ssa_pkcs1v15_sha1_prolog = chunk_from_chars( + 0x30, 0x21, /* DigestInfo tag + length */ + 0x30, 0x09, /* AlgorithmIdentifier tag + length */ + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* SHA-1 OID tag + length + value*/ + 0x05, 0x00, /* NULL*/ + 0x04, 0x14 /* Digest value + length (prolog, no value) */ + ); + +static chunk_t ssa_pkcs1v15_sha256_prolog = chunk_from_chars( + 0x30, 0x31, /* DigestInfo tag + length */ + 0x30, 0x0d, /* AlgorithmIdentifier tag + length */ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* SHA-256 OID tag + length + value*/ + 0x05, 0x00, /* NULL*/ + 0x04, 0x20 /* Digest value + length (prolog, no value) */ + ); + +static chunk_t ssa_pkcs1v15_sha384_prolog = chunk_from_chars( + 0x30, 0x41, /* DigestInfo tag + length */ + 0x30, 0x0d, /* AlgorithmIdentifier tag + length */ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, /* SHA-384 OID tag + length + value*/ + 0x05, 0x00, /* NULL*/ + 0x04, 0x30 /* Digest value + length (prolog, no value) */ + ); + +static chunk_t ssa_pkcs1v15_sha512_prolog = chunk_from_chars( + 0x30, 0x51, /* DigestInfo tag + length */ + 0x30, 0x0d, /* AlgorithmIdentifier tag + length */ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* SHA-512 OID tag + length + value*/ + 0x05, 0x00, /* NULL*/ + 0x04, 0x40 /* Digest value + length (prolog, no value) */ + ); + +static chunk_t ssa_pkcs1v15_sha224_prolog = chunk_from_chars( + 0x30, 0x2d, /* DigestInfo tag + length */ + 0x30, 0x0d, /* AlgorithmIdentifier tag + length */ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, /* SHA-224 OID tag + length + value*/ + 0x05, 0x00, /* NULL*/ + 0x04, 0x1c /* Digest value + length (prolog, no value) */ + ); + + +chunk_t pkcs11_ssa_pkcs1v15_encode(hash_algorithm_t hash_alg, chunk_t hash) +{ + static const char mode[3] = "cc"; + switch (hash_alg) + { + case HASH_MD5: return chunk_cat( mode, ssa_pkcs1v15_md5_prolog, hash ); + case HASH_SHA1: return chunk_cat( mode, ssa_pkcs1v15_sha1_prolog, hash ); + case HASH_SHA224: return chunk_cat( mode, ssa_pkcs1v15_sha224_prolog, hash ); + case HASH_SHA256: return chunk_cat( mode, ssa_pkcs1v15_sha256_prolog, hash ); + case HASH_SHA384: return chunk_cat( mode, ssa_pkcs1v15_sha384_prolog, hash ); + case HASH_SHA512: return chunk_cat( mode, ssa_pkcs1v15_sha512_prolog, hash ); + + default: + return chunk_empty; + } +} + METHOD(private_key_t, sign, bool, private_pkcs11_private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature) { - CK_MECHANISM_PTR mechanism; + CK_MECHANISM_PTR mechanism = NULL; CK_SESSION_HANDLE session; CK_BYTE_PTR buf; CK_ULONG len; CK_RV rv; - hash_algorithm_t hash_alg; + hash_algorithm_t hash_alg = HASH_UNKNOWN; chunk_t hash = chunk_empty; + chunk_t digest_info = chunk_empty; + bool use_sign_hasher; + + use_sign_hasher = lib->settings->get_bool(lib->settings, "%s.plugins.pkcs11.use_sign_hasher", FALSE, lib->ns); + + if( use_sign_hasher ) + mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, get_keysize(this), NULL); + if( !mechanism ) + mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, get_keysize(this), &hash_alg); - mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, - get_keysize(this), &hash_alg); if (!mechanism) { DBG1(DBG_LIB, "signature scheme %N not supported", @@ -272,7 +386,23 @@ METHOD(private_key_t, sign, bool, return FALSE; } hasher->destroy(hasher); - data = hash; + switch (scheme) + { + case SIGN_RSA_EMSA_PKCS1_MD5: + case SIGN_RSA_EMSA_PKCS1_SHA1: + case SIGN_RSA_EMSA_PKCS1_SHA224: + case SIGN_RSA_EMSA_PKCS1_SHA256: + case SIGN_RSA_EMSA_PKCS1_SHA384: + case SIGN_RSA_EMSA_PKCS1_SHA512: + digest_info = pkcs11_ssa_pkcs1v15_encode(hash_alg, hash); + data = digest_info; + break; + + default: + data = hash; + break; + } + } len = (get_keysize(this) + 7) / 8; if (this->type == KEY_ECDSA) @@ -283,6 +413,7 @@ METHOD(private_key_t, sign, bool, rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len); this->lib->f->C_CloseSession(session); chunk_free(&hash); + chunk_free(&digest_info); if (rv != CKR_OK) { DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h index 6d3a955..82fd6d9 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h @@ -62,6 +62,8 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args); * @param type key type * @param keylen key length in bits * @param hash hash algorithm to apply first (HASH_UNKNOWN if none) + * If hash is given NULL, returns mechanism (if supported) + * for hashing and signing/verifying at once. */ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, key_type_t type, size_t keylen, @@ -72,4 +74,10 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, */ CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme); +/** + * Encodes digest for PKCS#1 v1.5 signature to be given for CKM_RSA_PKCS mechanism + */ +chunk_t pkcs11_ssa_pkcs1v15_encode(hash_algorithm_t hash_alg, chunk_t hash); + + #endif /** PKCS11_PRIVATE_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index 3847776..a65100a 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -204,15 +204,21 @@ METHOD(public_key_t, verify, bool, private_pkcs11_public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t sig) { - CK_MECHANISM_PTR mechanism; + CK_MECHANISM_PTR mechanism = NULL; CK_SESSION_HANDLE session; CK_RV rv; hash_algorithm_t hash_alg; - chunk_t hash = chunk_empty, parse, r, s; + chunk_t hash = chunk_empty, digest_info = chunk_empty, parse, r, s; size_t len; + bool use_sign_hasher; + + use_sign_hasher = lib->settings->get_bool(lib->settings, "%s.plugins.pkcs11.use_sign_hasher", FALSE, lib->ns); + + if( use_sign_hasher ) + mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k, NULL); + if( !mechanism ) + mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k, &hash_alg); - mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k, - &hash_alg); if (!mechanism) { DBG1(DBG_LIB, "signature scheme %N not supported", @@ -247,6 +253,7 @@ METHOD(public_key_t, verify, bool, memcpy(sig.ptr + (len - r.len), r.ptr, r.len); memcpy(sig.ptr + len + (len - s.len), s.ptr, s.len); break; + default: sig = chunk_skip_zero(sig); break; @@ -277,11 +284,28 @@ METHOD(public_key_t, verify, bool, return FALSE; } hasher->destroy(hasher); - data = hash; + + switch (scheme) + { + case SIGN_RSA_EMSA_PKCS1_MD5: + case SIGN_RSA_EMSA_PKCS1_SHA1: + case SIGN_RSA_EMSA_PKCS1_SHA224: + case SIGN_RSA_EMSA_PKCS1_SHA256: + case SIGN_RSA_EMSA_PKCS1_SHA384: + case SIGN_RSA_EMSA_PKCS1_SHA512: + digest_info = pkcs11_ssa_pkcs1v15_encode(hash_alg, hash); + data = digest_info; + break; + + default: + data = hash; + break; + } } rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len); this->lib->f->C_CloseSession(session); chunk_free(&hash); + chunk_free(&digest_info); if (rv != CKR_OK) { DBG1(DBG_LIB, "C_Verify() failed: %N", ck_rv_names, rv); -- 1.9.1
_______________________________________________ Dev mailing list [email protected] https://lists.strongswan.org/mailman/listinfo/dev
