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 * Check the trust on one PKCS#7 SignedInfo block. 25 */ 26 static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, 27 struct pkcs7_signed_info *sinfo, 28 struct key *trust_keyring) 29 { 30 struct public_key_signature *sig = &sinfo->sig; 31 struct x509_certificate *x509, *last = NULL, *p; 32 struct key *key; 33 bool trusted; 34 int ret; 35 36 kenter(",%u,", sinfo->index); 37 38 if (sinfo->unsupported_crypto) { 39 kleave(" = -ENOPKG [cached]"); 40 return -ENOPKG; 41 } 42 43 for (x509 = sinfo->signer; x509; x509 = x509->signer) { 44 if (x509->seen) { 45 if (x509->verified) { 46 trusted = x509->trusted; 47 goto verified; 48 } 49 kleave(" = -ENOKEY [cached]"); 50 return -ENOKEY; 51 } 52 x509->seen = true; 53 54 /* Look to see if this certificate is present in the trusted 55 * keys. 56 */ 57 key = x509_request_asymmetric_key(trust_keyring, 58 x509->id, x509->skid, 59 false); 60 if (!IS_ERR(key)) { 61 /* One of the X.509 certificates in the PKCS#7 message 62 * is apparently the same as one we already trust. 63 * Verify that the trusted variant can also validate 64 * the signature on the descendant. 65 */ 66 pr_devel("sinfo %u: Cert %u as key %x\n", 67 sinfo->index, x509->index, key_serial(key)); 68 goto matched; 69 } 70 if (key == ERR_PTR(-ENOMEM)) 71 return -ENOMEM; 72 73 /* Self-signed certificates form roots of their own, and if we 74 * don't know them, then we can't accept them. 75 */ 76 if (x509->next == x509) { 77 kleave(" = -ENOKEY [unknown self-signed]"); 78 return -ENOKEY; 79 } 80 81 might_sleep(); 82 last = x509; 83 sig = &last->sig; 84 } 85 86 /* No match - see if the root certificate has a signer amongst the 87 * trusted keys. 88 */ 89 if (last && (last->akid_id || last->akid_skid)) { 90 key = x509_request_asymmetric_key(trust_keyring, 91 last->akid_id, 92 last->akid_skid, 93 false); 94 if (!IS_ERR(key)) { 95 x509 = last; 96 pr_devel("sinfo %u: Root cert %u signer is key %x\n", 97 sinfo->index, x509->index, key_serial(key)); 98 goto matched; 99 } 100 if (PTR_ERR(key) != -ENOKEY) 101 return PTR_ERR(key); 102 } 103 104 /* As a last resort, see if we have a trusted public key that matches 105 * the signed info directly. 106 */ 107 key = x509_request_asymmetric_key(trust_keyring, 108 sinfo->signing_cert_id, 109 NULL, 110 false); 111 if (!IS_ERR(key)) { 112 pr_devel("sinfo %u: Direct signer is key %x\n", 113 sinfo->index, key_serial(key)); 114 x509 = NULL; 115 goto matched; 116 } 117 if (PTR_ERR(key) != -ENOKEY) 118 return PTR_ERR(key); 119 120 kleave(" = -ENOKEY [no backref]"); 121 return -ENOKEY; 122 123 matched: 124 ret = verify_signature(key, sig); 125 trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); 126 key_put(key); 127 if (ret < 0) { 128 if (ret == -ENOMEM) 129 return ret; 130 kleave(" = -EKEYREJECTED [verify %d]", ret); 131 return -EKEYREJECTED; 132 } 133 134 verified: 135 if (x509) { 136 x509->verified = true; 137 for (p = sinfo->signer; p != x509; p = p->signer) { 138 p->verified = true; 139 p->trusted = trusted; 140 } 141 } 142 sinfo->trusted = trusted; 143 kleave(" = 0"); 144 return 0; 145 } 146 147 /** 148 * pkcs7_validate_trust - Validate PKCS#7 trust chain 149 * @pkcs7: The PKCS#7 certificate to validate 150 * @trust_keyring: Signing certificates to use as starting points 151 * @_trusted: Set to true if trustworth, false otherwise 152 * 153 * Validate that the certificate chain inside the PKCS#7 message intersects 154 * keys we already know and trust. 155 * 156 * Returns, in order of descending priority: 157 * 158 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 159 * key, or: 160 * 161 * (*) 0 if at least one signature chain intersects with the keys in the trust 162 * keyring, or: 163 * 164 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 165 * chain. 166 * 167 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 168 * the message. 169 * 170 * May also return -ENOMEM. 171 */ 172 int pkcs7_validate_trust(struct pkcs7_message *pkcs7, 173 struct key *trust_keyring, 174 bool *_trusted) 175 { 176 struct pkcs7_signed_info *sinfo; 177 struct x509_certificate *p; 178 int cached_ret = -ENOKEY; 179 int ret; 180 181 for (p = pkcs7->certs; p; p = p->next) 182 p->seen = false; 183 184 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 185 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); 186 switch (ret) { 187 case -ENOKEY: 188 continue; 189 case -ENOPKG: 190 if (cached_ret == -ENOKEY) 191 cached_ret = -ENOPKG; 192 continue; 193 case 0: 194 *_trusted |= sinfo->trusted; 195 cached_ret = 0; 196 continue; 197 default: 198 return ret; 199 } 200 } 201 202 return cached_ret; 203 } 204 EXPORT_SYMBOL_GPL(pkcs7_validate_trust); 205