18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Instantiate a public key crypto key from an X.509 Certificate 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "ASYM: "fmt 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <crypto/public_key.h> 138c2ecf20Sopenharmony_ci#include "asymmetric_keys.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic bool use_builtin_keys; 168c2ecf20Sopenharmony_cistatic struct asymmetric_key_id *ca_keyid; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifndef MODULE 198c2ecf20Sopenharmony_cistatic struct { 208c2ecf20Sopenharmony_ci struct asymmetric_key_id id; 218c2ecf20Sopenharmony_ci unsigned char data[10]; 228c2ecf20Sopenharmony_ci} cakey; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int __init ca_keys_setup(char *str) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci if (!str) /* default system keyring */ 278c2ecf20Sopenharmony_ci return 1; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (strncmp(str, "id:", 3) == 0) { 308c2ecf20Sopenharmony_ci struct asymmetric_key_id *p = &cakey.id; 318c2ecf20Sopenharmony_ci size_t hexlen = (strlen(str) - 3) / 2; 328c2ecf20Sopenharmony_ci int ret; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (hexlen == 0 || hexlen > sizeof(cakey.data)) { 358c2ecf20Sopenharmony_ci pr_err("Missing or invalid ca_keys id\n"); 368c2ecf20Sopenharmony_ci return 1; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); 408c2ecf20Sopenharmony_ci if (ret < 0) 418c2ecf20Sopenharmony_ci pr_err("Unparsable ca_keys id hex string\n"); 428c2ecf20Sopenharmony_ci else 438c2ecf20Sopenharmony_ci ca_keyid = p; /* owner key 'id:xxxxxx' */ 448c2ecf20Sopenharmony_ci } else if (strcmp(str, "builtin") == 0) { 458c2ecf20Sopenharmony_ci use_builtin_keys = true; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci return 1; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci__setup("ca_keys=", ca_keys_setup); 518c2ecf20Sopenharmony_ci#endif 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * restrict_link_by_signature - Restrict additions to a ring of public keys 558c2ecf20Sopenharmony_ci * @dest_keyring: Keyring being linked to. 568c2ecf20Sopenharmony_ci * @type: The type of key being added. 578c2ecf20Sopenharmony_ci * @payload: The payload of the new key. 588c2ecf20Sopenharmony_ci * @trust_keyring: A ring of keys that can be used to vouch for the new cert. 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * Check the new certificate against the ones in the trust keyring. If one of 618c2ecf20Sopenharmony_ci * those is the signing key and validates the new certificate, then mark the 628c2ecf20Sopenharmony_ci * new certificate as being trusted. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a 658c2ecf20Sopenharmony_ci * matching parent certificate in the trusted list, -EKEYREJECTED if the 668c2ecf20Sopenharmony_ci * signature check fails or the key is blacklisted, -ENOPKG if the signature 678c2ecf20Sopenharmony_ci * uses unsupported crypto, or some other error if there is a matching 688c2ecf20Sopenharmony_ci * certificate but the signature check cannot be performed. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ciint restrict_link_by_signature(struct key *dest_keyring, 718c2ecf20Sopenharmony_ci const struct key_type *type, 728c2ecf20Sopenharmony_ci const union key_payload *payload, 738c2ecf20Sopenharmony_ci struct key *trust_keyring) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci const struct public_key_signature *sig; 768c2ecf20Sopenharmony_ci struct key *key; 778c2ecf20Sopenharmony_ci int ret; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci pr_devel("==>%s()\n", __func__); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!trust_keyring) 828c2ecf20Sopenharmony_ci return -ENOKEY; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (type != &key_type_asymmetric) 858c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci sig = payload->data[asym_auth]; 888c2ecf20Sopenharmony_ci if (!sig) 898c2ecf20Sopenharmony_ci return -ENOPKG; 908c2ecf20Sopenharmony_ci if (!sig->auth_ids[0] && !sig->auth_ids[1]) 918c2ecf20Sopenharmony_ci return -ENOKEY; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) 948c2ecf20Sopenharmony_ci return -EPERM; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* See if we have a key that signed this one. */ 978c2ecf20Sopenharmony_ci key = find_asymmetric_key(trust_keyring, 988c2ecf20Sopenharmony_ci sig->auth_ids[0], sig->auth_ids[1], 998c2ecf20Sopenharmony_ci false); 1008c2ecf20Sopenharmony_ci if (IS_ERR(key)) 1018c2ecf20Sopenharmony_ci return -ENOKEY; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags)) 1048c2ecf20Sopenharmony_ci ret = -ENOKEY; 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci ret = verify_signature(key, sig); 1078c2ecf20Sopenharmony_ci key_put(key); 1088c2ecf20Sopenharmony_ci return ret; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic bool match_either_id(const struct asymmetric_key_ids *pair, 1128c2ecf20Sopenharmony_ci const struct asymmetric_key_id *single) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci return (asymmetric_key_id_same(pair->id[0], single) || 1158c2ecf20Sopenharmony_ci asymmetric_key_id_same(pair->id[1], single)); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int key_or_keyring_common(struct key *dest_keyring, 1198c2ecf20Sopenharmony_ci const struct key_type *type, 1208c2ecf20Sopenharmony_ci const union key_payload *payload, 1218c2ecf20Sopenharmony_ci struct key *trusted, bool check_dest) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci const struct public_key_signature *sig; 1248c2ecf20Sopenharmony_ci struct key *key = NULL; 1258c2ecf20Sopenharmony_ci int ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci pr_devel("==>%s()\n", __func__); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (!dest_keyring) 1308c2ecf20Sopenharmony_ci return -ENOKEY; 1318c2ecf20Sopenharmony_ci else if (dest_keyring->type != &key_type_keyring) 1328c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!trusted && !check_dest) 1358c2ecf20Sopenharmony_ci return -ENOKEY; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (type != &key_type_asymmetric) 1388c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci sig = payload->data[asym_auth]; 1418c2ecf20Sopenharmony_ci if (!sig) 1428c2ecf20Sopenharmony_ci return -ENOPKG; 1438c2ecf20Sopenharmony_ci if (!sig->auth_ids[0] && !sig->auth_ids[1]) 1448c2ecf20Sopenharmony_ci return -ENOKEY; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (trusted) { 1478c2ecf20Sopenharmony_ci if (trusted->type == &key_type_keyring) { 1488c2ecf20Sopenharmony_ci /* See if we have a key that signed this one. */ 1498c2ecf20Sopenharmony_ci key = find_asymmetric_key(trusted, sig->auth_ids[0], 1508c2ecf20Sopenharmony_ci sig->auth_ids[1], false); 1518c2ecf20Sopenharmony_ci if (IS_ERR(key)) 1528c2ecf20Sopenharmony_ci key = NULL; 1538c2ecf20Sopenharmony_ci } else if (trusted->type == &key_type_asymmetric) { 1548c2ecf20Sopenharmony_ci const struct asymmetric_key_ids *signer_ids; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci signer_ids = asymmetric_key_ids(trusted); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * The auth_ids come from the candidate key (the 1608c2ecf20Sopenharmony_ci * one that is being considered for addition to 1618c2ecf20Sopenharmony_ci * dest_keyring) and identify the key that was 1628c2ecf20Sopenharmony_ci * used to sign. 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * The signer_ids are identifiers for the 1658c2ecf20Sopenharmony_ci * signing key specified for dest_keyring. 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * The first auth_id is the preferred id, and 1688c2ecf20Sopenharmony_ci * the second is the fallback. If only one 1698c2ecf20Sopenharmony_ci * auth_id is present, it may match against 1708c2ecf20Sopenharmony_ci * either signer_id. If two auth_ids are 1718c2ecf20Sopenharmony_ci * present, the first auth_id must match one 1728c2ecf20Sopenharmony_ci * signer_id and the second auth_id must match 1738c2ecf20Sopenharmony_ci * the second signer_id. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci if (!sig->auth_ids[0] || !sig->auth_ids[1]) { 1768c2ecf20Sopenharmony_ci const struct asymmetric_key_id *auth_id; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci auth_id = sig->auth_ids[0] ?: sig->auth_ids[1]; 1798c2ecf20Sopenharmony_ci if (match_either_id(signer_ids, auth_id)) 1808c2ecf20Sopenharmony_ci key = __key_get(trusted); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci } else if (asymmetric_key_id_same(signer_ids->id[1], 1838c2ecf20Sopenharmony_ci sig->auth_ids[1]) && 1848c2ecf20Sopenharmony_ci match_either_id(signer_ids, 1858c2ecf20Sopenharmony_ci sig->auth_ids[0])) { 1868c2ecf20Sopenharmony_ci key = __key_get(trusted); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (check_dest && !key) { 1948c2ecf20Sopenharmony_ci /* See if the destination has a key that signed this one. */ 1958c2ecf20Sopenharmony_ci key = find_asymmetric_key(dest_keyring, sig->auth_ids[0], 1968c2ecf20Sopenharmony_ci sig->auth_ids[1], false); 1978c2ecf20Sopenharmony_ci if (IS_ERR(key)) 1988c2ecf20Sopenharmony_ci key = NULL; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!key) 2028c2ecf20Sopenharmony_ci return -ENOKEY; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ret = key_validate(key); 2058c2ecf20Sopenharmony_ci if (ret == 0) 2068c2ecf20Sopenharmony_ci ret = verify_signature(key, sig); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci key_put(key); 2098c2ecf20Sopenharmony_ci return ret; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/** 2138c2ecf20Sopenharmony_ci * restrict_link_by_key_or_keyring - Restrict additions to a ring of public 2148c2ecf20Sopenharmony_ci * keys using the restrict_key information stored in the ring. 2158c2ecf20Sopenharmony_ci * @dest_keyring: Keyring being linked to. 2168c2ecf20Sopenharmony_ci * @type: The type of key being added. 2178c2ecf20Sopenharmony_ci * @payload: The payload of the new key. 2188c2ecf20Sopenharmony_ci * @trusted: A key or ring of keys that can be used to vouch for the new cert. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * Check the new certificate only against the key or keys passed in the data 2218c2ecf20Sopenharmony_ci * parameter. If one of those is the signing key and validates the new 2228c2ecf20Sopenharmony_ci * certificate, then mark the new certificate as being ok to link. 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * Returns 0 if the new certificate was accepted, -ENOKEY if we 2258c2ecf20Sopenharmony_ci * couldn't find a matching parent certificate in the trusted list, 2268c2ecf20Sopenharmony_ci * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses 2278c2ecf20Sopenharmony_ci * unsupported crypto, or some other error if there is a matching certificate 2288c2ecf20Sopenharmony_ci * but the signature check cannot be performed. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ciint restrict_link_by_key_or_keyring(struct key *dest_keyring, 2318c2ecf20Sopenharmony_ci const struct key_type *type, 2328c2ecf20Sopenharmony_ci const union key_payload *payload, 2338c2ecf20Sopenharmony_ci struct key *trusted) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return key_or_keyring_common(dest_keyring, type, payload, trusted, 2368c2ecf20Sopenharmony_ci false); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of 2418c2ecf20Sopenharmony_ci * public keys using the restrict_key information stored in the ring. 2428c2ecf20Sopenharmony_ci * @dest_keyring: Keyring being linked to. 2438c2ecf20Sopenharmony_ci * @type: The type of key being added. 2448c2ecf20Sopenharmony_ci * @payload: The payload of the new key. 2458c2ecf20Sopenharmony_ci * @trusted: A key or ring of keys that can be used to vouch for the new cert. 2468c2ecf20Sopenharmony_ci * 2478c2ecf20Sopenharmony_ci * Check the new certificate only against the key or keys passed in the data 2488c2ecf20Sopenharmony_ci * parameter. If one of those is the signing key and validates the new 2498c2ecf20Sopenharmony_ci * certificate, then mark the new certificate as being ok to link. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * Returns 0 if the new certificate was accepted, -ENOKEY if we 2528c2ecf20Sopenharmony_ci * couldn't find a matching parent certificate in the trusted list, 2538c2ecf20Sopenharmony_ci * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses 2548c2ecf20Sopenharmony_ci * unsupported crypto, or some other error if there is a matching certificate 2558c2ecf20Sopenharmony_ci * but the signature check cannot be performed. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ciint restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, 2588c2ecf20Sopenharmony_ci const struct key_type *type, 2598c2ecf20Sopenharmony_ci const union key_payload *payload, 2608c2ecf20Sopenharmony_ci struct key *trusted) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci return key_or_keyring_common(dest_keyring, type, payload, trusted, 2638c2ecf20Sopenharmony_ci true); 2648c2ecf20Sopenharmony_ci} 265