mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 15:47:16 -04:00
TPM_DEBUG, and other similar flags, are a non-standard way to specify a feature in Linux kernel. Introduce CONFIG_TRUSTED_KEYS_DEBUG for trusted keys, and use it to replace these ad-hoc feature flags. Given that trusted keys debug dumps can contain sensitive data, harden the feature as follows: 1. In the Kconfig description postulate that pr_debug() statements must be used. 2. Use pr_debug() statements in TPM 1.x driver to print the protocol dump. 3. Require trusted.debug=1 on the kernel command line (default: 0) to activate dumps at runtime, even when CONFIG_TRUSTED_KEYS_DEBUG=y. Traces, when actually needed, can be easily enabled by providing trusted.dyndbg='+p' and trusted.debug=1 in the kernel command-line. Reported-by: Nayna Jain <nayna@linux.ibm.com> Closes: https://lore.kernel.org/all/7f8b8478-5cd8-4d97-bfd0-341fd5cf10f9@linux.ibm.com/ Reviewed-by: Nayna Jain <nayna@linux.ibm.com> Tested-by: Srish Srinivasan <ssrish@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
192 lines
4.1 KiB
C
192 lines
4.1 KiB
C
// 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;
|
|
|
|
#define KEYMOD "SECURE_KEY"
|
|
|
|
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 CONFIG_TRUSTED_KEYS_DEBUG
|
|
static inline void dump_options(const struct caam_pkey_info *pkey_info)
|
|
{
|
|
if (!trusted_debug)
|
|
return;
|
|
|
|
pr_debug("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;
|
|
struct caam_blob_info info = {
|
|
.input = p->key, .input_len = p->key_len,
|
|
.output = p->blob, .output_len = MAX_BLOB_SIZE,
|
|
.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;
|
|
}
|
|
|
|
static int trusted_caam_unseal(struct trusted_key_payload *p, char *datablob)
|
|
{
|
|
int ret;
|
|
struct caam_blob_info info = {
|
|
.input = p->blob, .input_len = p->blob_len,
|
|
.output = p->key, .output_len = MAX_KEY_SIZE,
|
|
.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;
|
|
}
|
|
|
|
static int trusted_caam_init(void)
|
|
{
|
|
int ret;
|
|
|
|
blobifier = caam_blob_gen_init();
|
|
if (IS_ERR(blobifier))
|
|
return PTR_ERR(blobifier);
|
|
|
|
ret = register_key_type(&key_type_trusted);
|
|
if (ret)
|
|
caam_blob_gen_exit(blobifier);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void trusted_caam_exit(void)
|
|
{
|
|
unregister_key_type(&key_type_trusted);
|
|
caam_blob_gen_exit(blobifier);
|
|
}
|
|
|
|
struct trusted_key_ops trusted_key_caam_ops = {
|
|
.migratable = 0, /* non-migratable */
|
|
.init = trusted_caam_init,
|
|
.seal = trusted_caam_seal,
|
|
.unseal = trusted_caam_unseal,
|
|
.exit = trusted_caam_exit,
|
|
};
|