Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.18 193 lines 5.3 kB view raw
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");