364 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Instantiate a public key crypto key from an X.509 Certificate3 *4 * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.5 * Written by David Howells (dhowells@redhat.com)6 */7 8#define pr_fmt(fmt) "ASYM: "fmt9#include <linux/module.h>10#include <linux/kernel.h>11#include <linux/err.h>12#include <crypto/public_key.h>13#include "asymmetric_keys.h"14 15static bool use_builtin_keys;16static struct asymmetric_key_id *ca_keyid;17 18#ifndef MODULE19static struct {20 struct asymmetric_key_id id;21 unsigned char data[10];22} cakey;23 24static int __init ca_keys_setup(char *str)25{26 if (!str) /* default system keyring */27 return 1;28 29 if (strncmp(str, "id:", 3) == 0) {30 struct asymmetric_key_id *p = &cakey.id;31 size_t hexlen = (strlen(str) - 3) / 2;32 int ret;33 34 if (hexlen == 0 || hexlen > sizeof(cakey.data)) {35 pr_err("Missing or invalid ca_keys id\n");36 return 1;37 }38 39 ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);40 if (ret < 0)41 pr_err("Unparsable ca_keys id hex string\n");42 else43 ca_keyid = p; /* owner key 'id:xxxxxx' */44 } else if (strcmp(str, "builtin") == 0) {45 use_builtin_keys = true;46 }47 48 return 1;49}50__setup("ca_keys=", ca_keys_setup);51#endif52 53/**54 * restrict_link_by_signature - Restrict additions to a ring of public keys55 * @dest_keyring: Keyring being linked to.56 * @type: The type of key being added.57 * @payload: The payload of the new key.58 * @trust_keyring: A ring of keys that can be used to vouch for the new cert.59 *60 * Check the new certificate against the ones in the trust keyring. If one of61 * those is the signing key and validates the new certificate, then mark the62 * new certificate as being trusted.63 *64 * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a65 * matching parent certificate in the trusted list, -EKEYREJECTED if the66 * signature check fails or the key is blacklisted, -ENOPKG if the signature67 * uses unsupported crypto, or some other error if there is a matching68 * certificate but the signature check cannot be performed.69 */70int restrict_link_by_signature(struct key *dest_keyring,71 const struct key_type *type,72 const union key_payload *payload,73 struct key *trust_keyring)74{75 const struct public_key_signature *sig;76 struct key *key;77 int ret;78 79 pr_devel("==>%s()\n", __func__);80 81 if (!trust_keyring)82 return -ENOKEY;83 84 if (type != &key_type_asymmetric)85 return -EOPNOTSUPP;86 87 sig = payload->data[asym_auth];88 if (!sig)89 return -ENOPKG;90 if (!sig->auth_ids[0] && !sig->auth_ids[1] && !sig->auth_ids[2])91 return -ENOKEY;92 93 if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))94 return -EPERM;95 96 /* See if we have a key that signed this one. */97 key = find_asymmetric_key(trust_keyring,98 sig->auth_ids[0], sig->auth_ids[1],99 sig->auth_ids[2], false);100 if (IS_ERR(key))101 return -ENOKEY;102 103 if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))104 ret = -ENOKEY;105 else if (IS_BUILTIN(CONFIG_SECONDARY_TRUSTED_KEYRING_SIGNED_BY_BUILTIN) &&106 !strcmp(dest_keyring->description, ".secondary_trusted_keys") &&107 !test_bit(KEY_FLAG_BUILTIN, &key->flags))108 ret = -ENOKEY;109 else110 ret = verify_signature(key, sig);111 key_put(key);112 return ret;113}114 115/**116 * restrict_link_by_ca - Restrict additions to a ring of CA keys117 * @dest_keyring: Keyring being linked to.118 * @type: The type of key being added.119 * @payload: The payload of the new key.120 * @trust_keyring: Unused.121 *122 * Check if the new certificate is a CA. If it is a CA, then mark the new123 * certificate as being ok to link.124 *125 * Returns 0 if the new certificate was accepted, -ENOKEY if the126 * certificate is not a CA. -ENOPKG if the signature uses unsupported127 * crypto, or some other error if there is a matching certificate but128 * the signature check cannot be performed.129 */130int restrict_link_by_ca(struct key *dest_keyring,131 const struct key_type *type,132 const union key_payload *payload,133 struct key *trust_keyring)134{135 const struct public_key *pkey;136 137 if (type != &key_type_asymmetric)138 return -EOPNOTSUPP;139 140 pkey = payload->data[asym_crypto];141 if (!pkey)142 return -ENOPKG;143 if (!test_bit(KEY_EFLAG_CA, &pkey->key_eflags))144 return -ENOKEY;145 if (!test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))146 return -ENOKEY;147 if (!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING_MAX))148 return 0;149 if (test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))150 return -ENOKEY;151 152 return 0;153}154 155/**156 * restrict_link_by_digsig - Restrict additions to a ring of digsig keys157 * @dest_keyring: Keyring being linked to.158 * @type: The type of key being added.159 * @payload: The payload of the new key.160 * @trust_keyring: A ring of keys that can be used to vouch for the new cert.161 *162 * Check if the new certificate has digitalSignature usage set. If it is,163 * then mark the new certificate as being ok to link. Afterwards verify164 * the new certificate against the ones in the trust_keyring.165 *166 * Returns 0 if the new certificate was accepted, -ENOKEY if the167 * certificate is not a digsig. -ENOPKG if the signature uses unsupported168 * crypto, or some other error if there is a matching certificate but169 * the signature check cannot be performed.170 */171int restrict_link_by_digsig(struct key *dest_keyring,172 const struct key_type *type,173 const union key_payload *payload,174 struct key *trust_keyring)175{176 const struct public_key *pkey;177 178 if (type != &key_type_asymmetric)179 return -EOPNOTSUPP;180 181 pkey = payload->data[asym_crypto];182 183 if (!pkey)184 return -ENOPKG;185 186 if (!test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))187 return -ENOKEY;188 189 if (test_bit(KEY_EFLAG_CA, &pkey->key_eflags))190 return -ENOKEY;191 192 if (test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))193 return -ENOKEY;194 195 return restrict_link_by_signature(dest_keyring, type, payload,196 trust_keyring);197}198 199static bool match_either_id(const struct asymmetric_key_id **pair,200 const struct asymmetric_key_id *single)201{202 return (asymmetric_key_id_same(pair[0], single) ||203 asymmetric_key_id_same(pair[1], single));204}205 206static int key_or_keyring_common(struct key *dest_keyring,207 const struct key_type *type,208 const union key_payload *payload,209 struct key *trusted, bool check_dest)210{211 const struct public_key_signature *sig;212 struct key *key = NULL;213 int ret;214 215 pr_devel("==>%s()\n", __func__);216 217 if (!dest_keyring)218 return -ENOKEY;219 else if (dest_keyring->type != &key_type_keyring)220 return -EOPNOTSUPP;221 222 if (!trusted && !check_dest)223 return -ENOKEY;224 225 if (type != &key_type_asymmetric)226 return -EOPNOTSUPP;227 228 sig = payload->data[asym_auth];229 if (!sig)230 return -ENOPKG;231 if (!sig->auth_ids[0] && !sig->auth_ids[1] && !sig->auth_ids[2])232 return -ENOKEY;233 234 if (trusted) {235 if (trusted->type == &key_type_keyring) {236 /* See if we have a key that signed this one. */237 key = find_asymmetric_key(trusted, sig->auth_ids[0],238 sig->auth_ids[1],239 sig->auth_ids[2], false);240 if (IS_ERR(key))241 key = NULL;242 } else if (trusted->type == &key_type_asymmetric) {243 const struct asymmetric_key_id **signer_ids;244 245 signer_ids = (const struct asymmetric_key_id **)246 asymmetric_key_ids(trusted)->id;247 248 /*249 * The auth_ids come from the candidate key (the250 * one that is being considered for addition to251 * dest_keyring) and identify the key that was252 * used to sign.253 *254 * The signer_ids are identifiers for the255 * signing key specified for dest_keyring.256 *257 * The first auth_id is the preferred id, 2nd and258 * 3rd are the fallbacks. If exactly one of259 * auth_ids[0] and auth_ids[1] is present, it may260 * match either signer_ids[0] or signed_ids[1].261 * If both are present the first one may match262 * either signed_id but the second one must match263 * the second signer_id. If neither of them is264 * available, auth_ids[2] is matched against265 * signer_ids[2] as a fallback.266 */267 if (!sig->auth_ids[0] && !sig->auth_ids[1]) {268 if (asymmetric_key_id_same(signer_ids[2],269 sig->auth_ids[2]))270 key = __key_get(trusted);271 272 } else if (!sig->auth_ids[0] || !sig->auth_ids[1]) {273 const struct asymmetric_key_id *auth_id;274 275 auth_id = sig->auth_ids[0] ?: sig->auth_ids[1];276 if (match_either_id(signer_ids, auth_id))277 key = __key_get(trusted);278 279 } else if (asymmetric_key_id_same(signer_ids[1],280 sig->auth_ids[1]) &&281 match_either_id(signer_ids,282 sig->auth_ids[0])) {283 key = __key_get(trusted);284 }285 } else {286 return -EOPNOTSUPP;287 }288 }289 290 if (check_dest && !key) {291 /* See if the destination has a key that signed this one. */292 key = find_asymmetric_key(dest_keyring, sig->auth_ids[0],293 sig->auth_ids[1], sig->auth_ids[2],294 false);295 if (IS_ERR(key))296 key = NULL;297 }298 299 if (!key)300 return -ENOKEY;301 302 ret = key_validate(key);303 if (ret == 0)304 ret = verify_signature(key, sig);305 306 key_put(key);307 return ret;308}309 310/**311 * restrict_link_by_key_or_keyring - Restrict additions to a ring of public312 * keys using the restrict_key information stored in the ring.313 * @dest_keyring: Keyring being linked to.314 * @type: The type of key being added.315 * @payload: The payload of the new key.316 * @trusted: A key or ring of keys that can be used to vouch for the new cert.317 *318 * Check the new certificate only against the key or keys passed in the data319 * parameter. If one of those is the signing key and validates the new320 * certificate, then mark the new certificate as being ok to link.321 *322 * Returns 0 if the new certificate was accepted, -ENOKEY if we323 * couldn't find a matching parent certificate in the trusted list,324 * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses325 * unsupported crypto, or some other error if there is a matching certificate326 * but the signature check cannot be performed.327 */328int restrict_link_by_key_or_keyring(struct key *dest_keyring,329 const struct key_type *type,330 const union key_payload *payload,331 struct key *trusted)332{333 return key_or_keyring_common(dest_keyring, type, payload, trusted,334 false);335}336 337/**338 * restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of339 * public keys using the restrict_key information stored in the ring.340 * @dest_keyring: Keyring being linked to.341 * @type: The type of key being added.342 * @payload: The payload of the new key.343 * @trusted: A key or ring of keys that can be used to vouch for the new cert.344 *345 * Check the new certificate against the key or keys passed in the data346 * parameter and against the keys already linked to the destination keyring. If347 * one of those is the signing key and validates the new certificate, then mark348 * the new certificate as being ok to link.349 *350 * Returns 0 if the new certificate was accepted, -ENOKEY if we351 * couldn't find a matching parent certificate in the trusted list,352 * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses353 * unsupported crypto, or some other error if there is a matching certificate354 * but the signature check cannot be performed.355 */356int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring,357 const struct key_type *type,358 const union key_payload *payload,359 struct key *trusted)360{361 return key_or_keyring_common(dest_keyring, type, payload, trusted,362 true);363}364