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 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 for (x509 = sinfo->signer; x509; x509 = x509->signer) { 39 if (x509->seen) { 40 if (x509->verified) { 41 trusted = x509->trusted; 42 goto verified; 43 } 44 kleave(" = -ENOKEY [cached]"); 45 return -ENOKEY; 46 } 47 x509->seen = true; 48 49 /* Look to see if this certificate is present in the trusted 50 * keys. 51 */ 52 key = x509_request_asymmetric_key(trust_keyring, x509->subject, 53 x509->fingerprint); 54 if (!IS_ERR(key)) 55 /* One of the X.509 certificates in the PKCS#7 message 56 * is apparently the same as one we already trust. 57 * Verify that the trusted variant can also validate 58 * the signature on the descendant. 59 */ 60 goto matched; 61 if (key == ERR_PTR(-ENOMEM)) 62 return -ENOMEM; 63 64 /* Self-signed certificates form roots of their own, and if we 65 * don't know them, then we can't accept them. 66 */ 67 if (x509->next == x509) { 68 kleave(" = -ENOKEY [unknown self-signed]"); 69 return -ENOKEY; 70 } 71 72 might_sleep(); 73 last = x509; 74 sig = &last->sig; 75 } 76 77 /* No match - see if the root certificate has a signer amongst the 78 * trusted keys. 79 */ 80 if (!last || !last->issuer || !last->authority) { 81 kleave(" = -ENOKEY [no backref]"); 82 return -ENOKEY; 83 } 84 85 key = x509_request_asymmetric_key(trust_keyring, last->issuer, 86 last->authority); 87 if (IS_ERR(key)) 88 return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; 89 x509 = last; 90 91 matched: 92 ret = verify_signature(key, sig); 93 trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); 94 key_put(key); 95 if (ret < 0) { 96 if (ret == -ENOMEM) 97 return ret; 98 kleave(" = -EKEYREJECTED [verify %d]", ret); 99 return -EKEYREJECTED; 100 } 101 102 verified: 103 x509->verified = true; 104 for (p = sinfo->signer; p != x509; p = p->signer) { 105 p->verified = true; 106 p->trusted = trusted; 107 } 108 sinfo->trusted = trusted; 109 kleave(" = 0"); 110 return 0; 111 } 112 113 /** 114 * pkcs7_validate_trust - Validate PKCS#7 trust chain 115 * @pkcs7: The PKCS#7 certificate to validate 116 * @trust_keyring: Signing certificates to use as starting points 117 * @_trusted: Set to true if trustworth, false otherwise 118 * 119 * Validate that the certificate chain inside the PKCS#7 message intersects 120 * keys we already know and trust. 121 * 122 * Returns, in order of descending priority: 123 * 124 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 125 * key, or: 126 * 127 * (*) 0 if at least one signature chain intersects with the keys in the trust 128 * keyring, or: 129 * 130 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 131 * chain. 132 * 133 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 134 * the message. 135 * 136 * May also return -ENOMEM. 137 */ 138 int pkcs7_validate_trust(struct pkcs7_message *pkcs7, 139 struct key *trust_keyring, 140 bool *_trusted) 141 { 142 struct pkcs7_signed_info *sinfo; 143 struct x509_certificate *p; 144 int cached_ret = 0, ret; 145 146 for (p = pkcs7->certs; p; p = p->next) 147 p->seen = false; 148 149 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 150 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); 151 if (ret < 0) { 152 if (ret == -ENOPKG) { 153 cached_ret = -ENOPKG; 154 } else if (ret == -ENOKEY) { 155 if (cached_ret == 0) 156 cached_ret = -ENOKEY; 157 } else { 158 return ret; 159 } 160 } 161 *_trusted |= sinfo->trusted; 162 } 163 164 return cached_ret; 165 } 166 EXPORT_SYMBOL_GPL(pkcs7_validate_trust); 167