summaryrefslogtreecommitdiff
path: root/security/keys/trusted-keys/trusted_caam.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys/trusted-keys/trusted_caam.c')
-rw-r--r--security/keys/trusted-keys/trusted_caam.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/security/keys/trusted-keys/trusted_caam.c b/security/keys/trusted-keys/trusted_caam.c
index e3415c520c0a..601943ce0d60 100644
--- a/security/keys/trusted-keys/trusted_caam.c
+++ b/security/keys/trusted-keys/trusted_caam.c
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Pengutronix, Ahmad Fatoum <kernel@pengutronix.de>
+ * Copyright 2025 NXP
*/
#include <keys/trusted_caam.h>
#include <keys/trusted-type.h>
#include <linux/build_bug.h>
#include <linux/key-type.h>
+#include <linux/parser.h>
#include <soc/fsl/caam-blob.h>
static struct caam_blob_priv *blobifier;
@@ -16,6 +18,77 @@ static struct caam_blob_priv *blobifier;
static_assert(MAX_KEY_SIZE + CAAM_BLOB_OVERHEAD <= CAAM_BLOB_MAX_LEN);
static_assert(MAX_BLOB_SIZE <= CAAM_BLOB_MAX_LEN);
+enum {
+ opt_err,
+ opt_key_enc_algo,
+};
+
+static const match_table_t key_tokens = {
+ {opt_key_enc_algo, "key_enc_algo=%s"},
+ {opt_err, NULL}
+};
+
+#ifdef CAAM_DEBUG
+static inline void dump_options(const struct caam_pkey_info *pkey_info)
+{
+ pr_info("key encryption algo %d\n", pkey_info->key_enc_algo);
+}
+#else
+static inline void dump_options(const struct caam_pkey_info *pkey_info)
+{
+}
+#endif
+
+static int get_pkey_options(char *c,
+ struct caam_pkey_info *pkey_info)
+{
+ substring_t args[MAX_OPT_ARGS];
+ unsigned long token_mask = 0;
+ u16 key_enc_algo;
+ char *p = c;
+ int token;
+ int res;
+
+ if (!c)
+ return 0;
+
+ while ((p = strsep(&c, " \t"))) {
+ if (*p == '\0' || *p == ' ' || *p == '\t')
+ continue;
+ token = match_token(p, key_tokens, args);
+ if (test_and_set_bit(token, &token_mask))
+ return -EINVAL;
+
+ switch (token) {
+ case opt_key_enc_algo:
+ res = kstrtou16(args[0].from, 16, &key_enc_algo);
+ if (res < 0)
+ return -EINVAL;
+ pkey_info->key_enc_algo = key_enc_algo;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static bool is_key_pkey(char **datablob)
+{
+ char *c = NULL;
+
+ do {
+ /* Second argument onwards,
+ * determine if tied to HW
+ */
+ c = strsep(datablob, " \t");
+ if (c && (strcmp(c, "pk") == 0))
+ return true;
+ } while (c);
+
+ return false;
+}
+
static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob)
{
int ret;
@@ -25,11 +98,30 @@ static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob)
.key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1,
};
+ /*
+ * If it is to be treated as protected key,
+ * read next arguments too.
+ */
+ if (is_key_pkey(&datablob)) {
+ info.pkey_info.plain_key_sz = p->key_len;
+ info.pkey_info.is_pkey = 1;
+ ret = get_pkey_options(datablob, &info.pkey_info);
+ if (ret < 0)
+ return 0;
+ dump_options(&info.pkey_info);
+ }
+
ret = caam_encap_blob(blobifier, &info);
if (ret)
return ret;
p->blob_len = info.output_len;
+ if (info.pkey_info.is_pkey) {
+ p->key_len = p->blob_len + sizeof(struct caam_pkey_info);
+ memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info));
+ memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len);
+ }
+
return 0;
}
@@ -42,11 +134,27 @@ static int trusted_caam_unseal(struct trusted_key_payload *p, char *datablob)
.key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1,
};
+ if (is_key_pkey(&datablob)) {
+ info.pkey_info.plain_key_sz = p->blob_len - CAAM_BLOB_OVERHEAD;
+ info.pkey_info.is_pkey = 1;
+ ret = get_pkey_options(datablob, &info.pkey_info);
+ if (ret < 0)
+ return 0;
+ dump_options(&info.pkey_info);
+
+ p->key_len = p->blob_len + sizeof(struct caam_pkey_info);
+ memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info));
+ memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len);
+
+ return 0;
+ }
+
ret = caam_decap_blob(blobifier, &info);
if (ret)
return ret;
p->key_len = info.output_len;
+
return 0;
}