1 /* Validate the trust chain of a PKCS#7 message. 2 * 3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #define pr_fmt(fmt) "PKCS7: "fmt 13 #include <linux/kernel.h> 14 #include <linux/export.h> 15 #include <linux/slab.h> 16 #include <linux/err.h> 17 #include <linux/asn1.h> 18 #include <linux/key.h> 19 #include <keys/asymmetric-type.h> 20 #include "public_key.h" 21 #include "pkcs7_parser.h" 22 23 /* 24 * Request an asymmetric key. 25 */ 26 static struct key *pkcs7_request_asymmetric_key( 27 struct key *keyring, 28 const char *signer, size_t signer_len, 29 const char *authority, size_t auth_len) 30 { 31 key_ref_t key; 32 char *id; 33 34 kenter(",%zu,,%zu", signer_len, auth_len); 35 36 /* Construct an identifier. */ 37 id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); 38 if (!id) 39 return ERR_PTR(-ENOMEM); 40 41 memcpy(id, signer, signer_len); 42 id[signer_len + 0] = ':'; 43 id[signer_len + 1] = ' '; 44 memcpy(id + signer_len + 2, authority, auth_len); 45 id[signer_len + 2 + auth_len] = 0; 46 47 pr_debug("Look up: \"%s\"\n", id); 48 49 key = keyring_search(make_key_ref(keyring, 1), 50 &key_type_asymmetric, id); 51 if (IS_ERR(key)) 52 pr_debug("Request for module key '%s' err %ld\n", 53 id, PTR_ERR(key)); 54 kfree(id); 55 56 if (IS_ERR(key)) { 57 switch (PTR_ERR(key)) { 58 /* Hide some search errors */ 59 case -EACCES: 60 case -ENOTDIR: 61 case -EAGAIN: 62 return ERR_PTR(-ENOKEY); 63 default: 64 return ERR_CAST(key); 65 } 66 } 67 68 pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); 69 return key_ref_to_ptr(key); 70 } 71 72 /** 73 * Check the trust on one PKCS#7 SignedInfo block. 74 */ 75 int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, 76 struct pkcs7_signed_info *sinfo, 77 struct key *trust_keyring) 78 { 79 struct public_key_signature *sig = &sinfo->sig; 80 struct x509_certificate *x509, *last = NULL, *p; 81 struct key *key; 82 bool trusted; 83 int ret; 84 85 kenter(",%u,", sinfo->index); 86 87 for (x509 = sinfo->signer; x509; x509 = x509->signer) { 88 if (x509->seen) { 89 if (x509->verified) { 90 trusted = x509->trusted; 91 goto verified; 92 } 93 kleave(" = -ENOKEY [cached]"); 94 return -ENOKEY; 95 } 96 x509->seen = true; 97 98 /* Look to see if this certificate is present in the trusted 99 * keys. 100 */ 101 key = pkcs7_request_asymmetric_key( 102 trust_keyring, 103 x509->subject, strlen(x509->subject), 104 x509->fingerprint, strlen(x509->fingerprint)); 105 if (!IS_ERR(key)) 106 /* One of the X.509 certificates in the PKCS#7 message 107 * is apparently the same as one we already trust. 108 * Verify that the trusted variant can also validate 109 * the signature on the descendant. 110 */ 111 goto matched; 112 if (key == ERR_PTR(-ENOMEM)) 113 return -ENOMEM; 114 115 /* Self-signed certificates form roots of their own, and if we 116 * don't know them, then we can't accept them. 117 */ 118 if (x509->next == x509) { 119 kleave(" = -ENOKEY [unknown self-signed]"); 120 return -ENOKEY; 121 } 122 123 might_sleep(); 124 last = x509; 125 sig = &last->sig; 126 } 127 128 /* No match - see if the root certificate has a signer amongst the 129 * trusted keys. 130 */ 131 if (!last || !last->issuer || !last->authority) { 132 kleave(" = -ENOKEY [no backref]"); 133 return -ENOKEY; 134 } 135 136 key = pkcs7_request_asymmetric_key( 137 trust_keyring, 138 last->issuer, strlen(last->issuer), 139 last->authority, strlen(last->authority)); 140 if (IS_ERR(key)) 141 return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; 142 x509 = last; 143 144 matched: 145 ret = verify_signature(key, sig); 146 trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); 147 key_put(key); 148 if (ret < 0) { 149 if (ret == -ENOMEM) 150 return ret; 151 kleave(" = -EKEYREJECTED [verify %d]", ret); 152 return -EKEYREJECTED; 153 } 154 155 verified: 156 x509->verified = true; 157 for (p = sinfo->signer; p != x509; p = p->signer) { 158 p->verified = true; 159 p->trusted = trusted; 160 } 161 sinfo->trusted = trusted; 162 kleave(" = 0"); 163 return 0; 164 } 165 166 /** 167 * pkcs7_validate_trust - Validate PKCS#7 trust chain 168 * @pkcs7: The PKCS#7 certificate to validate 169 * @trust_keyring: Signing certificates to use as starting points 170 * @_trusted: Set to true if trustworth, false otherwise 171 * 172 * Validate that the certificate chain inside the PKCS#7 message intersects 173 * keys we already know and trust. 174 * 175 * Returns, in order of descending priority: 176 * 177 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 178 * key, or: 179 * 180 * (*) 0 if at least one signature chain intersects with the keys in the trust 181 * keyring, or: 182 * 183 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 184 * chain. 185 * 186 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 187 * the message. 188 * 189 * May also return -ENOMEM. 190 */ 191 int pkcs7_validate_trust(struct pkcs7_message *pkcs7, 192 struct key *trust_keyring, 193 bool *_trusted) 194 { 195 struct pkcs7_signed_info *sinfo; 196 struct x509_certificate *p; 197 int cached_ret = 0, ret; 198 199 for (p = pkcs7->certs; p; p = p->next) 200 p->seen = false; 201 202 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 203 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); 204 if (ret < 0) { 205 if (ret == -ENOPKG) { 206 cached_ret = -ENOPKG; 207 } else if (ret == -ENOKEY) { 208 if (cached_ret == 0) 209 cached_ret = -ENOKEY; 210 } else { 211 return ret; 212 } 213 } 214 *_trusted |= sinfo->trusted; 215 } 216 217 return cached_ret; 218 } 219 EXPORT_SYMBOL_GPL(pkcs7_validate_trust); 220