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->next == 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 goto matched; 110 } 111 if (PTR_ERR(key) != -ENOKEY) 112 return PTR_ERR(key); 113 114 kleave(" = -ENOKEY [no backref]"); 115 return -ENOKEY; 116 117 matched: 118 ret = verify_signature(key, sig); 119 key_put(key); 120 if (ret < 0) { 121 if (ret == -ENOMEM) 122 return ret; 123 kleave(" = -EKEYREJECTED [verify %d]", ret); 124 return -EKEYREJECTED; 125 } 126 127 verified: 128 if (x509) { 129 x509->verified = true; 130 for (p = sinfo->signer; p != x509; p = p->signer) 131 p->verified = true; 132 } 133 kleave(" = 0"); 134 return 0; 135 } 136 137 /** 138 * pkcs7_validate_trust - Validate PKCS#7 trust chain 139 * @pkcs7: The PKCS#7 certificate to validate 140 * @trust_keyring: Signing certificates to use as starting points 141 * 142 * Validate that the certificate chain inside the PKCS#7 message intersects 143 * keys we already know and trust. 144 * 145 * Returns, in order of descending priority: 146 * 147 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 148 * key, or: 149 * 150 * (*) 0 if at least one signature chain intersects with the keys in the trust 151 * keyring, or: 152 * 153 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 154 * chain. 155 * 156 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 157 * the message. 158 * 159 * May also return -ENOMEM. 160 */ 161 int pkcs7_validate_trust(struct pkcs7_message *pkcs7, 162 struct key *trust_keyring) 163 { 164 struct pkcs7_signed_info *sinfo; 165 struct x509_certificate *p; 166 int cached_ret = -ENOKEY; 167 int ret; 168 169 for (p = pkcs7->certs; p; p = p->next) 170 p->seen = false; 171 172 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 173 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); 174 switch (ret) { 175 case -ENOKEY: 176 continue; 177 case -ENOPKG: 178 if (cached_ret == -ENOKEY) 179 cached_ret = -ENOPKG; 180 continue; 181 case 0: 182 cached_ret = 0; 183 continue; 184 default: 185 return ret; 186 } 187 } 188 189 return cached_ret; 190 } 191 EXPORT_SYMBOL_GPL(pkcs7_validate_trust); 192