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

Reply via email to