pkcs11: Optionally hash data for PKCS#1 v1.5 RSA signatures in software
authorTobias Brunner <tobias@strongswan.org>
Mon, 4 May 2020 07:45:39 +0000 (09:45 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 7 May 2020 07:11:19 +0000 (09:11 +0200)
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.

src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h
src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c

index 77cc9bd..6b8be62 100644 (file)
@@ -118,9 +118,33 @@ METHOD(private_key_t, get_keysize, int,
 }
 
 /**
- * See header.
+ * Check if a token supports the given mechanism.
+ */
+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(signature_scheme_t scheme,
+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;
index b3bf911..24565e1 100644 (file)
@@ -30,6 +30,7 @@ typedef struct pkcs11_private_key_t pkcs11_private_key_t;
 #include <credentials/keys/private_key.h>
 
 #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);
 
index ed450a6..5c7a9a1 100644 (file)
@@ -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);