brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · afcd4d1 Raw
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