File Index
Files and directories
Sign in
FILE

turris-signing-key.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/cznic/turris-signing-key.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Some of CZ.NIC's Turris devices support signing messages with a per-device unique asymmetric
  4 * cryptographic key that was burned into the device at manufacture.
  5 *
  6 * This helper module exposes this message signing ability via the keyctl() syscall. Upon load, it
  7 * creates the `.turris-signing-keys` keyring. A device-specific driver then has to create a signing
  8 * key by calling devm_turris_signing_key_create().
  9 *
 10 * 2025 by Marek BehĂșn <kabel@kernel.org>
 11 */
 12
 13#include <linux/device.h>
 14#include <linux/err.h>
 15#include <linux/key-type.h>
 16#include <linux/key.h>
 17#include <linux/keyctl.h>
 18#include <linux/module.h>
 19#include <linux/seq_file.h>
 20#include <linux/string.h>
 21#include <linux/types.h>
 22
 23#include <linux/turris-signing-key.h>
 24
 25static int turris_signing_key_instantiate(struct key *key,
 26					  struct key_preparsed_payload *payload)
 27{
 28	return 0;
 29}
 30
 31static void turris_signing_key_describe(const struct key *key, struct seq_file *m)
 32{
 33	const struct turris_signing_key_subtype *subtype = dereference_key_rcu(key);
 34
 35	if (!subtype)
 36		return;
 37
 38	seq_printf(m, "%s: %*phN", key->description, subtype->public_key_size,
 39		   subtype->get_public_key(key));
 40}
 41
 42static long turris_signing_key_read(const struct key *key, char *buffer, size_t buflen)
 43{
 44	const struct turris_signing_key_subtype *subtype = dereference_key_rcu(key);
 45
 46	if (!subtype)
 47		return -EIO;
 48
 49	if (buffer) {
 50		if (buflen > subtype->public_key_size)
 51			buflen = subtype->public_key_size;
 52
 53		memcpy(buffer, subtype->get_public_key(key), subtype->public_key_size);
 54	}
 55
 56	return subtype->public_key_size;
 57}
 58
 59static bool turris_signing_key_asym_valid_params(const struct turris_signing_key_subtype *subtype,
 60						 const struct kernel_pkey_params *params)
 61{
 62	if (params->encoding && strcmp(params->encoding, "raw"))
 63		return false;
 64
 65	if (params->hash_algo && strcmp(params->hash_algo, subtype->hash_algo))
 66		return false;
 67
 68	return true;
 69}
 70
 71static int turris_signing_key_asym_query(const struct kernel_pkey_params *params,
 72					 struct kernel_pkey_query *info)
 73{
 74	const struct turris_signing_key_subtype *subtype = dereference_key_rcu(params->key);
 75
 76	if (!subtype)
 77		return -EIO;
 78
 79	if (!turris_signing_key_asym_valid_params(subtype, params))
 80		return -EINVAL;
 81
 82	info->supported_ops = KEYCTL_SUPPORTS_SIGN;
 83	info->key_size = subtype->key_size;
 84	info->max_data_size = subtype->data_size;
 85	info->max_sig_size = subtype->sig_size;
 86	info->max_enc_size = 0;
 87	info->max_dec_size = 0;
 88
 89	return 0;
 90}
 91
 92static int turris_signing_key_asym_eds_op(struct kernel_pkey_params *params,
 93				 const void *in, void *out)
 94{
 95	const struct turris_signing_key_subtype *subtype = dereference_key_rcu(params->key);
 96	int err;
 97
 98	if (!subtype)
 99		return -EIO;
100
101	if (!turris_signing_key_asym_valid_params(subtype, params))
102		return -EINVAL;
103
104	if (params->op != kernel_pkey_sign)
105		return -EOPNOTSUPP;
106
107	if (params->in_len != subtype->data_size || params->out_len != subtype->sig_size)
108		return -EINVAL;
109
110	err = subtype->sign(params->key, in, out);
111	if (err)
112		return err;
113
114	return subtype->sig_size;
115}
116
117static struct key_type turris_signing_key_type = {
118	.name		= "turris-signing-key",
119	.instantiate	= turris_signing_key_instantiate,
120	.describe	= turris_signing_key_describe,
121	.read		= turris_signing_key_read,
122	.asym_query	= turris_signing_key_asym_query,
123	.asym_eds_op	= turris_signing_key_asym_eds_op,
124};
125
126static struct key *turris_signing_keyring;
127
128static void turris_signing_key_release(void *key)
129{
130	key_unlink(turris_signing_keyring, key);
131	key_put(key);
132}
133
134int
135devm_turris_signing_key_create(struct device *dev, const struct turris_signing_key_subtype *subtype,
136			       const char *desc)
137{
138	struct key *key;
139	key_ref_t kref;
140
141	kref = key_create(make_key_ref(turris_signing_keyring, true),
142			  turris_signing_key_type.name, desc, NULL, 0,
143			  (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ |
144			  KEY_USR_SEARCH,
145			  KEY_ALLOC_BUILT_IN | KEY_ALLOC_SET_KEEP | KEY_ALLOC_NOT_IN_QUOTA);
146	if (IS_ERR(kref))
147		return PTR_ERR(kref);
148
149	key = key_ref_to_ptr(kref);
150	key->payload.data[1] = dev;
151	rcu_assign_keypointer(key, subtype);
152
153	return devm_add_action_or_reset(dev, turris_signing_key_release, key);
154}
155EXPORT_SYMBOL_GPL(devm_turris_signing_key_create);
156
157static int turris_signing_key_init(void)
158{
159	int err;
160
161	err = register_key_type(&turris_signing_key_type);
162	if (err)
163		return err;
164
165	turris_signing_keyring = keyring_alloc(".turris-signing-keys",
166					       GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
167					       (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW |
168					       KEY_USR_READ | KEY_USR_SEARCH,
169					       KEY_ALLOC_BUILT_IN | KEY_ALLOC_SET_KEEP |
170					       KEY_ALLOC_NOT_IN_QUOTA,
171					       NULL, NULL);
172	if (IS_ERR(turris_signing_keyring)) {
173		pr_err("Cannot allocate Turris keyring\n");
174
175		unregister_key_type(&turris_signing_key_type);
176
177		return PTR_ERR(turris_signing_keyring);
178	}
179
180	return 0;
181}
182module_init(turris_signing_key_init);
183
184static void turris_signing_key_exit(void)
185{
186	key_put(turris_signing_keyring);
187	unregister_key_type(&turris_signing_key_type);
188}
189module_exit(turris_signing_key_exit);
190
191MODULE_AUTHOR("Marek Behun <kabel@kernel.org>");
192MODULE_DESCRIPTION("CZ.NIC's Turris signing key helper");
193MODULE_LICENSE("GPL");
~/ Read-only file preview.