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