/*
* Helper functions
*/
-
-static int key2protkey_fallback(const struct clearkeytoken *t,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
-{
- size_t tmpbuflen = max_t(size_t, SECKEYBLOBSIZE, MAXEP11AESKEYBLOBSIZE);
- u32 keysize, keybitsize, tmplen;
- u8 *tmpbuf = NULL;
- int i, rc;
-
- /* As of now only for AES keys a fallback is available */
-
- keysize = pkey_keytype_aes_to_size(t->keytype);
- if (!keysize) {
- PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
- __func__, t->keytype);
- return -EINVAL;
- }
- if (t->len != keysize) {
- PKEY_DBF_ERR("%s clear key AES token: invalid key len %u\n",
- __func__, t->len);
- return -EINVAL;
- }
- keybitsize = 8 * keysize;
-
- /* alloc tmp key buffer */
- tmpbuf = kmalloc(tmpbuflen, GFP_ATOMIC);
- if (!tmpbuf)
- return -ENOMEM;
-
- /* try two times in case of failure */
- for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
-
- /* CCA secure key way */
- tmplen = tmpbuflen;
- rc = pkey_handler_clr_to_key(NULL, 0,
- t->keytype, PKEY_TYPE_CCA_DATA,
- keybitsize, 0,
- t->clearkey, t->len,
- tmpbuf, &tmplen, NULL);
- pr_debug("clr_to_key()=%d\n", rc);
- if (rc)
- goto try_via_ep11;
- rc = pkey_handler_key_to_protkey(NULL, 0,
- tmpbuf, tmplen,
- protkey, protkeylen,
- protkeytype);
- pr_debug("key_to_protkey()=%d\n", rc);
- if (!rc)
- break;
-
-try_via_ep11:
- /* the CCA way failed, try via EP11 */
- tmplen = tmpbuflen;
- rc = pkey_handler_clr_to_key(NULL, 0,
- t->keytype, PKEY_TYPE_EP11_AES,
- keybitsize, 0,
- t->clearkey, t->len,
- tmpbuf, &tmplen, NULL);
- pr_debug("clr_to_key()=%d\n", rc);
- if (rc)
- continue;
- rc = pkey_handler_key_to_protkey(NULL, 0,
- tmpbuf, tmplen,
- protkey, protkeylen,
- protkeytype);
- pr_debug("key_to_protkey()=%d\n", rc);
- }
-
- kfree(tmpbuf);
-
- return rc;
-}
-
static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
const u8 *key, size_t keylen,
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- struct keytoken_header *hdr = (struct keytoken_header *)key;
- int i, rc;
-
- /* retry two times */
- for (rc = -ENODEV, i = 0; rc && i < 2; i++) {
- /* First try the direct way */
- rc = pkey_handler_key_to_protkey(apqns, nr_apqns,
- key, keylen,
- protkey, protkeylen,
- protkeytype);
- /* For some clear key tokens there exists a fallback way */
- if (rc &&
- hdr->type == TOKTYPE_NON_CCA &&
- hdr->version == TOKVER_CLEAR_KEY)
- rc = key2protkey_fallback((struct clearkeytoken *)key,
- protkey, protkeylen,
- protkeytype);
+ int rc;
+
+ /* try the direct way */
+ rc = pkey_handler_key_to_protkey(apqns, nr_apqns,
+ key, keylen,
+ protkey, protkeylen,
+ protkeytype);
+
+ /* if this did not work, try the slowpath way */
+ if (rc == -ENODEV) {
+ rc = pkey_handler_slowpath_key_to_protkey(apqns, nr_apqns,
+ key, keylen,
+ protkey, protkeylen,
+ protkeytype);
+ if (rc)
+ rc = -ENODEV;
}
+ pr_debug("rc=%d\n", rc);
return rc;
}
}
EXPORT_SYMBOL(pkey_handler_key_to_protkey);
+/*
+ * This handler invocation is special as there may be more than
+ * one handler providing support for the very same key (type).
+ * And the handler may not respond true on is_supported_key(),
+ * so simple try and check return value here.
+ */
+int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
+ size_t nr_apqns,
+ const u8 *key, u32 keylen,
+ u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype)
+{
+ const struct pkey_handler *h, *htmp[10];
+ int i, n = 0, rc = -ENODEV;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(h, &handler_list, list) {
+ if (!try_module_get(h->module))
+ continue;
+ if (h->slowpath_key_to_protkey && n < ARRAY_SIZE(htmp))
+ htmp[n++] = h;
+ else
+ module_put(h->module);
+ }
+ rcu_read_unlock();
+
+ for (i = 0; i < n; i++) {
+ h = htmp[i];
+ if (rc)
+ rc = h->slowpath_key_to_protkey(apqns, nr_apqns,
+ key, keylen,
+ protkey, protkeylen,
+ protkeytype);
+ module_put(h->module);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey);
+
int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
u32 keytype, u32 keysubtype,
u32 keybitsize, u32 flags,
int (*key_to_protkey)(const struct pkey_apqn *apqns, size_t nr_apqns,
const u8 *key, u32 keylen,
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
+ int (*slowpath_key_to_protkey)(const struct pkey_apqn *apqns,
+ size_t nr_apqns,
+ const u8 *key, u32 keylen,
+ u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype);
int (*gen_key)(const struct pkey_apqn *apqns, size_t nr_apqns,
u32 keytype, u32 keysubtype,
u32 keybitsize, u32 flags,
int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
const u8 *key, u32 keylen,
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
+int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
+ size_t nr_apqns,
+ const u8 *key, u32 keylen,
+ u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype);
int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
u32 keytype, u32 keysubtype,
u32 keybitsize, u32 flags,
return rc;
}
+/*
+ * This function provides an alternate but usually slow way
+ * to convert a 'clear key token' with AES key material into
+ * a protected key. This is done via an intermediate step
+ * which creates a CCA AES DATA secure key first and then
+ * derives the protected key from this secure key.
+ */
+static int cca_slowpath_key2protkey(const struct pkey_apqn *apqns,
+ size_t nr_apqns,
+ const u8 *key, u32 keylen,
+ u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype)
+{
+ const struct keytoken_header *hdr = (const struct keytoken_header *)key;
+ const struct clearkeytoken *t = (const struct clearkeytoken *)key;
+ u32 tmplen, keysize = 0;
+ u8 *tmpbuf;
+ int i, rc;
+
+ if (keylen < sizeof(*hdr))
+ return -EINVAL;
+
+ if (hdr->type == TOKTYPE_NON_CCA &&
+ hdr->version == TOKVER_CLEAR_KEY)
+ keysize = pkey_keytype_aes_to_size(t->keytype);
+ if (!keysize || t->len != keysize)
+ return -EINVAL;
+
+ /* alloc tmp key buffer */
+ tmpbuf = kmalloc(SECKEYBLOBSIZE, GFP_ATOMIC);
+ if (!tmpbuf)
+ return -ENOMEM;
+
+ /* try two times in case of failure */
+ for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
+ tmplen = SECKEYBLOBSIZE;
+ rc = cca_clr2key(NULL, 0, t->keytype, PKEY_TYPE_CCA_DATA,
+ 8 * keysize, 0, t->clearkey, t->len,
+ tmpbuf, &tmplen, NULL);
+ pr_debug("cca_clr2key()=%d\n", rc);
+ if (rc)
+ continue;
+ rc = cca_key2protkey(NULL, 0, tmpbuf, tmplen,
+ protkey, protkeylen, protkeytype);
+ pr_debug("cca_key2protkey()=%d\n", rc);
+ }
+
+ kfree(tmpbuf);
+ pr_debug("rc=%d\n", rc);
+ return rc;
+}
+
static struct pkey_handler cca_handler = {
- .module = THIS_MODULE,
- .name = "PKEY CCA handler",
- .is_supported_key = is_cca_key,
- .is_supported_keytype = is_cca_keytype,
- .key_to_protkey = cca_key2protkey,
- .gen_key = cca_gen_key,
- .clr_to_key = cca_clr2key,
- .verify_key = cca_verifykey,
- .apqns_for_key = cca_apqns4key,
- .apqns_for_keytype = cca_apqns4type,
+ .module = THIS_MODULE,
+ .name = "PKEY CCA handler",
+ .is_supported_key = is_cca_key,
+ .is_supported_keytype = is_cca_keytype,
+ .key_to_protkey = cca_key2protkey,
+ .slowpath_key_to_protkey = cca_slowpath_key2protkey,
+ .gen_key = cca_gen_key,
+ .clr_to_key = cca_clr2key,
+ .verify_key = cca_verifykey,
+ .apqns_for_key = cca_apqns4key,
+ .apqns_for_keytype = cca_apqns4type,
};
/*
return rc;
}
+/*
+ * This function provides an alternate but usually slow way
+ * to convert a 'clear key token' with AES key material into
+ * a protected key. That is done via an intermediate step
+ * which creates an EP11 AES secure key first and then derives
+ * the protected key from this secure key.
+ */
+static int ep11_slowpath_key2protkey(const struct pkey_apqn *apqns,
+ size_t nr_apqns,
+ const u8 *key, u32 keylen,
+ u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype)
+{
+ const struct keytoken_header *hdr = (const struct keytoken_header *)key;
+ const struct clearkeytoken *t = (const struct clearkeytoken *)key;
+ u32 tmplen, keysize = 0;
+ u8 *tmpbuf;
+ int i, rc;
+
+ if (keylen < sizeof(*hdr))
+ return -EINVAL;
+
+ if (hdr->type == TOKTYPE_NON_CCA &&
+ hdr->version == TOKVER_CLEAR_KEY)
+ keysize = pkey_keytype_aes_to_size(t->keytype);
+ if (!keysize || t->len != keysize)
+ return -EINVAL;
+
+ /* alloc tmp key buffer */
+ tmpbuf = kmalloc(MAXEP11AESKEYBLOBSIZE, GFP_ATOMIC);
+ if (!tmpbuf)
+ return -ENOMEM;
+
+ /* try two times in case of failure */
+ for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
+ tmplen = MAXEP11AESKEYBLOBSIZE;
+ rc = ep11_clr2key(NULL, 0, t->keytype, PKEY_TYPE_EP11,
+ 8 * keysize, 0, t->clearkey, t->len,
+ tmpbuf, &tmplen, NULL);
+ pr_debug("ep11_clr2key()=%d\n", rc);
+ if (rc)
+ continue;
+ rc = ep11_key2protkey(NULL, 0, tmpbuf, tmplen,
+ protkey, protkeylen, protkeytype);
+ pr_debug("ep11_key2protkey()=%d\n", rc);
+ }
+
+ kfree(tmpbuf);
+ pr_debug("rc=%d\n", rc);
+ return rc;
+}
+
static struct pkey_handler ep11_handler = {
- .module = THIS_MODULE,
- .name = "PKEY EP11 handler",
- .is_supported_key = is_ep11_key,
- .is_supported_keytype = is_ep11_keytype,
- .key_to_protkey = ep11_key2protkey,
- .gen_key = ep11_gen_key,
- .clr_to_key = ep11_clr2key,
- .verify_key = ep11_verifykey,
- .apqns_for_key = ep11_apqns4key,
- .apqns_for_keytype = ep11_apqns4type,
+ .module = THIS_MODULE,
+ .name = "PKEY EP11 handler",
+ .is_supported_key = is_ep11_key,
+ .is_supported_keytype = is_ep11_keytype,
+ .key_to_protkey = ep11_key2protkey,
+ .slowpath_key_to_protkey = ep11_slowpath_key2protkey,
+ .gen_key = ep11_gen_key,
+ .clr_to_key = ep11_clr2key,
+ .verify_key = ep11_verifykey,
+ .apqns_for_key = ep11_apqns4key,
+ .apqns_for_keytype = ep11_apqns4type,
};
/*