Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later 2 : : /* Validate the trust chain of a PKCS#7 message. 3 : : * 4 : : * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 5 : : * Written by David Howells (dhowells@redhat.com) 6 : : */ 7 : : 8 : : #define pr_fmt(fmt) "PKCS7: "fmt 9 : : #include <linux/kernel.h> 10 : : #include <linux/export.h> 11 : : #include <linux/slab.h> 12 : : #include <linux/err.h> 13 : : #include <linux/asn1.h> 14 : : #include <linux/key.h> 15 : : #include <keys/asymmetric-type.h> 16 : : #include <crypto/public_key.h> 17 : : #include "pkcs7_parser.h" 18 : : 19 : : /** 20 : : * Check the trust on one PKCS#7 SignedInfo block. 21 : : */ 22 : 3 : static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, 23 : : struct pkcs7_signed_info *sinfo, 24 : : struct key *trust_keyring) 25 : : { 26 : 3 : struct public_key_signature *sig = sinfo->sig; 27 : : struct x509_certificate *x509, *last = NULL, *p; 28 : : struct key *key; 29 : : int ret; 30 : : 31 : : kenter(",%u,", sinfo->index); 32 : : 33 : 3 : if (sinfo->unsupported_crypto) { 34 : : kleave(" = -ENOPKG [cached]"); 35 : : return -ENOPKG; 36 : : } 37 : : 38 : 3 : for (x509 = sinfo->signer; x509; x509 = x509->signer) { 39 : 3 : if (x509->seen) { 40 : 0 : if (x509->verified) 41 : : goto verified; 42 : : kleave(" = -ENOKEY [cached]"); 43 : : return -ENOKEY; 44 : : } 45 : 3 : x509->seen = true; 46 : : 47 : : /* Look to see if this certificate is present in the trusted 48 : : * keys. 49 : : */ 50 : 3 : key = find_asymmetric_key(trust_keyring, 51 : 3 : x509->id, x509->skid, false); 52 : 3 : if (!IS_ERR(key)) { 53 : : /* One of the X.509 certificates in the PKCS#7 message 54 : : * is apparently the same as one we already trust. 55 : : * Verify that the trusted variant can also validate 56 : : * the signature on the descendant. 57 : : */ 58 : : pr_devel("sinfo %u: Cert %u as key %x\n", 59 : : sinfo->index, x509->index, key_serial(key)); 60 : : goto matched; 61 : : } 62 : 0 : if (key == ERR_PTR(-ENOMEM)) 63 : : return -ENOMEM; 64 : : 65 : : /* Self-signed certificates form roots of their own, and if we 66 : : * don't know them, then we can't accept them. 67 : : */ 68 : 0 : if (x509->signer == x509) { 69 : : kleave(" = -ENOKEY [unknown self-signed]"); 70 : : return -ENOKEY; 71 : : } 72 : : 73 : 0 : might_sleep(); 74 : : last = x509; 75 : 0 : sig = last->sig; 76 : : } 77 : : 78 : : /* No match - see if the root certificate has a signer amongst the 79 : : * trusted keys. 80 : : */ 81 : 0 : if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) { 82 : 0 : key = find_asymmetric_key(trust_keyring, 83 : : last->sig->auth_ids[0], 84 : 0 : last->sig->auth_ids[1], 85 : : false); 86 : 0 : if (!IS_ERR(key)) { 87 : 0 : x509 = last; 88 : : pr_devel("sinfo %u: Root cert %u signer is key %x\n", 89 : : sinfo->index, x509->index, key_serial(key)); 90 : 0 : goto matched; 91 : : } 92 : 0 : if (PTR_ERR(key) != -ENOKEY) 93 : : return PTR_ERR(key); 94 : : } 95 : : 96 : : /* As a last resort, see if we have a trusted public key that matches 97 : : * the signed info directly. 98 : : */ 99 : 0 : key = find_asymmetric_key(trust_keyring, 100 : 0 : sinfo->sig->auth_ids[0], NULL, false); 101 : 0 : if (!IS_ERR(key)) { 102 : : pr_devel("sinfo %u: Direct signer is key %x\n", 103 : : sinfo->index, key_serial(key)); 104 : : x509 = NULL; 105 : 0 : sig = sinfo->sig; 106 : 0 : goto matched; 107 : : } 108 : 0 : if (PTR_ERR(key) != -ENOKEY) 109 : 0 : return PTR_ERR(key); 110 : : 111 : : kleave(" = -ENOKEY [no backref]"); 112 : : return -ENOKEY; 113 : : 114 : : matched: 115 : 3 : ret = verify_signature(key, sig); 116 : 3 : key_put(key); 117 : 3 : if (ret < 0) { 118 : 0 : if (ret == -ENOMEM) 119 : 0 : return ret; 120 : : kleave(" = -EKEYREJECTED [verify %d]", ret); 121 : : return -EKEYREJECTED; 122 : : } 123 : : 124 : : verified: 125 : 3 : if (x509) { 126 : 3 : x509->verified = true; 127 : 3 : for (p = sinfo->signer; p != x509; p = p->signer) 128 : 0 : p->verified = true; 129 : : } 130 : : kleave(" = 0"); 131 : : return 0; 132 : : } 133 : : 134 : : /** 135 : : * pkcs7_validate_trust - Validate PKCS#7 trust chain 136 : : * @pkcs7: The PKCS#7 certificate to validate 137 : : * @trust_keyring: Signing certificates to use as starting points 138 : : * 139 : : * Validate that the certificate chain inside the PKCS#7 message intersects 140 : : * keys we already know and trust. 141 : : * 142 : : * Returns, in order of descending priority: 143 : : * 144 : : * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 145 : : * key, or: 146 : : * 147 : : * (*) 0 if at least one signature chain intersects with the keys in the trust 148 : : * keyring, or: 149 : : * 150 : : * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 151 : : * chain. 152 : : * 153 : : * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 154 : : * the message. 155 : : * 156 : : * May also return -ENOMEM. 157 : : */ 158 : 3 : int pkcs7_validate_trust(struct pkcs7_message *pkcs7, 159 : : struct key *trust_keyring) 160 : : { 161 : : struct pkcs7_signed_info *sinfo; 162 : : struct x509_certificate *p; 163 : : int cached_ret = -ENOKEY; 164 : : int ret; 165 : : 166 : 3 : for (p = pkcs7->certs; p; p = p->next) 167 : 3 : p->seen = false; 168 : : 169 : 3 : for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 170 : 3 : ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); 171 : 3 : switch (ret) { 172 : : case -ENOKEY: 173 : 0 : continue; 174 : : case -ENOPKG: 175 : 0 : if (cached_ret == -ENOKEY) 176 : : cached_ret = -ENOPKG; 177 : 0 : continue; 178 : : case 0: 179 : : cached_ret = 0; 180 : 3 : continue; 181 : : default: 182 : 0 : return ret; 183 : : } 184 : : } 185 : : 186 : 3 : return cached_ret; 187 : : } 188 : : EXPORT_SYMBOL_GPL(pkcs7_validate_trust);