xref: /linux/crypto/asymmetric_keys/pkcs7_trust.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
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