// SPDX-License-Identifier: GPL-2.0-or-later1/* Instantiate a public key crypto key from an X.509 Certificate2*3* Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.4* Written by David Howells ([email protected])5*/67#define pr_fmt(fmt) "ASYM: "fmt8#include <linux/module.h>9#include <linux/kernel.h>10#include <linux/err.h>11#include <crypto/public_key.h>12#include "asymmetric_keys.h"1314static bool use_builtin_keys;15static struct asymmetric_key_id *ca_keyid;1617#ifndef MODULE18static struct {19/* Must be last as it ends in a flexible-array member. */20TRAILING_OVERLAP(struct asymmetric_key_id, id, data,21unsigned char data[10];22);23} cakey;24static_assert(offsetof(typeof(cakey), id.data) == offsetof(typeof(cakey), data));2526static int __init ca_keys_setup(char *str)27{28if (!str) /* default system keyring */29return 1;3031if (strncmp(str, "id:", 3) == 0) {32struct asymmetric_key_id *p = &cakey.id;33size_t hexlen = (strlen(str) - 3) / 2;34int ret;3536if (hexlen == 0 || hexlen > sizeof(cakey.data)) {37pr_err("Missing or invalid ca_keys id\n");38return 1;39}4041ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);42if (ret < 0)43pr_err("Unparsable ca_keys id hex string\n");44else45ca_keyid = p; /* owner key 'id:xxxxxx' */46} else if (strcmp(str, "builtin") == 0) {47use_builtin_keys = true;48}4950return 1;51}52__setup("ca_keys=", ca_keys_setup);53#endif5455/**56* restrict_link_by_signature - Restrict additions to a ring of public keys57* @dest_keyring: Keyring being linked to.58* @type: The type of key being added.59* @payload: The payload of the new key.60* @trust_keyring: A ring of keys that can be used to vouch for the new cert.61*62* Check the new certificate against the ones in the trust keyring. If one of63* those is the signing key and validates the new certificate, then mark the64* new certificate as being trusted.65*66* Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a67* matching parent certificate in the trusted list, -EKEYREJECTED if the68* signature check fails or the key is blacklisted, -ENOPKG if the signature69* uses unsupported crypto, or some other error if there is a matching70* certificate but the signature check cannot be performed.71*/72int restrict_link_by_signature(struct key *dest_keyring,73const struct key_type *type,74const union key_payload *payload,75struct key *trust_keyring)76{77const struct public_key_signature *sig;78struct key *key;79int ret;8081pr_devel("==>%s()\n", __func__);8283if (!trust_keyring)84return -ENOKEY;8586if (type != &key_type_asymmetric)87return -EOPNOTSUPP;8889sig = payload->data[asym_auth];90if (!sig)91return -ENOPKG;92if (!sig->auth_ids[0] && !sig->auth_ids[1] && !sig->auth_ids[2])93return -ENOKEY;9495if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))96return -EPERM;9798/* See if we have a key that signed this one. */99key = find_asymmetric_key(trust_keyring,100sig->auth_ids[0], sig->auth_ids[1],101sig->auth_ids[2], false);102if (IS_ERR(key))103return -ENOKEY;104105if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))106ret = -ENOKEY;107else if (IS_BUILTIN(CONFIG_SECONDARY_TRUSTED_KEYRING_SIGNED_BY_BUILTIN) &&108!strcmp(dest_keyring->description, ".secondary_trusted_keys") &&109!test_bit(KEY_FLAG_BUILTIN, &key->flags))110ret = -ENOKEY;111else112ret = verify_signature(key, sig);113key_put(key);114return ret;115}116117/**118* restrict_link_by_ca - Restrict additions to a ring of CA keys119* @dest_keyring: Keyring being linked to.120* @type: The type of key being added.121* @payload: The payload of the new key.122* @trust_keyring: Unused.123*124* Check if the new certificate is a CA. If it is a CA, then mark the new125* certificate as being ok to link.126*127* Returns 0 if the new certificate was accepted, -ENOKEY if the128* certificate is not a CA. -ENOPKG if the signature uses unsupported129* crypto, or some other error if there is a matching certificate but130* the signature check cannot be performed.131*/132int restrict_link_by_ca(struct key *dest_keyring,133const struct key_type *type,134const union key_payload *payload,135struct key *trust_keyring)136{137const struct public_key *pkey;138139if (type != &key_type_asymmetric)140return -EOPNOTSUPP;141142pkey = payload->data[asym_crypto];143if (!pkey)144return -ENOPKG;145if (!test_bit(KEY_EFLAG_CA, &pkey->key_eflags))146return -ENOKEY;147if (!test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))148return -ENOKEY;149if (!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING_MAX))150return 0;151if (test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))152return -ENOKEY;153154return 0;155}156157/**158* restrict_link_by_digsig - Restrict additions to a ring of digsig keys159* @dest_keyring: Keyring being linked to.160* @type: The type of key being added.161* @payload: The payload of the new key.162* @trust_keyring: A ring of keys that can be used to vouch for the new cert.163*164* Check if the new certificate has digitalSignature usage set. If it is,165* then mark the new certificate as being ok to link. Afterwards verify166* the new certificate against the ones in the trust_keyring.167*168* Returns 0 if the new certificate was accepted, -ENOKEY if the169* certificate is not a digsig. -ENOPKG if the signature uses unsupported170* crypto, or some other error if there is a matching certificate but171* the signature check cannot be performed.172*/173int restrict_link_by_digsig(struct key *dest_keyring,174const struct key_type *type,175const union key_payload *payload,176struct key *trust_keyring)177{178const struct public_key *pkey;179180if (type != &key_type_asymmetric)181return -EOPNOTSUPP;182183pkey = payload->data[asym_crypto];184185if (!pkey)186return -ENOPKG;187188if (!test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))189return -ENOKEY;190191if (test_bit(KEY_EFLAG_CA, &pkey->key_eflags))192return -ENOKEY;193194if (test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))195return -ENOKEY;196197return restrict_link_by_signature(dest_keyring, type, payload,198trust_keyring);199}200201static bool match_either_id(const struct asymmetric_key_id **pair,202const struct asymmetric_key_id *single)203{204return (asymmetric_key_id_same(pair[0], single) ||205asymmetric_key_id_same(pair[1], single));206}207208static int key_or_keyring_common(struct key *dest_keyring,209const struct key_type *type,210const union key_payload *payload,211struct key *trusted, bool check_dest)212{213const struct public_key_signature *sig;214struct key *key = NULL;215int ret;216217pr_devel("==>%s()\n", __func__);218219if (!dest_keyring)220return -ENOKEY;221else if (dest_keyring->type != &key_type_keyring)222return -EOPNOTSUPP;223224if (!trusted && !check_dest)225return -ENOKEY;226227if (type != &key_type_asymmetric)228return -EOPNOTSUPP;229230sig = payload->data[asym_auth];231if (!sig)232return -ENOPKG;233if (!sig->auth_ids[0] && !sig->auth_ids[1] && !sig->auth_ids[2])234return -ENOKEY;235236if (trusted) {237if (trusted->type == &key_type_keyring) {238/* See if we have a key that signed this one. */239key = find_asymmetric_key(trusted, sig->auth_ids[0],240sig->auth_ids[1],241sig->auth_ids[2], false);242if (IS_ERR(key))243key = NULL;244} else if (trusted->type == &key_type_asymmetric) {245const struct asymmetric_key_id **signer_ids;246247signer_ids = (const struct asymmetric_key_id **)248asymmetric_key_ids(trusted)->id;249250/*251* The auth_ids come from the candidate key (the252* one that is being considered for addition to253* dest_keyring) and identify the key that was254* used to sign.255*256* The signer_ids are identifiers for the257* signing key specified for dest_keyring.258*259* The first auth_id is the preferred id, 2nd and260* 3rd are the fallbacks. If exactly one of261* auth_ids[0] and auth_ids[1] is present, it may262* match either signer_ids[0] or signed_ids[1].263* If both are present the first one may match264* either signed_id but the second one must match265* the second signer_id. If neither of them is266* available, auth_ids[2] is matched against267* signer_ids[2] as a fallback.268*/269if (!sig->auth_ids[0] && !sig->auth_ids[1]) {270if (asymmetric_key_id_same(signer_ids[2],271sig->auth_ids[2]))272key = __key_get(trusted);273274} else if (!sig->auth_ids[0] || !sig->auth_ids[1]) {275const struct asymmetric_key_id *auth_id;276277auth_id = sig->auth_ids[0] ?: sig->auth_ids[1];278if (match_either_id(signer_ids, auth_id))279key = __key_get(trusted);280281} else if (asymmetric_key_id_same(signer_ids[1],282sig->auth_ids[1]) &&283match_either_id(signer_ids,284sig->auth_ids[0])) {285key = __key_get(trusted);286}287} else {288return -EOPNOTSUPP;289}290}291292if (check_dest && !key) {293/* See if the destination has a key that signed this one. */294key = find_asymmetric_key(dest_keyring, sig->auth_ids[0],295sig->auth_ids[1], sig->auth_ids[2],296false);297if (IS_ERR(key))298key = NULL;299}300301if (!key)302return -ENOKEY;303304ret = key_validate(key);305if (ret == 0)306ret = verify_signature(key, sig);307308key_put(key);309return ret;310}311312/**313* restrict_link_by_key_or_keyring - Restrict additions to a ring of public314* keys using the restrict_key information stored in the ring.315* @dest_keyring: Keyring being linked to.316* @type: The type of key being added.317* @payload: The payload of the new key.318* @trusted: A key or ring of keys that can be used to vouch for the new cert.319*320* Check the new certificate only against the key or keys passed in the data321* parameter. If one of those is the signing key and validates the new322* certificate, then mark the new certificate as being ok to link.323*324* Returns 0 if the new certificate was accepted, -ENOKEY if we325* couldn't find a matching parent certificate in the trusted list,326* -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses327* unsupported crypto, or some other error if there is a matching certificate328* but the signature check cannot be performed.329*/330int restrict_link_by_key_or_keyring(struct key *dest_keyring,331const struct key_type *type,332const union key_payload *payload,333struct key *trusted)334{335return key_or_keyring_common(dest_keyring, type, payload, trusted,336false);337}338339/**340* restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of341* public keys using the restrict_key information stored in the ring.342* @dest_keyring: Keyring being linked to.343* @type: The type of key being added.344* @payload: The payload of the new key.345* @trusted: A key or ring of keys that can be used to vouch for the new cert.346*347* Check the new certificate against the key or keys passed in the data348* parameter and against the keys already linked to the destination keyring. If349* one of those is the signing key and validates the new certificate, then mark350* the new certificate as being ok to link.351*352* Returns 0 if the new certificate was accepted, -ENOKEY if we353* couldn't find a matching parent certificate in the trusted list,354* -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses355* unsupported crypto, or some other error if there is a matching certificate356* but the signature check cannot be performed.357*/358int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring,359const struct key_type *type,360const union key_payload *payload,361struct key *trusted)362{363return key_or_keyring_common(dest_keyring, type, payload, trusted,364true);365}366367368