Blame view
crypto/asymmetric_keys/restrict.c
7.88 KB
b4d0d230c
|
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
cfb664ff2
|
2 3 |
/* Instantiate a public key crypto key from an X.509 Certificate * |
a511e1af8
|
4 |
* Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved. |
cfb664ff2
|
5 |
* Written by David Howells (dhowells@redhat.com) |
cfb664ff2
|
6 |
*/ |
a511e1af8
|
7 |
#define pr_fmt(fmt) "ASYM: "fmt |
cfb664ff2
|
8 9 |
#include <linux/module.h> #include <linux/kernel.h> |
cfb664ff2
|
10 |
#include <linux/err.h> |
cfb664ff2
|
11 12 |
#include <crypto/public_key.h> #include "asymmetric_keys.h" |
cfb664ff2
|
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
static bool use_builtin_keys; static struct asymmetric_key_id *ca_keyid; #ifndef MODULE static struct { struct asymmetric_key_id id; unsigned char data[10]; } cakey; static int __init ca_keys_setup(char *str) { if (!str) /* default system keyring */ return 1; if (strncmp(str, "id:", 3) == 0) { struct asymmetric_key_id *p = &cakey.id; size_t hexlen = (strlen(str) - 3) / 2; int ret; if (hexlen == 0 || hexlen > sizeof(cakey.data)) { pr_err("Missing or invalid ca_keys id "); return 1; } ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); if (ret < 0) pr_err("Unparsable ca_keys id hex string "); else ca_keyid = p; /* owner key 'id:xxxxxx' */ } else if (strcmp(str, "builtin") == 0) { use_builtin_keys = true; } return 1; } __setup("ca_keys=", ca_keys_setup); #endif |
a511e1af8
|
53 54 |
/** * restrict_link_by_signature - Restrict additions to a ring of public keys |
aaf66c883
|
55 |
* @dest_keyring: Keyring being linked to. |
a511e1af8
|
56 57 |
* @type: The type of key being added. * @payload: The payload of the new key. |
aaf66c883
|
58 |
* @trust_keyring: A ring of keys that can be used to vouch for the new cert. |
a511e1af8
|
59 |
* |
cfb664ff2
|
60 61 62 63 |
* Check the new certificate against the ones in the trust keyring. If one of * those is the signing key and validates the new certificate, then mark the * new certificate as being trusted. * |
a511e1af8
|
64 65 |
* Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a * matching parent certificate in the trusted list, -EKEYREJECTED if the |
4b34968e7
|
66 67 68 |
* signature check fails or the key is blacklisted, -ENOPKG if the signature * uses unsupported crypto, or some other error if there is a matching * certificate but the signature check cannot be performed. |
cfb664ff2
|
69 |
*/ |
aaf66c883
|
70 |
int restrict_link_by_signature(struct key *dest_keyring, |
a511e1af8
|
71 |
const struct key_type *type, |
aaf66c883
|
72 73 |
const union key_payload *payload, struct key *trust_keyring) |
cfb664ff2
|
74 |
{ |
a511e1af8
|
75 |
const struct public_key_signature *sig; |
cfb664ff2
|
76 |
struct key *key; |
a511e1af8
|
77 |
int ret; |
cfb664ff2
|
78 |
|
a511e1af8
|
79 80 |
pr_devel("==>%s() ", __func__); |
cfb664ff2
|
81 82 |
if (!trust_keyring) |
a511e1af8
|
83 84 85 |
return -ENOKEY; if (type != &key_type_asymmetric) |
cfb664ff2
|
86 |
return -EOPNOTSUPP; |
a511e1af8
|
87 88 |
sig = payload->data[asym_auth]; |
4b34968e7
|
89 90 |
if (!sig) return -ENOPKG; |
a511e1af8
|
91 |
if (!sig->auth_ids[0] && !sig->auth_ids[1]) |
acddc7201
|
92 |
return -ENOKEY; |
a511e1af8
|
93 |
|
cfb664ff2
|
94 95 |
if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) return -EPERM; |
cfb664ff2
|
96 |
|
a511e1af8
|
97 |
/* See if we have a key that signed this one. */ |
cfb664ff2
|
98 99 100 101 |
key = find_asymmetric_key(trust_keyring, sig->auth_ids[0], sig->auth_ids[1], false); if (IS_ERR(key)) |
a511e1af8
|
102 |
return -ENOKEY; |
cfb664ff2
|
103 |
|
a511e1af8
|
104 105 106 107 |
if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags)) ret = -ENOKEY; else ret = verify_signature(key, sig); |
cfb664ff2
|
108 109 110 |
key_put(key); return ret; } |
7e3c4d220
|
111 |
|
8e323a02e
|
112 113 114 115 116 117 118 119 120 121 122 |
static bool match_either_id(const struct asymmetric_key_ids *pair, const struct asymmetric_key_id *single) { return (asymmetric_key_id_same(pair->id[0], single) || asymmetric_key_id_same(pair->id[1], single)); } static int key_or_keyring_common(struct key *dest_keyring, const struct key_type *type, const union key_payload *payload, struct key *trusted, bool check_dest) |
7e3c4d220
|
123 124 |
{ const struct public_key_signature *sig; |
8e323a02e
|
125 |
struct key *key = NULL; |
7e3c4d220
|
126 127 128 129 130 131 132 133 134 |
int ret; pr_devel("==>%s() ", __func__); if (!dest_keyring) return -ENOKEY; else if (dest_keyring->type != &key_type_keyring) return -EOPNOTSUPP; |
8e323a02e
|
135 |
if (!trusted && !check_dest) |
7e3c4d220
|
136 137 138 139 140 141 |
return -ENOKEY; if (type != &key_type_asymmetric) return -EOPNOTSUPP; sig = payload->data[asym_auth]; |
4b34968e7
|
142 143 |
if (!sig) return -ENOPKG; |
7e3c4d220
|
144 145 |
if (!sig->auth_ids[0] && !sig->auth_ids[1]) return -ENOKEY; |
8e323a02e
|
146 147 148 149 150 151 152 153 154 |
if (trusted) { if (trusted->type == &key_type_keyring) { /* See if we have a key that signed this one. */ key = find_asymmetric_key(trusted, sig->auth_ids[0], sig->auth_ids[1], false); if (IS_ERR(key)) key = NULL; } else if (trusted->type == &key_type_asymmetric) { const struct asymmetric_key_ids *signer_ids; |
7e3c4d220
|
155 |
|
8e323a02e
|
156 |
signer_ids = asymmetric_key_ids(trusted); |
7e3c4d220
|
157 |
|
8e323a02e
|
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
/* * The auth_ids come from the candidate key (the * one that is being considered for addition to * dest_keyring) and identify the key that was * used to sign. * * The signer_ids are identifiers for the * signing key specified for dest_keyring. * * The first auth_id is the preferred id, and * the second is the fallback. If only one * auth_id is present, it may match against * either signer_id. If two auth_ids are * present, the first auth_id must match one * signer_id and the second auth_id must match * the second signer_id. */ if (!sig->auth_ids[0] || !sig->auth_ids[1]) { const struct asymmetric_key_id *auth_id; |
7e3c4d220
|
177 |
|
8e323a02e
|
178 179 180 181 182 183 184 185 186 187 188 189 190 |
auth_id = sig->auth_ids[0] ?: sig->auth_ids[1]; if (match_either_id(signer_ids, auth_id)) key = __key_get(trusted); } else if (asymmetric_key_id_same(signer_ids->id[1], sig->auth_ids[1]) && match_either_id(signer_ids, sig->auth_ids[0])) { key = __key_get(trusted); } } else { return -EOPNOTSUPP; } |
7e3c4d220
|
191 |
} |
8e323a02e
|
192 193 194 195 196 197 198 199 200 201 |
if (check_dest && !key) { /* See if the destination has a key that signed this one. */ key = find_asymmetric_key(dest_keyring, sig->auth_ids[0], sig->auth_ids[1], false); if (IS_ERR(key)) key = NULL; } if (!key) return -ENOKEY; |
7e3c4d220
|
202 203 204 205 206 207 208 |
ret = key_validate(key); if (ret == 0) ret = verify_signature(key, sig); key_put(key); return ret; } |
8e323a02e
|
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
/** * restrict_link_by_key_or_keyring - Restrict additions to a ring of public * keys using the restrict_key information stored in the ring. * @dest_keyring: Keyring being linked to. * @type: The type of key being added. * @payload: The payload of the new key. * @trusted: A key or ring of keys that can be used to vouch for the new cert. * * Check the new certificate only against the key or keys passed in the data * parameter. If one of those is the signing key and validates the new * certificate, then mark the new certificate as being ok to link. * * Returns 0 if the new certificate was accepted, -ENOKEY if we * couldn't find a matching parent certificate in the trusted list, |
4b34968e7
|
224 225 226 |
* -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses * unsupported crypto, or some other error if there is a matching certificate * but the signature check cannot be performed. |
8e323a02e
|
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
*/ int restrict_link_by_key_or_keyring(struct key *dest_keyring, const struct key_type *type, const union key_payload *payload, struct key *trusted) { return key_or_keyring_common(dest_keyring, type, payload, trusted, false); } /** * restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of * public keys using the restrict_key information stored in the ring. * @dest_keyring: Keyring being linked to. * @type: The type of key being added. * @payload: The payload of the new key. * @trusted: A key or ring of keys that can be used to vouch for the new cert. * |
40d32b59e
|
245 246 247 248 |
* Check the new certificate against the key or keys passed in the data * parameter and against the keys already linked to the destination keyring. If * one of those is the signing key and validates the new certificate, then mark * the new certificate as being ok to link. |
8e323a02e
|
249 250 251 |
* * Returns 0 if the new certificate was accepted, -ENOKEY if we * couldn't find a matching parent certificate in the trusted list, |
4b34968e7
|
252 253 254 |
* -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses * unsupported crypto, or some other error if there is a matching certificate * but the signature check cannot be performed. |
8e323a02e
|
255 256 257 258 259 260 261 262 263 |
*/ int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, const struct key_type *type, const union key_payload *payload, struct key *trusted) { return key_or_keyring_common(dest_keyring, type, payload, trusted, true); } |