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